radiator 0.2.0a
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/.codeclimate.yml +19 -0
- data/.gitignore +50 -0
- data/.travis.yml +12 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +86 -0
- data/LICENSE +41 -0
- data/README.md +362 -0
- data/Rakefile +39 -0
- data/lib/radiator/account_by_key_api.rb +7 -0
- data/lib/radiator/api.rb +168 -0
- data/lib/radiator/base_error.rb +17 -0
- data/lib/radiator/broadcast_operations.json +489 -0
- data/lib/radiator/chain_config.rb +29 -0
- data/lib/radiator/chain_stats_api.rb +15 -0
- data/lib/radiator/database_api.rb +4 -0
- data/lib/radiator/follow_api.rb +7 -0
- data/lib/radiator/logger.rb +18 -0
- data/lib/radiator/market_history_api.rb +19 -0
- data/lib/radiator/methods.json +488 -0
- data/lib/radiator/network_broadcast_api.rb +7 -0
- data/lib/radiator/operation.rb +75 -0
- data/lib/radiator/operation_ids.rb +80 -0
- data/lib/radiator/operation_types.rb +113 -0
- data/lib/radiator/stream.rb +260 -0
- data/lib/radiator/tag_api.rb +11 -0
- data/lib/radiator/transaction.rb +150 -0
- data/lib/radiator/type/amount.rb +36 -0
- data/lib/radiator/type/permission.rb +17 -0
- data/lib/radiator/type/point_in_time.rb +19 -0
- data/lib/radiator/type/public_key.rb +17 -0
- data/lib/radiator/type/u_int16.rb +19 -0
- data/lib/radiator/type/u_int32.rb +19 -0
- data/lib/radiator/utils.rb +62 -0
- data/lib/radiator/version.rb +3 -0
- data/lib/radiator.rb +29 -0
- data/radiator.gemspec +42 -0
- metadata +406 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
module Radiator
|
2
|
+
|
3
|
+
# See: https://github.com/steemit/steem-js/blob/766746adb5ded86380be982c844f4c269f7800ae/src/auth/serializer/src/operations.js
|
4
|
+
module OperationTypes
|
5
|
+
TYPES = {
|
6
|
+
transfer: {
|
7
|
+
amount: Type::Amount
|
8
|
+
},
|
9
|
+
transfer_to_vesting: {
|
10
|
+
amount: Type::Amount
|
11
|
+
},
|
12
|
+
withdraw_vesting: {
|
13
|
+
vesting_shares: Type::Amount
|
14
|
+
},
|
15
|
+
limit_order_create: {
|
16
|
+
orderid: Type::Uint32,
|
17
|
+
amount_to_sell: Type::Amount,
|
18
|
+
min_to_receive: Type::Amount,
|
19
|
+
expiration: Type::PointInTime
|
20
|
+
},
|
21
|
+
limit_order_cancel: {
|
22
|
+
orderid: Type::Uint32
|
23
|
+
},
|
24
|
+
convert: {
|
25
|
+
requestid: Type::Uint32,
|
26
|
+
amount: Type::Amount
|
27
|
+
},
|
28
|
+
account_create: {
|
29
|
+
fee: Type::Amount,
|
30
|
+
owner: Type::Permission,
|
31
|
+
active: Type::Permission,
|
32
|
+
posting: Type::Permission,
|
33
|
+
memo: Type::Permission
|
34
|
+
},
|
35
|
+
account_update: {
|
36
|
+
owner: Type::Permission,
|
37
|
+
active: Type::Permission,
|
38
|
+
posting: Type::Permission,
|
39
|
+
memo: Type::PublicKey
|
40
|
+
},
|
41
|
+
custom: {
|
42
|
+
id: Type::Uint16
|
43
|
+
},
|
44
|
+
comment_options: {
|
45
|
+
max_accepted_payout: Type::Amount
|
46
|
+
},
|
47
|
+
set_withdraw_vesting_route: {
|
48
|
+
percent: Type::Uint16
|
49
|
+
},
|
50
|
+
request_account_recovery: {
|
51
|
+
new_owner_Permission: Type::Permission
|
52
|
+
},
|
53
|
+
recover_account: {
|
54
|
+
new_owner_Permission: Type::Permission,
|
55
|
+
recent_owner_Permission: Type::Permission
|
56
|
+
},
|
57
|
+
escrow_transfer: {
|
58
|
+
sbd_amount: Type::Amount,
|
59
|
+
steem_amount: Type::Amount,
|
60
|
+
escrow_id: Type::Uint32,
|
61
|
+
fee: Type::Amount,
|
62
|
+
ratification_deadline: Type::PointInTime,
|
63
|
+
escrow_expiration: Type::PointInTime
|
64
|
+
},
|
65
|
+
escrow_dispute: {
|
66
|
+
escrow_id: Type::Uint32
|
67
|
+
},
|
68
|
+
escrow_release: {
|
69
|
+
escrow_id: Type::Uint32,
|
70
|
+
sbd_amount: Type::Amount,
|
71
|
+
steem_amount: Type::Amount
|
72
|
+
},
|
73
|
+
escrow_approve: {
|
74
|
+
escrow_id: Type::Uint32
|
75
|
+
},
|
76
|
+
transfer_to_savings: {
|
77
|
+
amount: Type::Amount
|
78
|
+
},
|
79
|
+
transfer_from_savings: {
|
80
|
+
request_id: Type::Uint32,
|
81
|
+
amount: Type::Amount
|
82
|
+
},
|
83
|
+
cancel_transfer_from_savings: {
|
84
|
+
request_id: Type::Uint32
|
85
|
+
},
|
86
|
+
reset_account: {
|
87
|
+
new_owner_Permission: Type::Amount
|
88
|
+
},
|
89
|
+
set_reset_account: {
|
90
|
+
reward_steem: Type::Amount,
|
91
|
+
reward_sbd: Type::Amount,
|
92
|
+
reward_vests: Type::Amount
|
93
|
+
},
|
94
|
+
claim_reward_balance: {
|
95
|
+
reward_steem: Type::Amount,
|
96
|
+
reward_sbd: Type::Amount,
|
97
|
+
reward_vests: Type::Amount
|
98
|
+
},
|
99
|
+
delegate_vesting_shares: {
|
100
|
+
vesting_shares: Type::Amount
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
def type(key, param, value)
|
105
|
+
return if value.nil?
|
106
|
+
|
107
|
+
t = TYPES[key] or return value
|
108
|
+
p = t[param] or return value
|
109
|
+
|
110
|
+
p.new(value)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
module Radiator
|
2
|
+
# Radiator::Stream allows a live view of the STEEM blockchain.
|
3
|
+
#
|
4
|
+
# All values returned by `get_dynamic_global_properties` can be streamed.
|
5
|
+
#
|
6
|
+
# For example, if you want to know which witness is currently signing blocks,
|
7
|
+
# use the following:
|
8
|
+
#
|
9
|
+
# stream = Radiator::Stream.new
|
10
|
+
# stream.current_witness do |witness|
|
11
|
+
# puts witness
|
12
|
+
# end
|
13
|
+
class Stream < Api
|
14
|
+
INITIAL_TIMEOUT = 0.0200
|
15
|
+
MAX_TIMEOUT = 80
|
16
|
+
MAX_BLOCKS_PER_NODE = 100
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
@api_options = options
|
20
|
+
@logger = @api_options[:logger] || Radiator.logger
|
21
|
+
end
|
22
|
+
|
23
|
+
def api
|
24
|
+
@api ||= Api.new(@api_options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def method_names
|
28
|
+
@method_names ||= [
|
29
|
+
:head_block_number,
|
30
|
+
:head_block_id,
|
31
|
+
:time,
|
32
|
+
:current_witness,
|
33
|
+
:total_pow,
|
34
|
+
:num_pow_witnesses,
|
35
|
+
:virtual_supply,
|
36
|
+
:current_supply,
|
37
|
+
:confidential_supply,
|
38
|
+
:current_sbd_supply,
|
39
|
+
:confidential_sbd_supply,
|
40
|
+
:total_vesting_fund_steem,
|
41
|
+
:total_vesting_shares,
|
42
|
+
:total_reward_fund_steem,
|
43
|
+
:total_reward_shares2,
|
44
|
+
:total_activity_fund_steem,
|
45
|
+
:total_activity_fund_shares,
|
46
|
+
:sbd_interest_rate,
|
47
|
+
:average_block_size,
|
48
|
+
:maximum_block_size,
|
49
|
+
:current_aslot,
|
50
|
+
:recent_slots_filled,
|
51
|
+
:participation_count,
|
52
|
+
:last_irreversible_block_num,
|
53
|
+
:max_virtual_bandwidth,
|
54
|
+
:current_reserve_ratio,
|
55
|
+
:block_numbers,
|
56
|
+
:blocks
|
57
|
+
].freeze
|
58
|
+
end
|
59
|
+
|
60
|
+
def method_params(method)
|
61
|
+
case method
|
62
|
+
when :block_numbers then {head_block_number: nil}
|
63
|
+
when :blocks then {get_block: :head_block_number}
|
64
|
+
else; nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns the latest operations from the blockchain.
|
69
|
+
#
|
70
|
+
# If symbol are passed, then only that operation is returned. Expected
|
71
|
+
# symbols are:
|
72
|
+
#
|
73
|
+
# transfer_to_vesting
|
74
|
+
# withdraw_vesting
|
75
|
+
# interest
|
76
|
+
# transfer
|
77
|
+
# liquidity_reward
|
78
|
+
# author_reward
|
79
|
+
# curation_reward
|
80
|
+
# transfer_to_savings
|
81
|
+
# transfer_from_savings
|
82
|
+
# cancel_transfer_from_savings
|
83
|
+
# escrow_transfer
|
84
|
+
# escrow_approve
|
85
|
+
# escrow_dispute
|
86
|
+
# escrow_release
|
87
|
+
# comment
|
88
|
+
# limit_order_create
|
89
|
+
# limit_order_cancel
|
90
|
+
# fill_convert_request
|
91
|
+
# fill_order
|
92
|
+
# vote
|
93
|
+
# account_witness_vote
|
94
|
+
# account_witness_proxy
|
95
|
+
# account_create
|
96
|
+
# account_update
|
97
|
+
# witness_update
|
98
|
+
# pow
|
99
|
+
# custom
|
100
|
+
#
|
101
|
+
# @param type [symbol || Array<symbol>] the type(s) of operation, optional.
|
102
|
+
# @param start starting block
|
103
|
+
# @param mode we have the choice between
|
104
|
+
# * :head the last block
|
105
|
+
# * :irreversible the block that is confirmed by 2/3 of all block producers and is thus irreversible!
|
106
|
+
# @param block the block to execute for each result, optional.
|
107
|
+
# @return [Hash]
|
108
|
+
def operations(type = nil, start = nil, mode = :irreversible, &block)
|
109
|
+
transactions(start, mode) do |transaction|
|
110
|
+
ops = transaction.operations.map do |t, op|
|
111
|
+
t = t.to_sym
|
112
|
+
if type == t
|
113
|
+
op
|
114
|
+
elsif type.nil? || [type].flatten.include?(t)
|
115
|
+
{t => op}
|
116
|
+
end
|
117
|
+
end.compact
|
118
|
+
|
119
|
+
next if ops.none?
|
120
|
+
|
121
|
+
return ops unless !!block
|
122
|
+
|
123
|
+
ops.each do |op|
|
124
|
+
yield op
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns the latest transactions from the blockchain.
|
130
|
+
#
|
131
|
+
# @param start starting block
|
132
|
+
# @param mode we have the choice between
|
133
|
+
# * :head the last block
|
134
|
+
# * :irreversible the block that is confirmed by 2/3 of all block producers and is thus irreversible!
|
135
|
+
# @param block the block to execute for each result, optional.
|
136
|
+
# @return [Hash]
|
137
|
+
def transactions(start = nil, mode = :irreversible, &block)
|
138
|
+
blocks(start, mode) do |b|
|
139
|
+
next if (_transactions = b.transactions).nil?
|
140
|
+
return _transactions unless !!block
|
141
|
+
|
142
|
+
_transactions.each.each do |transaction|
|
143
|
+
yield transaction
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the latest blocks from the blockchain.
|
149
|
+
#
|
150
|
+
# @param start starting block
|
151
|
+
# @param mode we have the choice between
|
152
|
+
# * :head the last block
|
153
|
+
# * :irreversible the block that is confirmed by 2/3 of all block producers and is thus irreversible!
|
154
|
+
# * :max_blocks_per_node the number of blocks to read before trying a new node
|
155
|
+
# @param block the block to execute for each result, optional.
|
156
|
+
# @return [Hash]
|
157
|
+
def blocks(start = nil, mode = :irreversible, max_blocks_per_node = MAX_BLOCKS_PER_NODE, &block)
|
158
|
+
counter = 0
|
159
|
+
|
160
|
+
if start.nil?
|
161
|
+
properties = api.get_dynamic_global_properties.result
|
162
|
+
start = case mode.to_sym
|
163
|
+
when :head then properties.head_block_number
|
164
|
+
when :irreversible then properties.last_irreversible_block_num
|
165
|
+
else; raise StreamError, '"mode" has to be "head" or "irreversible"'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
loop do
|
170
|
+
properties = api.get_dynamic_global_properties.result
|
171
|
+
|
172
|
+
head_block = case mode.to_sym
|
173
|
+
when :head then properties.head_block_number
|
174
|
+
when :irreversible then properties.last_irreversible_block_num
|
175
|
+
else; raise StreamError, '"mode" has to be "head" or "irreversible"'
|
176
|
+
end
|
177
|
+
|
178
|
+
[*(start..(head_block))].each do |n|
|
179
|
+
if (counter += 1) > max_blocks_per_node
|
180
|
+
shutdown
|
181
|
+
counter = 0
|
182
|
+
end
|
183
|
+
|
184
|
+
response = api.send(:get_block, n)
|
185
|
+
raise StreamError, JSON[response.error] if !!response.error
|
186
|
+
result = response.result
|
187
|
+
|
188
|
+
if !!block
|
189
|
+
yield result
|
190
|
+
else
|
191
|
+
return result
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
start = head_block + 1
|
196
|
+
sleep 3
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def method_missing(m, *args, &block)
|
201
|
+
super unless respond_to_missing?(m)
|
202
|
+
|
203
|
+
@latest_values ||= []
|
204
|
+
@latest_values.shift(5) if @latest_values.size > 20
|
205
|
+
loop do
|
206
|
+
value = if (n = method_params(m)).nil?
|
207
|
+
key_value = api.get_dynamic_global_properties.result[m]
|
208
|
+
else
|
209
|
+
key = n.keys.first
|
210
|
+
if !!n[key]
|
211
|
+
r = api.get_dynamic_global_properties.result
|
212
|
+
key_value = param = r[n[key]]
|
213
|
+
result = nil
|
214
|
+
loop do
|
215
|
+
response = api.send(key, param)
|
216
|
+
raise StreamError, JSON[response.error] if !!response.error
|
217
|
+
result = response.result
|
218
|
+
break if !!result
|
219
|
+
@logger.warn "#{key}: #{param} result missing, retrying with timeout: #{@timeout || INITIAL_TIMEOUT} seconds"
|
220
|
+
shutdown
|
221
|
+
sleep timeout
|
222
|
+
end
|
223
|
+
@timeout = INITIAL_TIMEOUT
|
224
|
+
result
|
225
|
+
else
|
226
|
+
key_value = api.get_dynamic_global_properties.result[key]
|
227
|
+
end
|
228
|
+
end
|
229
|
+
unless @latest_values.include? key_value
|
230
|
+
@latest_values << key_value
|
231
|
+
if !!block
|
232
|
+
yield value
|
233
|
+
else
|
234
|
+
return value
|
235
|
+
end
|
236
|
+
end
|
237
|
+
sleep 0.0200
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def timeout
|
242
|
+
@timeout ||= INITIAL_TIMEOUT
|
243
|
+
@timeout *= 2
|
244
|
+
@timeout = INITIAL_TIMEOUT if @timeout > MAX_TIMEOUT
|
245
|
+
@timeout
|
246
|
+
end
|
247
|
+
|
248
|
+
# Stops the persistant http connections.
|
249
|
+
#
|
250
|
+
def shutdown
|
251
|
+
begin
|
252
|
+
@api.shutdown
|
253
|
+
rescue => e
|
254
|
+
@logger.warn("Unable to shut down: #{e}")
|
255
|
+
end
|
256
|
+
|
257
|
+
@api = nil
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'bitcoin'
|
2
|
+
require 'digest'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Radiator
|
6
|
+
# * graphenej:
|
7
|
+
# * https://github.com/kenCode-de/graphenej/blob/master/graphenej/src/main/java/de/bitsharesmunich/graphenej/Transaction.java#L142
|
8
|
+
class Transaction
|
9
|
+
include ChainConfig
|
10
|
+
include Utils
|
11
|
+
|
12
|
+
VALID_OPTIONS = %w(
|
13
|
+
wif private_key ref_block_num ref_block_prefix expiration operations
|
14
|
+
chain
|
15
|
+
).map(&:to_sym)
|
16
|
+
VALID_OPTIONS.each { |option| attr_accessor option }
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
options.each do |k, v|
|
20
|
+
k = k.to_sym
|
21
|
+
if VALID_OPTIONS.include?(k.to_sym)
|
22
|
+
options.delete(k)
|
23
|
+
send("#{k}=", v)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
@logger = options[:logger] || Radiator.logger
|
28
|
+
@chain ||= :steem
|
29
|
+
@chain_id = chain_id options[:chain_id]
|
30
|
+
@url = options[:url] || url
|
31
|
+
@operations ||= []
|
32
|
+
|
33
|
+
unless NETWORK_CHAIN_IDS.include? @chain_id
|
34
|
+
@logger.warn "Unknown chain id: #{@chain_id}"
|
35
|
+
end
|
36
|
+
|
37
|
+
if !!wif && !!private_key
|
38
|
+
raise TransactionError, "Do not pass both wif and private_key. That's confusing."
|
39
|
+
end
|
40
|
+
|
41
|
+
if !!wif
|
42
|
+
@private_key = Bitcoin::Key.from_base58 wif
|
43
|
+
end
|
44
|
+
|
45
|
+
options = options.merge(url: @url)
|
46
|
+
@api = Api.new(options)
|
47
|
+
@network_broadcast_api = NetworkBroadcastApi.new(options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def chain_id(chain_id = nil)
|
51
|
+
return chain_id if !!chain_id
|
52
|
+
|
53
|
+
case chain.to_s.downcase.to_sym
|
54
|
+
when :steem then NETWORKS_STEEM_CHAIN_ID
|
55
|
+
when :golos then NETWORKS_GOLOS_CHAIN_ID
|
56
|
+
when :test then NETWORKS_TEST_CHAIN_ID
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def url
|
61
|
+
case chain.to_s.downcase.to_sym
|
62
|
+
when :steem then NETWORKS_STEEM_DEFAULT_NODE
|
63
|
+
when :golos then NETWORKS_GOLOS_DEFAULT_NODE
|
64
|
+
when :test then NETWORKS_TEST_DEFAULT_NODE
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def process(broadcast = false)
|
69
|
+
prepare
|
70
|
+
|
71
|
+
if broadcast
|
72
|
+
@network_broadcast_api.broadcast_transaction_synchronous(payload)
|
73
|
+
else
|
74
|
+
self
|
75
|
+
end
|
76
|
+
end
|
77
|
+
private
|
78
|
+
def payload
|
79
|
+
{
|
80
|
+
expiration: @expiration.strftime('%Y-%m-%dT%H:%M:%S'),
|
81
|
+
ref_block_num: @ref_block_num,
|
82
|
+
ref_block_prefix: @ref_block_prefix,
|
83
|
+
operations: @operations.map { |op| op.payload },
|
84
|
+
extensions: [],
|
85
|
+
signatures: [hexlify(signature)]
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def prepare
|
90
|
+
raise TransactionError, "No wif or private key." unless !!@wif || !!@private_key
|
91
|
+
|
92
|
+
@properties = @api.get_dynamic_global_properties.result
|
93
|
+
@ref_block_num = @properties.head_block_number & 0xFFFF
|
94
|
+
@ref_block_prefix = unhexlify(@properties.head_block_id[8..-1]).unpack('V*')[0]
|
95
|
+
|
96
|
+
# The expiration allows for transactions to expire if they are not
|
97
|
+
# included into a block by that time. Always update it to the current
|
98
|
+
# time + EXPIRE_IN_SECS.
|
99
|
+
@expiration = Time.parse(@properties.time + 'Z') + EXPIRE_IN_SECS
|
100
|
+
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_bytes
|
105
|
+
bytes = unhexlify(@chain_id)
|
106
|
+
bytes << pakS(@ref_block_num)
|
107
|
+
bytes << pakI(@ref_block_prefix)
|
108
|
+
bytes << pakI(@expiration.to_i)
|
109
|
+
bytes << pakC(@operations.size)
|
110
|
+
|
111
|
+
@operations.each do |op|
|
112
|
+
bytes << op.to_bytes
|
113
|
+
end
|
114
|
+
|
115
|
+
bytes << 0x00 # extensions
|
116
|
+
|
117
|
+
bytes
|
118
|
+
end
|
119
|
+
|
120
|
+
def digest
|
121
|
+
Digest::SHA256.digest(to_bytes)
|
122
|
+
end
|
123
|
+
|
124
|
+
def signature
|
125
|
+
public_key_hex = @private_key.pub
|
126
|
+
ec = Bitcoin::OpenSSL_EC
|
127
|
+
digest_hex = digest.freeze
|
128
|
+
|
129
|
+
loop do
|
130
|
+
@expiration += 1
|
131
|
+
sig = ec.sign_compact(digest_hex, @private_key.priv, public_key_hex)
|
132
|
+
|
133
|
+
next if public_key_hex != ec.recover_compact(digest_hex, sig)
|
134
|
+
|
135
|
+
return sig if canonical? sig
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def canonical?(sig)
|
140
|
+
sig = sig.unpack('C*')
|
141
|
+
|
142
|
+
!(
|
143
|
+
((sig[0] & 0x80 ) != 0) || ( sig[0] == 0 ) ||
|
144
|
+
((sig[1] & 0x80 ) != 0) ||
|
145
|
+
((sig[32] & 0x80 ) != 0) || ( sig[32] == 0 ) ||
|
146
|
+
((sig[33] & 0x80 ) != 0)
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Radiator
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/piston-lib/blob/34a7525cee119ec9b24a99577ede2d54466fca0e/steembase/operations.py
|
5
|
+
class Amount
|
6
|
+
def initialize(value)
|
7
|
+
@amount, @asset = value.strip.split(' ')
|
8
|
+
@precision = case @asset
|
9
|
+
when 'STEEM' then 3
|
10
|
+
when 'VESTS' then 6
|
11
|
+
when 'SBD' then 3
|
12
|
+
when 'GOLOS' then 3
|
13
|
+
when 'GESTS' then 6
|
14
|
+
when 'GBG' then 3
|
15
|
+
when 'CORE' then 3
|
16
|
+
when 'CESTS' then 6
|
17
|
+
when 'TEST' then 3
|
18
|
+
else; raise TypeError, "Asset #{@asset} unknown."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_bytes
|
23
|
+
asset = @asset.ljust(7, "\x00")
|
24
|
+
amount = (@amount.to_f * 10 ** @precision).round
|
25
|
+
|
26
|
+
[amount].pack('q') +
|
27
|
+
[@precision].pack('c') +
|
28
|
+
asset
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"#{@amount} #{@asset}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Radiator
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/piston-lib/blob/34a7525cee119ec9b24a99577ede2d54466fca0e/steembase/operations.py
|
5
|
+
class Permission
|
6
|
+
def initialize()
|
7
|
+
raise NotImplementedError, 'stub'
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Radiator
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/python-graphenelib/blob/98de98e219264d45fe04b3c28f3aabd1a9f58b71/graphenebase/types.py
|
5
|
+
class PointInTime
|
6
|
+
def initialize(value)
|
7
|
+
@value = value
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes
|
11
|
+
[Time.parse(@value + 'Z').to_i].pack('I')
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Radiator
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/piston-lib/blob/34a7525cee119ec9b24a99577ede2d54466fca0e/steembase/operations.py
|
5
|
+
class PublicKey
|
6
|
+
def initialize()
|
7
|
+
raise NotImplementedError, 'stub'
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Radiator
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/piston-lib/blob/34a7525cee119ec9b24a99577ede2d54466fca0e/steembase/operations.py
|
5
|
+
class Uint16
|
6
|
+
def initialize(value)
|
7
|
+
@value = value.to_i
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes
|
11
|
+
[@value].pack('S')
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@value.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Radiator
|
2
|
+
module Type
|
3
|
+
|
4
|
+
# See: https://github.com/xeroc/piston-lib/blob/34a7525cee119ec9b24a99577ede2d54466fca0e/steembase/operations.py
|
5
|
+
class Uint32
|
6
|
+
def initialize(value)
|
7
|
+
@value = value.to_i
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_bytes
|
11
|
+
[@value].pack('L')
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@value.to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|