crea-ruby 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +55 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +234 -0
- data/Rakefile +332 -0
- data/crea-ruby.gemspec +39 -0
- data/gource.sh +6 -0
- data/lib/crea.rb +85 -0
- data/lib/crea/api.rb +208 -0
- data/lib/crea/base_error.rb +218 -0
- data/lib/crea/block_api.rb +78 -0
- data/lib/crea/broadcast.rb +1334 -0
- data/lib/crea/chain_config.rb +36 -0
- data/lib/crea/formatter.rb +14 -0
- data/lib/crea/jsonrpc.rb +108 -0
- data/lib/crea/marshal.rb +231 -0
- data/lib/crea/mixins/jsonable.rb +37 -0
- data/lib/crea/mixins/retriable.rb +58 -0
- data/lib/crea/mixins/serializable.rb +45 -0
- data/lib/crea/operation.rb +141 -0
- data/lib/crea/operation/account_create.rb +10 -0
- data/lib/crea/operation/account_create_with_delegation.rb +12 -0
- data/lib/crea/operation/account_update.rb +8 -0
- data/lib/crea/operation/account_witness_proxy.rb +4 -0
- data/lib/crea/operation/account_witness_vote.rb +5 -0
- data/lib/crea/operation/cancel_transfer_from_savings.rb +4 -0
- data/lib/crea/operation/challenge_authority.rb +5 -0
- data/lib/crea/operation/change_recovery_account.rb +5 -0
- data/lib/crea/operation/claim_account.rb +5 -0
- data/lib/crea/operation/claim_reward_balance.rb +6 -0
- data/lib/crea/operation/comment.rb +9 -0
- data/lib/crea/operation/comment_options.rb +10 -0
- data/lib/crea/operation/convert.rb +5 -0
- data/lib/crea/operation/create_claimed_account.rb +10 -0
- data/lib/crea/operation/custom.rb +5 -0
- data/lib/crea/operation/custom_binary.rb +8 -0
- data/lib/crea/operation/custom_json.rb +6 -0
- data/lib/crea/operation/decline_voting_rights.rb +4 -0
- data/lib/crea/operation/delegate_vesting_shares.rb +5 -0
- data/lib/crea/operation/delete_comment.rb +4 -0
- data/lib/crea/operation/escrow_approve.rb +8 -0
- data/lib/crea/operation/escrow_dispute.rb +7 -0
- data/lib/crea/operation/escrow_release.rb +10 -0
- data/lib/crea/operation/escrow_transfer.rb +12 -0
- data/lib/crea/operation/feed_publish.rb +4 -0
- data/lib/crea/operation/limit_order_cancel.rb +4 -0
- data/lib/crea/operation/limit_order_create.rb +8 -0
- data/lib/crea/operation/limit_order_create2.rb +8 -0
- data/lib/crea/operation/prove_authority.rb +4 -0
- data/lib/crea/operation/recover_account.rb +6 -0
- data/lib/crea/operation/report_over_production.rb +5 -0
- data/lib/crea/operation/request_account_recovery.rb +6 -0
- data/lib/crea/operation/reset_account.rb +5 -0
- data/lib/crea/operation/set_reset_account.rb +5 -0
- data/lib/crea/operation/set_withdraw_vesting_route.rb +6 -0
- data/lib/crea/operation/transfer.rb +6 -0
- data/lib/crea/operation/transfer_from_savings.rb +7 -0
- data/lib/crea/operation/transfer_to_savings.rb +6 -0
- data/lib/crea/operation/transfer_to_vesting.rb +5 -0
- data/lib/crea/operation/vote.rb +6 -0
- data/lib/crea/operation/withdraw_vesting.rb +4 -0
- data/lib/crea/operation/witness_set_properties.rb +5 -0
- data/lib/crea/operation/witness_update.rb +7 -0
- data/lib/crea/rpc/base_client.rb +179 -0
- data/lib/crea/rpc/http_client.rb +143 -0
- data/lib/crea/rpc/thread_safe_http_client.rb +35 -0
- data/lib/crea/stream.rb +385 -0
- data/lib/crea/transaction.rb +96 -0
- data/lib/crea/transaction_builder.rb +393 -0
- data/lib/crea/type/amount.rb +107 -0
- data/lib/crea/type/base_type.rb +10 -0
- data/lib/crea/utils.rb +17 -0
- data/lib/crea/version.rb +4 -0
- metadata +478 -0
@@ -0,0 +1,393 @@
|
|
1
|
+
module Crea
|
2
|
+
# {TransactionBuilder} can be used to create a transaction that the
|
3
|
+
# {NetworkBroadcastApi} can broadcast to the rest of the platform. The main
|
4
|
+
# feature of this class is the ability to cryptographically sign the
|
5
|
+
# transaction so that it conforms to the consensus rules that are required by
|
6
|
+
# the blockchain.
|
7
|
+
#
|
8
|
+
# wif = '5JrvPrQeBBvCRdjv29iDvkwn3EQYZ9jqfAHzrCyUvfbEbRkrYFC'
|
9
|
+
# builder = Crea::TransactionBuilder.new(wif: wif)
|
10
|
+
# builder.put(vote: {
|
11
|
+
# voter: 'alice',
|
12
|
+
# author: 'bob',
|
13
|
+
# permlink: 'my-burgers',
|
14
|
+
# weight: 10000
|
15
|
+
# })
|
16
|
+
#
|
17
|
+
# trx = builder.transaction
|
18
|
+
# network_broadcast_api = Crea::CondenserApi.new
|
19
|
+
# network_broadcast_api.broadcast_transaction_synchronous(trx: trx)
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# The `wif` value may also be an array, when signing with multiple signatures
|
23
|
+
# (multisig).
|
24
|
+
class TransactionBuilder
|
25
|
+
include Retriable
|
26
|
+
include ChainConfig
|
27
|
+
include Utils
|
28
|
+
|
29
|
+
attr_accessor :app_base, :database_api, :block_api, :expiration, :operations
|
30
|
+
attr_writer :wif
|
31
|
+
attr_reader :signed, :testnet, :force_serialize
|
32
|
+
|
33
|
+
alias app_base? app_base
|
34
|
+
alias testnet? testnet
|
35
|
+
alias force_serialize? force_serialize
|
36
|
+
|
37
|
+
def initialize(options = {})
|
38
|
+
@app_base = !!options[:app_base] # default false
|
39
|
+
@database_api = options[:database_api]
|
40
|
+
@block_api = options[:block_api]
|
41
|
+
|
42
|
+
if app_base?
|
43
|
+
@database_api ||= Crea::DatabaseApi.new(options)
|
44
|
+
@block_api ||= Crea::BlockApi.new(options)
|
45
|
+
else
|
46
|
+
@database_api ||= Crea::CondenserApi.new(options)
|
47
|
+
@block_api ||= Crea::CondenserApi.new(options)
|
48
|
+
end
|
49
|
+
|
50
|
+
@wif = [options[:wif]].flatten
|
51
|
+
@signed = false
|
52
|
+
@testnet = !!options[:testnet]
|
53
|
+
@force_serialize = !!options[:force_serialize]
|
54
|
+
|
55
|
+
if !!(trx = options[:trx])
|
56
|
+
trx = case trx
|
57
|
+
when String then JSON[trx]
|
58
|
+
else; trx
|
59
|
+
end
|
60
|
+
|
61
|
+
@trx = Transaction.new(trx)
|
62
|
+
end
|
63
|
+
|
64
|
+
@trx ||= Transaction.new
|
65
|
+
@chain = options[:chain] || :crea
|
66
|
+
@error_pipe = options[:error_pipe] || STDERR
|
67
|
+
@chain_id = options[:chain_id]
|
68
|
+
@chain_id ||= case @chain
|
69
|
+
when :crea then NETWORKS_CREA_CHAIN_ID
|
70
|
+
when :test then NETWORKS_TEST_CHAIN_ID
|
71
|
+
else; raise UnsupportedChainError, "Unsupported chain: #{@chain}"
|
72
|
+
end
|
73
|
+
|
74
|
+
if testnet? && @chain_id == NETWORKS_CREA_CHAIN_ID
|
75
|
+
raise UnsupportedChainError, "Unsupported testnet chain id: #{@chain_id}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def inspect
|
80
|
+
properties = %w(trx).map do |prop|
|
81
|
+
if !!(v = instance_variable_get("@#{prop}"))
|
82
|
+
"@#{prop}=#{v.inspect}"
|
83
|
+
end
|
84
|
+
end.compact.join(', ')
|
85
|
+
|
86
|
+
"#<#{self.class.name} [#{properties}]>"
|
87
|
+
end
|
88
|
+
|
89
|
+
def reset
|
90
|
+
@trx = Transaction.new
|
91
|
+
@signed = false
|
92
|
+
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
# If the transaction can be prepared, this method will do so and set the
|
97
|
+
# expiration. Once the expiration is set, it will not re-prepare. If you
|
98
|
+
# call {#put}, the expiration is set {::Nil} so that it can be re-prepared.
|
99
|
+
#
|
100
|
+
# Usually, this method is called automatically by {#put} and/or {#transaction}.
|
101
|
+
#
|
102
|
+
# @return {TransactionBuilder}
|
103
|
+
def prepare
|
104
|
+
if @trx.expired?
|
105
|
+
catch :prepare_header do; begin
|
106
|
+
@database_api.get_dynamic_global_properties do |properties|
|
107
|
+
block_number = properties.last_irreversible_block_num
|
108
|
+
block_header_args = if app_base?
|
109
|
+
{block_num: block_number}
|
110
|
+
else
|
111
|
+
block_number
|
112
|
+
end
|
113
|
+
|
114
|
+
@block_api.get_block_header(block_header_args) do |result|
|
115
|
+
header = if app_base?
|
116
|
+
result.header
|
117
|
+
else
|
118
|
+
result
|
119
|
+
end
|
120
|
+
|
121
|
+
@trx.ref_block_num = (block_number - 1) & 0xFFFF
|
122
|
+
@trx.ref_block_prefix = unhexlify(header.previous[8..-1]).unpack('V*')[0]
|
123
|
+
@trx.expiration ||= (Time.parse(properties.time + 'Z') + EXPIRE_IN_SECS).utc
|
124
|
+
end
|
125
|
+
end
|
126
|
+
rescue => e
|
127
|
+
if can_retry? e
|
128
|
+
@error_pipe.puts "#{e} ... retrying."
|
129
|
+
throw :prepare_header
|
130
|
+
else
|
131
|
+
raise e
|
132
|
+
end
|
133
|
+
end; end
|
134
|
+
end
|
135
|
+
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
139
|
+
# Sets operations all at once, then prepares.
|
140
|
+
def operations=(operations)
|
141
|
+
@trx.operations = operations.map{ |op| normalize_operation(op) }
|
142
|
+
prepare
|
143
|
+
@trx.operations
|
144
|
+
end
|
145
|
+
|
146
|
+
# A quick and flexible way to append a new operation to the transaction.
|
147
|
+
# This method uses ducktyping to figure out how to form the operation.
|
148
|
+
#
|
149
|
+
# There are three main ways you can call this method. These assume that
|
150
|
+
# `op_type` is a {::Symbol} (or {::String}) representing the type of operation and `op` is the
|
151
|
+
# operation {::Hash}.
|
152
|
+
#
|
153
|
+
# put(op_type, op)
|
154
|
+
#
|
155
|
+
# ... or ...
|
156
|
+
#
|
157
|
+
# put(op_type => op)
|
158
|
+
#
|
159
|
+
# ... or ...
|
160
|
+
#
|
161
|
+
# put([op_type, op])
|
162
|
+
#
|
163
|
+
# You can also chain multiple operations:
|
164
|
+
#
|
165
|
+
# builder = Crea::TransactionBuilder.new
|
166
|
+
# builder.put(vote: vote1).put(vote: vote2)
|
167
|
+
# @return {TransactionBuilder}
|
168
|
+
def put(type, op = nil)
|
169
|
+
@trx.expiration = nil
|
170
|
+
@trx.operations << normalize_operation(type, op)
|
171
|
+
prepare
|
172
|
+
self
|
173
|
+
end
|
174
|
+
|
175
|
+
# If all of the required values are set, this returns a fully formed
|
176
|
+
# transaction that is ready to broadcast.
|
177
|
+
#
|
178
|
+
# @return
|
179
|
+
# {
|
180
|
+
# :ref_block_num => 18912,
|
181
|
+
# :ref_block_prefix => 575781536,
|
182
|
+
# :expiration => "2018-04-26T15:26:12",
|
183
|
+
# :extensions => [],
|
184
|
+
# :operations => [[:vote, {
|
185
|
+
# :voter => "alice",
|
186
|
+
# :author => "bob",
|
187
|
+
# :permlink => "my-burgers",
|
188
|
+
# :weight => 10000
|
189
|
+
# }
|
190
|
+
# ]],
|
191
|
+
# :signatures => ["1c45b65740b4b2c17c4bcf6bcc3f8d90ddab827d50532729fc3b8f163f2c465a532b0112ae4bf388ccc97b7c2e0bc570caadda78af48cf3c261037e65eefcd941e"]
|
192
|
+
# }
|
193
|
+
def transaction(options = {prepare: true, sign: true})
|
194
|
+
options[:prepare] = true unless options.has_key? :prepare
|
195
|
+
options[:sign] = true unless options.has_key? :sign
|
196
|
+
|
197
|
+
prepare if !!options[:prepare]
|
198
|
+
|
199
|
+
if !!options[:sign]
|
200
|
+
sign
|
201
|
+
else
|
202
|
+
@trx
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Appends to the `signatures` array of the transaction, built from a
|
207
|
+
# serialized digest.
|
208
|
+
#
|
209
|
+
# @return {Hash | TransactionBuilder} The fully signed transaction if a `wif` is provided or the instance of the {TransactionBuilder} if a `wif` has not yet been provided.
|
210
|
+
def sign
|
211
|
+
return self if @wif.empty?
|
212
|
+
return self if @trx.expired?
|
213
|
+
|
214
|
+
unless @signed
|
215
|
+
catch :serialize do; begin
|
216
|
+
transaction_hex.tap do |result|
|
217
|
+
hex = if app_base?
|
218
|
+
result.hex
|
219
|
+
else
|
220
|
+
result
|
221
|
+
end
|
222
|
+
|
223
|
+
unless force_serialize?
|
224
|
+
derrived_trx = Transaction.new(hex: hex)
|
225
|
+
derrived_ops = derrived_trx.operations
|
226
|
+
derrived_trx.operations = derrived_ops.map do |op|
|
227
|
+
op_name = if app_base?
|
228
|
+
op[:type].to_sym
|
229
|
+
else
|
230
|
+
op[:type].to_s.sub(/_operation$/, '').to_sym
|
231
|
+
end
|
232
|
+
|
233
|
+
normalize_operation op_name, JSON[op[:value].to_json]
|
234
|
+
end
|
235
|
+
|
236
|
+
raise SerializationMismatchError unless @trx == derrived_trx
|
237
|
+
end
|
238
|
+
|
239
|
+
hex = hex[0..-4] # drop empty signature array
|
240
|
+
@trx.id = Digest::SHA256.hexdigest(unhexlify(hex))[0..39]
|
241
|
+
|
242
|
+
hex = @chain_id + hex
|
243
|
+
digest = unhexlify(hex)
|
244
|
+
digest_hex = Digest::SHA256.digest(digest)
|
245
|
+
private_keys = @wif.map{ |wif| Bitcoin::Key.from_base58 wif }
|
246
|
+
ec = Bitcoin::OpenSSL_EC
|
247
|
+
count = 0
|
248
|
+
|
249
|
+
private_keys.each do |private_key|
|
250
|
+
sig = nil
|
251
|
+
|
252
|
+
loop do
|
253
|
+
count += 1
|
254
|
+
@error_pipe.puts "#{count} attempts to find canonical signature" if count % 40 == 0
|
255
|
+
public_key_hex = private_key.pub
|
256
|
+
sig = ec.sign_compact(digest_hex, private_key.priv, public_key_hex, false)
|
257
|
+
|
258
|
+
next if public_key_hex != ec.recover_compact(digest_hex, sig)
|
259
|
+
break if canonical? sig
|
260
|
+
end
|
261
|
+
|
262
|
+
@trx.signatures << hexlify(sig)
|
263
|
+
end
|
264
|
+
|
265
|
+
@signed = true
|
266
|
+
end
|
267
|
+
rescue => e
|
268
|
+
if can_retry? e
|
269
|
+
@error_pipe.puts "#{e} ... retrying."
|
270
|
+
throw :serialize
|
271
|
+
else
|
272
|
+
raise e
|
273
|
+
end
|
274
|
+
end; end
|
275
|
+
end
|
276
|
+
|
277
|
+
@trx
|
278
|
+
end
|
279
|
+
|
280
|
+
def transaction_hex
|
281
|
+
trx = transaction(prepare: true, sign: false)
|
282
|
+
|
283
|
+
transaction_hex_args = if app_base?
|
284
|
+
{trx: trx}
|
285
|
+
else
|
286
|
+
trx
|
287
|
+
end
|
288
|
+
|
289
|
+
@database_api.get_transaction_hex(transaction_hex_args) do |result|
|
290
|
+
if app_base?
|
291
|
+
result[:hex]
|
292
|
+
else
|
293
|
+
result
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# @return [Array] All public keys that could possibly sign for a given transaction.
|
299
|
+
def potential_signatures
|
300
|
+
potential_signatures_args = if app_base?
|
301
|
+
{trx: transaction}
|
302
|
+
else
|
303
|
+
transaction
|
304
|
+
end
|
305
|
+
|
306
|
+
@database_api.get_potential_signatures(potential_signatures_args) do |result|
|
307
|
+
if app_base?
|
308
|
+
result[:keys]
|
309
|
+
else
|
310
|
+
result
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# This API will take a partially signed transaction and a set of public keys
|
316
|
+
# that the owner has the ability to sign for and return the minimal subset
|
317
|
+
# of public keys that should add signatures to the transaction.
|
318
|
+
#
|
319
|
+
# @return [Array] The minimal subset of public keys that should add signatures to the transaction.
|
320
|
+
def required_signatures
|
321
|
+
required_signatures_args = if app_base?
|
322
|
+
{trx: transaction}
|
323
|
+
else
|
324
|
+
[transaction, []]
|
325
|
+
end
|
326
|
+
|
327
|
+
@database_api.get_required_signatures(*required_signatures_args) do |result|
|
328
|
+
if app_base?
|
329
|
+
result[:keys]
|
330
|
+
else
|
331
|
+
result
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
# @return [Boolean] True if the transaction has all of the required signatures.
|
337
|
+
def valid?
|
338
|
+
verify_authority_args = if app_base?
|
339
|
+
{trx: transaction}
|
340
|
+
else
|
341
|
+
transaction
|
342
|
+
end
|
343
|
+
|
344
|
+
@database_api.verify_authority(verify_authority_args) do |result|
|
345
|
+
if app_base?
|
346
|
+
result.valid
|
347
|
+
else
|
348
|
+
result
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
private
|
353
|
+
# See: https://github.com/creary/crea/pull/2500
|
354
|
+
# @private
|
355
|
+
def canonical?(sig)
|
356
|
+
sig = sig.unpack('C*')
|
357
|
+
|
358
|
+
!(
|
359
|
+
((sig[0] & 0x80 ) != 0) || ( sig[0] == 0 ) ||
|
360
|
+
((sig[1] & 0x80 ) != 0) ||
|
361
|
+
((sig[32] & 0x80 ) != 0) || ( sig[32] == 0 ) ||
|
362
|
+
((sig[33] & 0x80 ) != 0)
|
363
|
+
)
|
364
|
+
end
|
365
|
+
|
366
|
+
def normalize_operation(type, op = nil)
|
367
|
+
if app_base?
|
368
|
+
case type
|
369
|
+
when Symbol, String
|
370
|
+
type_value = "#{type}_operation"
|
371
|
+
{type: type_value, value: op}
|
372
|
+
when Hash
|
373
|
+
type_value = "#{type.keys.first}_operation"
|
374
|
+
{type: type_value, value: type.values.first}
|
375
|
+
when Array
|
376
|
+
type_value = "#{type[0]}_operation"
|
377
|
+
{type: type_value, value: type[1]}
|
378
|
+
else
|
379
|
+
raise Crea::ArgumentError, "Don't know what to do with operation type #{type.class}: #{type} (#{op})"
|
380
|
+
end
|
381
|
+
else
|
382
|
+
case type
|
383
|
+
when Symbol then [type, op]
|
384
|
+
when String then [type.to_sym, op]
|
385
|
+
when Hash then [type.keys.first.to_sym, type.values.first]
|
386
|
+
when Array then type
|
387
|
+
else
|
388
|
+
raise Crea::ArgumentError, "Don't know what to do with operation type #{type.class}: #{type} (#{op})"
|
389
|
+
end
|
390
|
+
end
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Crea
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/piston-lib/blob/34a7525cee119ec9b24a99577ede2d54466fca0e/creabase/operations.py
|
5
|
+
class Amount < BaseType
|
6
|
+
attr_reader :amount, :precision, :nai, :asset
|
7
|
+
|
8
|
+
def self.to_h(amount)
|
9
|
+
new(amount).to_h
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.to_s(amount)
|
13
|
+
new(amount).to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.to_bytes(amount)
|
17
|
+
new(amount).to_bytes
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(value)
|
21
|
+
super(:amount, value)
|
22
|
+
|
23
|
+
case value
|
24
|
+
when Array
|
25
|
+
@amount, @precision, @nai = value
|
26
|
+
@asset = case @nai
|
27
|
+
when '@@000000013' then 'CBD'
|
28
|
+
when '@@000000021' then 'CREA'
|
29
|
+
when '@@000000037' then 'VESTS'
|
30
|
+
else; raise TypeError, "Asset #{@nai} unknown."
|
31
|
+
end
|
32
|
+
|
33
|
+
@amount = "%.#{@precision}f" % (@amount.to_f / 10 ** @precision)
|
34
|
+
when Hash
|
35
|
+
@amount, @precision, @nai = value.map do |k, v|
|
36
|
+
v if %i(amount precision nai).include? k.to_sym
|
37
|
+
end.compact
|
38
|
+
|
39
|
+
@asset = case @nai
|
40
|
+
when '@@000000013' then 'CBD'
|
41
|
+
when '@@000000021' then 'CREA'
|
42
|
+
when '@@000000037' then 'VESTS'
|
43
|
+
else; raise TypeError, "Asset #{@nai} unknown."
|
44
|
+
end
|
45
|
+
|
46
|
+
@amount = "%.#{@precision}f" % (@amount.to_f / 10 ** @precision)
|
47
|
+
when Amount
|
48
|
+
@precision = value.precision
|
49
|
+
@nai = value.nai
|
50
|
+
@asset = value.asset
|
51
|
+
@amount = value.amount
|
52
|
+
else
|
53
|
+
@amount, @asset = value.strip.split(' ') rescue ['', '']
|
54
|
+
@precision = case @asset
|
55
|
+
when 'CREA' then 3
|
56
|
+
when 'VESTS' then 6
|
57
|
+
when 'CBD' then 3
|
58
|
+
when 'TESTS' then 3
|
59
|
+
when 'TBD' then 3
|
60
|
+
else; raise TypeError, "Asset #{@asset} unknown."
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_bytes
|
66
|
+
asset = @asset.ljust(7, "\x00")
|
67
|
+
amount = (@amount.to_f * 10 ** @precision).round
|
68
|
+
|
69
|
+
[amount].pack('q') +
|
70
|
+
[@precision].pack('c') +
|
71
|
+
asset
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_a
|
75
|
+
case @asset
|
76
|
+
when 'CREA' then [(@amount.to_f * 1000).to_i.to_s, 3, '@@000000021']
|
77
|
+
when 'VESTS' then [(@amount.to_f * 1000000).to_i.to_s, 6, '@@000000037']
|
78
|
+
when 'CBD' then [(@amount.to_f * 1000).to_i.to_s, 3, '@@000000013']
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_h
|
83
|
+
case @asset
|
84
|
+
when 'CREA' then {
|
85
|
+
amount: (@amount.to_f * 1000).to_i.to_s,
|
86
|
+
precision: 3,
|
87
|
+
nai: '@@000000021'
|
88
|
+
}
|
89
|
+
when 'VESTS' then {
|
90
|
+
amount: (@amount.to_f * 1000000).to_i.to_s,
|
91
|
+
precision: 6,
|
92
|
+
nai: '@@000000037'
|
93
|
+
}
|
94
|
+
when 'CBD' then {
|
95
|
+
amount: (@amount.to_f * 1000).to_i.to_s,
|
96
|
+
precision: 3,
|
97
|
+
nai: '@@000000013'
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_s
|
103
|
+
"#{@amount} #{@asset}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|