steem-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1056 @@
1
+ require 'bitcoin'
2
+ require 'digest'
3
+ require 'time'
4
+
5
+ module Steem
6
+
7
+ # These class methods make it simple to do things like broacast a {Broadcast#vote}
8
+ # or {Broadcast#comment} operation. They accept all of the fields expected by
9
+ # the blockchain plus the following additional options:
10
+ #
11
+ # * wif
12
+ # * url (optional)
13
+ # * database_api (optional)
14
+ # * block_api (optional)
15
+ # * network_broadcast_api (optional)
16
+ # * pretend (optional)
17
+ #
18
+ # These options are not sent in the broadcast. The `wif` authorities can be
19
+ # posting, active, and owner.
20
+ #
21
+ # Setting `url` will allow you to specify a different node instead of taking
22
+ # the default: ({ChainConfig::NETWORKS_STEEM_DEFAULT_NODE}).
23
+ #
24
+ # Setting `database_api`, `block_api`, and `network_broadcast_api` is
25
+ # optional, doing so will allow you to override the default node and/or the
26
+ # RPC Client.
27
+ #
28
+ # When passing the `pretend` field, if it is set to {::True}, nothing is
29
+ # broadcasted, but the `wif` is checked for the proper authority.
30
+ #
31
+ # For details on what to pass to these methods, check out the {https://developers.steem.io/apidefinitions/broadcast-ops Steem Developer Portal Broadcast Operations} page.
32
+ class Broadcast
33
+ extend Retriable
34
+
35
+ DEFAULT_MAX_ACCEPTED_PAYOUT = Type::Amount.new(["1000000000", 3, "@@000000013"])
36
+
37
+ # This operation is used to cast a vote on a post/comment.
38
+ #
39
+ # options = {
40
+ # wif: wif,
41
+ # params: {
42
+ # voter: voter,
43
+ # author: author,
44
+ # permlink: permlink,
45
+ # weight: weight
46
+ # }
47
+ # }
48
+ #
49
+ # Steem::Broadcast.vote(options) do |result|
50
+ # puts result
51
+ # end
52
+ #
53
+ # @param options [Hash] options
54
+ # @option options [String] :wif Posting wif
55
+ # @option options [Hash] :params
56
+ # * :voter (String)
57
+ # * :author (String)
58
+ # * :permlink (String)
59
+ # * :weight (Number)
60
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
61
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_vote
62
+ def self.vote(options, &block)
63
+ required_fields = %i(voter author permlink weight)
64
+ params = options[:params]
65
+ check_required_fields(params, *required_fields)
66
+
67
+ ops = [[:vote, params]]
68
+
69
+ process(options.merge(ops: ops), &block)
70
+ end
71
+
72
+ # Creates a post/comment. This method simplifies content creation by
73
+ # combining `comment` and `comment_options` into one transaction.
74
+ #
75
+ # options = {
76
+ # wif: wif,
77
+ # params: {
78
+ # author: author,
79
+ # title: 'This is my fancy post title.',
80
+ # body: 'This is my fancy post body.',
81
+ # metadata: {
82
+ # tags: %w(these are my fancy tags)
83
+ # }
84
+ # }
85
+ # }
86
+ #
87
+ # Steem::Broadcast.comment(options)
88
+ #
89
+ # options = {
90
+ # wif: wif,
91
+ # params: {
92
+ # author: author,
93
+ # title: 'This is my fancy post title.',
94
+ # body: 'This is my fancy post body.',
95
+ # metadata: {
96
+ # tags: %w(these are my fancy tags)
97
+ # },
98
+ # beneficiaries: [
99
+ # {account: "david", weight: 500},
100
+ # {account: "erin", weight: 500},
101
+ # {account: "faythe", weight: 1000},
102
+ # {account: "frank", weight: 500}
103
+ # ]
104
+ # }
105
+ # }
106
+ #
107
+ # Steem::Broadcast.comment(options)
108
+ #
109
+ # @param options [Hash] options
110
+ # @option options [String] :wif Posting wif
111
+ # @option options [Hash] :params
112
+ # * :author (String)
113
+ # * :title (String) Title of the content.
114
+ # * :body (String) Body of the content.
115
+ # * :metadata (Hash) Metadata of the content, becomes `json_metadata`.
116
+ # * :permlink (String) (automatic) Permlink of the content, defaults to formatted title.
117
+ # * :parent_permlink (String) (automatic) Parent permlink of the content, defaults to first tag.
118
+ # * :parent_author (String) (optional) Parent author of the content (only used if reply).
119
+ # * :max_accepted_payout (String) (1000000.000 SBD) Maximum accepted payout, set to '0.000 SBD' to deline payout
120
+ # * :percent_steem_dollars (Numeric) (5000) Percent STEEM Dollars is used to set 50/50 or 100% STEEM Power
121
+ # * :allow_votes (Numeric) (true) Allow votes for this content.
122
+ # * :allow_curation_rewards (Numeric) (true) Allow curation rewards for this content.
123
+ # * :beneficiaries (Array<Hash>) Sets the beneficiaries of this content.
124
+ # * :pretend (Boolean) Just validate, do not broadcast.
125
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_comment
126
+ def self.comment(options, &block)
127
+ required_fields = %i(author body permlink parent_permlink)
128
+ params = options[:params]
129
+ metadata = (params[:metadata] rescue nil) || {}
130
+ metadata['app'] ||= Steem::AGENT_ID
131
+ tags = metadata['tags'] || []
132
+ params[:parent_permlink] ||= tags.first
133
+
134
+ if !!params[:title]
135
+ params[:permlink] ||= params[:title].downcase.gsub(/[^a-z0-9\-]+/, '-')
136
+ end
137
+
138
+ check_required_fields(params, *required_fields)
139
+
140
+ ops = [[:comment, {
141
+ parent_author: params[:parent_author] || '',
142
+ parent_permlink: params[:parent_permlink],
143
+ author: params[:author],
144
+ permlink: params[:permlink],
145
+ title: params[:title] || '',
146
+ body: params[:body],
147
+ json_metadata: metadata.to_json
148
+ }]]
149
+
150
+ max_accepted_payout = if params.keys.include? :max_accepted_payout
151
+ Type::Amount.to_nia(params[:max_accepted_payout])
152
+ else
153
+ DEFAULT_MAX_ACCEPTED_PAYOUT.to_nia
154
+ end
155
+
156
+ allow_votes = if params.keys.include? :allow_votes
157
+ !!params[:allow_votes]
158
+ else
159
+ true
160
+ end
161
+
162
+ allow_curation_rewards = if params.keys.include? :allow_curation_rewards
163
+ !!params[:allow_curation_rewards]
164
+ else
165
+ true
166
+ end
167
+
168
+ comment_options = {
169
+ author: params[:author],
170
+ permlink: params[:permlink],
171
+ max_accepted_payout: max_accepted_payout,
172
+ percent_steem_dollars: params[:percent_steem_dollars] || 10000,
173
+ allow_votes: allow_votes,
174
+ allow_curation_rewards: allow_curation_rewards,
175
+ extensions: []
176
+ }
177
+
178
+ if !!params[:beneficiaries]
179
+ comment_options[:extensions] << [0, {beneficiaries: params[:beneficiaries]}]
180
+ end
181
+
182
+ ops << [:comment_options, comment_options]
183
+
184
+ process(options.merge(ops: ops), &block)
185
+ end
186
+
187
+ # Deletes a post/comment.
188
+ #
189
+ # Steem::Broadcast.delete_comment(wif: wif, params: {author: author, permlink: permlink}) do |result|
190
+ # puts result
191
+ # end
192
+ #
193
+ # @param options [Hash] options
194
+ # @option options [String] :wif Posting wif
195
+ # @option options [Hash] :params
196
+ # * :author (String)
197
+ # * :permlink (String)
198
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
199
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_delete_comment
200
+ def self.delete_comment(options, &block)
201
+ required_fields = %i(author permlink)
202
+ params = options[:params]
203
+ check_required_fields(params, *required_fields)
204
+
205
+ ops = [[:delete_comment, params]]
206
+
207
+ process(options.merge(ops: ops), &block)
208
+ end
209
+
210
+ # Transfers asset from one account to another.
211
+ #
212
+ # options = {
213
+ # wif: wif,
214
+ # params: {
215
+ # from: from,
216
+ # to: to,
217
+ # amount: amount,
218
+ # memo: memo
219
+ # }
220
+ # }
221
+ #
222
+ # Steem::Broadcast.transfer(options) do |result|
223
+ # puts result
224
+ # end
225
+ #
226
+ # @param options [Hash] options
227
+ # @option options [String] :wif Active wif
228
+ # @option options [Hash] :params
229
+ # * :from (String)
230
+ # * :to (String)
231
+ # * :amount (String)
232
+ # * :memo (String)
233
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
234
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_transfer
235
+ def self.transfer(options, &block)
236
+ required_fields = %i(from to amount memo)
237
+ params = options[:params]
238
+ check_required_fields(params, *required_fields)
239
+
240
+ params[:amount] = Type::Amount.to_nia(params[:amount])
241
+
242
+ ops = [[:transfer, params]]
243
+
244
+ process(options.merge(ops: ops), &block)
245
+ end
246
+
247
+ # This operation converts STEEM into VFS (Vesting Fund Shares) at the
248
+ # current exchange rate.
249
+ #
250
+ # options = {
251
+ # wif: wif,
252
+ # params: {
253
+ # from: from,
254
+ # to: to,
255
+ # amount: amount,
256
+ # }
257
+ # }
258
+ #
259
+ # Steem::Broadcast.transfer_to_vesting(options) do |result|
260
+ # puts result
261
+ # end
262
+ #
263
+ # @param options [Hash] options
264
+ # @option options [String] :wif Active wif
265
+ # @option options [Hash] :params
266
+ # * :from (String)
267
+ # * :to (String)
268
+ # * :amount (String)
269
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
270
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_transfer_to_vesting
271
+ def self.transfer_to_vesting(options, &block)
272
+ required_fields = %i(from to amount)
273
+ params = options[:params]
274
+ check_required_fields(params, *required_fields)
275
+
276
+ params[:amount] = Type::Amount.to_nia(params[:amount])
277
+
278
+ ops = [[:transfer_to_vesting, params]]
279
+
280
+ process(options.merge(ops: ops), &block)
281
+ end
282
+
283
+ # At any given point in time an account can be withdrawing from their
284
+ # vesting shares.
285
+ #
286
+ # Steem::Broadcast.withdraw_vesting(wif: wif, params: {account: account, vesting_shares: vesting_shares}) do |result|
287
+ # puts result
288
+ # end
289
+ #
290
+ # @param options [Hash] options
291
+ # @option options [String] :wif Active wif
292
+ # @option options [Hash] :params
293
+ # * :account (String)
294
+ # * :vesting_shares (String)
295
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
296
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_withdraw_vesting
297
+ def self.withdraw_vesting(options, &block)
298
+ required_fields = %i(account vesting_shares)
299
+ params = options[:params]
300
+ check_required_fields(params, *required_fields)
301
+
302
+ params[:vesting_shares] = Type::Amount.to_nia(params[:vesting_shares])
303
+
304
+ ops = [[:withdraw_vesting, params]]
305
+
306
+ process(options.merge(ops: ops), &block)
307
+ end
308
+
309
+ # This operation creates a limit order and matches it against existing open
310
+ # orders.
311
+ #
312
+ # @param options [Hash] options
313
+ # @option options [String] :wif Active wif
314
+ # @option options [Hash] :params
315
+ # * :owner (String)
316
+ # * :orderid (String)
317
+ # * :amount_to_sell (String)
318
+ # * :min_to_receive (String)
319
+ # * :fill_or_kill (Boolean)
320
+ # * :expiration (String)
321
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
322
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_limit_order_create
323
+ def self.limit_order_create(options, &block)
324
+ required_fields = %i(owner orderid amount_to_sell min_to_receive
325
+ fill_or_kill)
326
+ params = options[:params]
327
+ check_required_fields(params, *required_fields)
328
+
329
+ params[:amount_to_sell] = Type::Amount.to_nia(params[:amount_to_sell])
330
+ params[:min_to_receive] = Type::Amount.to_nia(params[:min_to_receive])
331
+
332
+ if !!params[:expiration]
333
+ params[:expiration] = Time.parse(params[:expiration].to_s)
334
+ params[:expiration] = params[:expiration].strftime('%Y-%m-%dT%H:%M:%S')
335
+ end
336
+
337
+ ops = [[:limit_order_create, params]]
338
+
339
+ process(options.merge(ops: ops), &block)
340
+ end
341
+
342
+ # Cancels an order and returns the balance to owner.
343
+ #
344
+ # @param options [Hash] options
345
+ # @option options [String] :wif Active wif
346
+ # @option options [Hash] :params
347
+ # * :owner (String)
348
+ # * :orderid (String)
349
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
350
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_limit_order_cancel
351
+ def self.limit_order_cancel(options, &block)
352
+ required_fields = %i(owner orderid)
353
+ params = options[:params]
354
+ check_required_fields(params, *required_fields)
355
+
356
+ ops = [[:limit_order_cancel, params]]
357
+
358
+ process(options.merge(ops: ops), &block)
359
+ end
360
+
361
+ # Feeds can only be published by the top N witnesses which are included in
362
+ # every round and are used to define the exchange rate between steem and the
363
+ # dollar.
364
+ #
365
+ # @param options [Hash] options
366
+ # @option options [String] :wif Active wif
367
+ # @option options [Hash] :params
368
+ # * :publisher (String)
369
+ # * :exchange_rate (Hash)
370
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
371
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_feed_publish
372
+ def self.feed_publish(options, &block)
373
+ required_fields = %i(publisher exchange_rate)
374
+ params = options[:params]
375
+ check_required_fields(params, *required_fields)
376
+
377
+ exchange_rate = params[:exchange_rate] rescue {}
378
+ base = exchange_rate[:base]
379
+ quote = exchange_rate[:quote]
380
+ params[:exchange_rate][:base] = Type::Amount.to_nia(base)
381
+ params[:exchange_rate][:quote] = Type::Amount.to_nia(quote)
382
+
383
+ ops = [[:feed_publish, params]]
384
+
385
+ process(options.merge(ops: ops), &block)
386
+ end
387
+
388
+ # This operation instructs the blockchain to start a conversion between
389
+ # STEEM and SBD, the funds are deposited after 3.5 days.
390
+ #
391
+ # @param options [Hash] options
392
+ # @option options [String] :wif Active wif
393
+ # @option options [Hash] :params
394
+ # * :owner (String)
395
+ # * :requestid (String)
396
+ # * :amount (String)
397
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
398
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_convert
399
+ def self.convert(options, &block)
400
+ required_fields = %i(owner requestid amount)
401
+ params = options[:params]
402
+ check_required_fields(params, *required_fields)
403
+
404
+ params[:amount] = Type::Amount.to_nia(params[:amount])
405
+
406
+ ops = [[:convert, params]]
407
+
408
+ process(options.merge(ops: ops), &block)
409
+ end
410
+
411
+ # Create an account.
412
+ # options = {
413
+ # wif: wif,
414
+ # params: {
415
+ # fee: '1.000 STEEM',
416
+ # creator: creator_account_name,
417
+ # new_account_name: new_account_name,
418
+ # owner: {
419
+ # weight_threshold: 1,
420
+ # account_auths: [],
421
+ # key_auths: [[owner_public_key, 1]],
422
+ # },
423
+ # active: {
424
+ # weight_threshold: 1,
425
+ # account_auths: [],
426
+ # key_auths: [[active_public_key, 1]],
427
+ # },
428
+ # posting: {
429
+ # weight_threshold: 1,
430
+ # account_auths: [],
431
+ # key_auths: [[posting_public_key, 1]],
432
+ # },
433
+ # memo_key: memo_public_key,
434
+ # json_metadata: '{}'
435
+ # }
436
+ # }
437
+ #
438
+ # Steem::Broadcast.account_create(options)
439
+ #
440
+ # @param options [Hash] options
441
+ # @option options [String] :wif Active wif
442
+ # @option options [Hash] :params
443
+ # * :fee (String)
444
+ # * :creator (String)
445
+ # * :new_account_name (String)
446
+ # * :owner (Hash)
447
+ # * :active (Hash)
448
+ # * :posting (Hash)
449
+ # * :memo_key (String)
450
+ # * :json_metadata (String)
451
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
452
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_account_create
453
+ def self.account_create(options, &block)
454
+ required_fields = %i(fee creator new_account_name owner active posting memo_key json_metadata)
455
+ params = options[:params]
456
+ check_required_fields(params, *required_fields)
457
+
458
+ params[:fee] = Type::Amount.to_nia(params[:fee])
459
+
460
+ ops = [[:account_create, params]]
461
+
462
+ process(options.merge(ops: ops), &block)
463
+ end
464
+
465
+ # Update an account.
466
+ # options = {
467
+ # wif: wif,
468
+ # params: {
469
+ # account: new_account_name,
470
+ # owner: {
471
+ # weight_threshold: 1,
472
+ # account_auths: [],
473
+ # key_auths: [[owner_public_key, 1]],
474
+ # },
475
+ # active: {
476
+ # weight_threshold: 1,
477
+ # account_auths: [],
478
+ # key_auths: [[active_public_key, 1]],
479
+ # },
480
+ # posting: {
481
+ # weight_threshold: 1,
482
+ # account_auths: [],
483
+ # key_auths: [[posting_public_key, 1]],
484
+ # },
485
+ # memo_key: memo_public_key,
486
+ # json_metadata: '{}'
487
+ # }
488
+ # }
489
+ #
490
+ # Steem::Broadcast.account_update(options)
491
+ #
492
+ # @param options [Hash] options
493
+ # @option options [String] :wif Active wif
494
+ # @option options [Hash] :params
495
+ # * :account (String)
496
+ # * :owner (Hash) (optional)
497
+ # * :active (Hash) (optional)
498
+ # * :posting (Hash) (optional)
499
+ # * :memo_key (String) (optional)
500
+ # @option options [String] :json_metadata (optional)
501
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
502
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_account_update
503
+ def self.account_update(options, &block)
504
+ required_fields = %i(account)
505
+ params = options[:params]
506
+ check_required_fields(params, *required_fields)
507
+
508
+ ops = [[:account_update, params]]
509
+
510
+ process(options.merge(ops: ops), &block)
511
+ end
512
+
513
+ # Users who wish to become a witness must pay a fee acceptable to the
514
+ # current witnesses to apply for the position and allow voting to begin.
515
+ #
516
+ # options = {
517
+ # wif: wif,
518
+ # params: {
519
+ # owner: witness_account_name,
520
+ # url: '',
521
+ # block_signing_key: 'STM8ZSyzjPm48GmUuMSRufkVYkwYbZzbxeMysAVp7KFQwbTf98TcG',
522
+ # props: {
523
+ # account_creation_fee: '0.000 STEEM',
524
+ # maximum_block_size: 131072,
525
+ # sbd_interest_rate:1000
526
+ # },
527
+ # fee: '0.000 STEEM',
528
+ # }
529
+ # }
530
+ #
531
+ # Steem::Broadcast.witness_update(options)
532
+ #
533
+ # @param options [Hash] options
534
+ # @option options [String] :wif Active wif
535
+ # @option options [Hash] :params
536
+ # * :owner (String)
537
+ # * :url (String) (optional)
538
+ # * :block_signing_key (String)
539
+ # * :props (String)
540
+ # * :fee (String)
541
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
542
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_witness_update
543
+ def self.witness_update(options, &block)
544
+ required_fields = %i(owner block_signing_key props fee)
545
+ params = options[:params]
546
+ check_required_fields(params, *required_fields)
547
+
548
+ account_creation_fee = params[:props][:account_creation_fee] rescue nil
549
+ params[:props][:account_creation_fee] = Type::Amount.to_nia(account_creation_fee)
550
+ params[:fee] = Type::Amount.to_nia(params[:fee])
551
+
552
+ ops = [[:witness_update, params]]
553
+
554
+ process(options.merge(ops: ops), &block)
555
+ end
556
+
557
+ # All accounts with a VFS (Vesting Fund Shares) can vote for or against any
558
+ # witness.
559
+ #
560
+ # @param options [Hash] options
561
+ # @option options [String] :wif Active wif
562
+ # @option options [Hash] :params
563
+ # * :account (String)
564
+ # * :witness (String)
565
+ # * :approve (Boolean)
566
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
567
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_account_witness_vote
568
+ def self.account_witness_vote(options, &block)
569
+ required_fields = %i(account witness approve)
570
+ params = options[:params]
571
+ check_required_fields(params, *required_fields)
572
+
573
+ ops = [[:account_witness_vote, params]]
574
+
575
+ process(options.merge(ops: ops), &block)
576
+ end
577
+
578
+ # @param options [Hash] options
579
+ # @option options [String] :wif Active wif
580
+ # @option options [Hash] :params
581
+ # * :account (String)
582
+ # * :proxy (String)
583
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
584
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_account_witness_proxy
585
+ def self.account_witness_proxy(options, &block)
586
+ required_fields = %i(account proxy)
587
+ params = options[:params]
588
+ check_required_fields(params, *required_fields)
589
+
590
+ ops = [[:account_witness_proxy, params]]
591
+
592
+ process(options.merge(ops: ops), &block)
593
+ end
594
+
595
+ # Provides a generic way to add higher level protocols on top of witness
596
+ # consensus.
597
+ #
598
+ # @param options [Hash] options
599
+ # @option options [String] :wif Active wif
600
+ # @option options [Hash] :params
601
+ # * :required_auths (Array<String>)
602
+ # * :id (String)
603
+ # * :data (String)
604
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
605
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_custom
606
+ def self.custom(options, &block)
607
+ required_fields = %i(required_auths id data)
608
+ params = options[:params]
609
+ check_required_fields(params, *required_fields)
610
+
611
+ ops = [[:custom, params]]
612
+
613
+ process(options.merge(ops: ops), &block)
614
+ end
615
+
616
+ # The semmantics for this operation are the same as the {Broadcast#custom_json}
617
+ # operation, but with a binary payload.
618
+ #
619
+ # @param options [Hash] options
620
+ # @option options [String] :wif Posting wif
621
+ # @option options [Hash] :params
622
+ # * :id (String)
623
+ # * :data (String)
624
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
625
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_custom_binary
626
+ def self.custom_binary(options, &block)
627
+ required_fields = %i(id data)
628
+ params = options[:params]
629
+ check_required_fields(params, *required_fields)
630
+
631
+ ops = [[:custom_binary, params]]
632
+
633
+ process(options.merge(ops: ops), &block)
634
+ end
635
+
636
+ # Serves the same purpose as {Broadcast#custom} but also supports required
637
+ # posting authorities.
638
+ #
639
+ # @param options [Hash] options
640
+ # @option options [String] :wif Posting wif
641
+ # @option options [Hash] :params
642
+ # * :required_auths (Array<String>)
643
+ # * :required_posting_auths (Arrat<String>)
644
+ # * :id (String)
645
+ # * :json (String)
646
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
647
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_custom_json
648
+ def self.custom_json(options, &block)
649
+ required_fields = %i(id json)
650
+ params = options[:params]
651
+ check_required_fields(params, *required_fields)
652
+
653
+ params[:required_auths] ||= []
654
+ params[:required_posting_auths] ||= []
655
+ ops = [[:custom_json, params]]
656
+
657
+ process(options.merge(ops: ops), &block)
658
+ end
659
+
660
+ # Allows an account to setup a vesting withdraw but with the additional
661
+ # request for the funds to be transferred directly to another account’s
662
+ # balance rather than the withdrawing account.
663
+ #
664
+ # @param options [Hash] options
665
+ # @option options [String] :wif Active wif
666
+ # @option options [Hash] :params
667
+ # * :from_account (String)
668
+ # * :to_account (String)
669
+ # * :percent (Numeric)
670
+ # * :auto_vest (Boolean)
671
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
672
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_set_withdraw_vesting_route
673
+ def self.set_withdraw_vesting_route(options, &block)
674
+ required_fields = %i(from_account to_account percent auto_vest)
675
+ params = options[:params]
676
+ check_required_fields(params, *required_fields)
677
+
678
+ ops = [[:set_withdraw_vesting_route, params]]
679
+
680
+ process(options.merge(ops: ops), &block)
681
+ end
682
+
683
+ # All account recovery requests come from a listed recovery account.
684
+ #
685
+ # @param options [Hash] options
686
+ # @option options [String] :wif Active wif
687
+ # @option options [Hash] :params
688
+ # * :recovery_account (String)
689
+ # * :account_to_recover (String)
690
+ # * :new_owner_authority (Hash)
691
+ # * :extensions (Array) (optional)
692
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
693
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_request_account_recovery
694
+ def self.request_account_recovery(options, &block)
695
+ required_fields = %i(recovery_account account_to_recover new_owner_authority)
696
+ params = options[:params]
697
+ check_required_fields(params, *required_fields)
698
+
699
+ params[:extensions] ||= []
700
+ ops = [[:request_account_recovery, params]]
701
+
702
+ process(options.merge(ops: ops), &block)
703
+ end
704
+
705
+ # @param options [Hash] options
706
+ # @option options [String] :wif Active wif
707
+ # @option options [Hash] :params
708
+ # * :account_to_recover (String)
709
+ # * :new_owner_authority (Hash)
710
+ # * :recent_owner_authority (Hash)
711
+ # * :extensions (Array) (optional)
712
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
713
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_recover_account
714
+ def self.recover_account(options, &block)
715
+ required_fields = %i(account_to_recover new_owner_authority recent_owner_authority)
716
+ params = options[:params]
717
+ check_required_fields(params, *required_fields)
718
+
719
+ params[:extensions] ||= []
720
+ ops = [[:recover_account, params]]
721
+
722
+ process(options.merge(ops: ops), &block)
723
+ end
724
+
725
+ # Each account lists another account as their recovery account.
726
+ #
727
+ # @param options [Hash] options
728
+ # @option options [String] :wif Posting wif
729
+ # @option options [Hash] :params
730
+ # * :account_to_recover (String)
731
+ # * :new_recovery_account (String)
732
+ # * :extensions (Array) (optional)
733
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
734
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_change_recovery_account
735
+ def self.change_recovery_account(options, &block)
736
+ required_fields = %i(account_to_recover)
737
+ params = options[:params]
738
+ check_required_fields(params, *required_fields)
739
+
740
+ params[:new_recovery_account] ||= ''
741
+ params[:extensions] ||= []
742
+ ops = [[:change_recovery_account, params]]
743
+
744
+ process(options.merge(ops: ops), &block)
745
+ end
746
+
747
+ # The purpose of this operation is to enable someone to send money
748
+ # contingently to another individual.
749
+ #
750
+ # @param options [Hash] options
751
+ # @option options [String] :wif Active wif
752
+ # @option options [Hash] :params
753
+ # * :from (String)
754
+ # * :to (String)
755
+ # * :agent (String)
756
+ # * :escrow_id (String)
757
+ # * :sbd_amount (String)
758
+ # * :steem_amount (String)
759
+ # * :fee (String)
760
+ # * :ratification_deadline (String)
761
+ # * :escrow_expiration (String)
762
+ # * :json_meta (String)
763
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
764
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_escrow_transfer
765
+ def self.escrow_transfer(options, &block)
766
+ required_fields = %i(from to agent escrow_id fee ratification_deadline json_meta)
767
+ params = options[:params]
768
+ check_required_fields(params, *required_fields)
769
+
770
+ params[:sbd_amount] = Type::Amount.to_nia(params[:sbd_amount])
771
+ params[:steem_amount] = Type::Amount.to_nia(params[:steem_amount])
772
+ params[:fee] = Type::Amount.to_nia(params[:fee])
773
+
774
+ params[:ratification_deadline] = Time.parse(params[:ratification_deadline].to_s)
775
+ params[:ratification_deadline] = params[:ratification_deadline].strftime('%Y-%m-%dT%H:%M:%S')
776
+
777
+ if !!params[:escrow_expiration]
778
+ params[:escrow_expiration] = Time.parse(params[:escrow_expiration].to_s)
779
+ params[:escrow_expiration] = params[:escrow_expiration].strftime('%Y-%m-%dT%H:%M:%S')
780
+ end
781
+
782
+ ops = [[:escrow_transfer, params]]
783
+
784
+ process(options.merge(ops: ops), &block)
785
+ end
786
+
787
+ # If either the sender or receiver of an escrow payment has an issue, they
788
+ # can raise it for dispute.
789
+ #
790
+ # @param options [Hash] options
791
+ # @option options [String] :wif Active wif
792
+ # @option options [Hash] :params
793
+ # * :from (String)
794
+ # * :to (String)
795
+ # * :agent (String)
796
+ # * :who (String)
797
+ # * :escrow_id (String)
798
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
799
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_escrow_dispute
800
+ def self.escrow_dispute(options, &block)
801
+ required_fields = %i(from to agent who escrow_id)
802
+ params = options[:params]
803
+ check_required_fields(params, *required_fields)
804
+
805
+ ops = [[:escrow_dispute, params]]
806
+
807
+ process(options.merge(ops: ops), &block)
808
+ end
809
+
810
+ # This operation can be used by anyone associated with the escrow transfer
811
+ # to release funds if they have permission.
812
+ #
813
+ # @param options [Hash] options
814
+ # @option options [String] :wif Active wif
815
+ # @option options [Hash] :params
816
+ # * :from (String)
817
+ # * :to (String)
818
+ # * :agent (String)
819
+ # * :who (String)
820
+ # * :receiver (String)
821
+ # * :escrow_id (String)
822
+ # * :sbd_amount (String)
823
+ # * :steem_amount (String)
824
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
825
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_escrow_release
826
+ def self.escrow_release(options, &block)
827
+ required_fields = %i(from to agent who receiver escrow_id)
828
+ params = options[:params]
829
+ check_required_fields(params, *required_fields)
830
+
831
+ params[:sbd_amount] = Type::Amount.to_nia(params[:sbd_amount])
832
+ params[:steem_amount] = Type::Amount.to_nia(params[:steem_amount])
833
+
834
+ ops = [[:escrow_release, params]]
835
+
836
+ process(options.merge(ops: ops), &block)
837
+ end
838
+
839
+ # The agent and to accounts must approve an escrow transaction for it to be
840
+ # valid on the blockchain.
841
+ #
842
+ # @param options [Hash] options
843
+ # @option options [String] :wif Active wif
844
+ # @option options [Hash] :params
845
+ # * :from (String)
846
+ # * :to (String)
847
+ # * :agent (String)
848
+ # * :who (String)
849
+ # * :escrow_id (String)
850
+ # * :approve (String)
851
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
852
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_escrow_approve
853
+ def self.escrow_approve(options, &block)
854
+ required_fields = %i(from to agent who escrow_id approve)
855
+ params = options[:params]
856
+ check_required_fields(params, *required_fields)
857
+
858
+ ops = [[:escrow_approve, params]]
859
+
860
+ process(options.merge(ops: ops), &block)
861
+ end
862
+
863
+ # For time locked savings accounts.
864
+ #
865
+ # @param options [Hash] options
866
+ # @option options [String] :wif Active wif
867
+ # @option options [Hash] :params
868
+ # * :from (String)
869
+ # * :to (String)
870
+ # * :amount (String)
871
+ # * :memo (String) (optional)
872
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
873
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_transfer_to_savings
874
+ def self.transfer_to_savings(options, &block)
875
+ required_fields = %i(from to amount)
876
+ params = options[:params]
877
+ check_required_fields(params, *required_fields)
878
+
879
+ params[:memo] ||= ''
880
+ params[:amount] = Type::Amount.to_nia(params[:amount])
881
+
882
+ ops = [[:transfer_to_savings, params]]
883
+
884
+ process(options.merge(ops: ops), &block)
885
+ end
886
+
887
+ # @param options [Hash] options
888
+ # @option options [String] :wif Active wif
889
+ # @option options [Hash] :params
890
+ # * :from (String)
891
+ # * :request_id (String)
892
+ # * :to (String)
893
+ # * :amount (String)
894
+ # * :memo (String) (optional)
895
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
896
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_transfer_from_savings
897
+ def self.transfer_from_savings(options, &block)
898
+ required_fields = %i(from request_id to amount)
899
+ params = options[:params]
900
+ check_required_fields(params, *required_fields)
901
+
902
+ params[:memo] ||= ''
903
+ params[:amount] = Type::Amount.to_nia(params[:amount])
904
+
905
+ ops = [[:transfer_from_savings, params]]
906
+
907
+ process(options.merge(ops: ops), &block)
908
+ end
909
+
910
+ # @param options [Hash] options
911
+ # @option options [String] :wif Active wif
912
+ # @option options [Hash] :params
913
+ # * :from (String)
914
+ # * :request_id (String)
915
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
916
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_cancel_transfer_from_savings
917
+ def self.cancel_transfer_from_savings(options, &block)
918
+ required_fields = %i(from request_id)
919
+ params = options[:params]
920
+ check_required_fields(params, *required_fields)
921
+
922
+ ops = [[:cancel_transfer_from_savings, params]]
923
+
924
+ process(options.merge(ops: ops), &block)
925
+ end
926
+
927
+ # An account can chose to decline their voting rights after a 30 day delay.
928
+ # This includes voting on content and witnesses. **The voting rights cannot
929
+ # be acquired again once they have been declined.** This is only to
930
+ # formalize a smart contract between certain accounts and the community that
931
+ # currently only exists as a social contract.
932
+ #
933
+ # @param options [Hash] options
934
+ # @option options [String] :wif Owner wif
935
+ # @option options [Hash] :params
936
+ # * :account (String)
937
+ # * :decline (String)
938
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
939
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_decline_voting_rights
940
+ def self.decline_voting_rights(options, &block)
941
+ required_fields = %i(account decline)
942
+ params = options[:params]
943
+ check_required_fields(params, *required_fields)
944
+
945
+ ops = [[:decline_voting_rights, params]]
946
+
947
+ process(options.merge(ops: ops), &block)
948
+ end
949
+
950
+ # Delegate vesting shares from one account to the other.
951
+ #
952
+ # @param options [Hash] options
953
+ # @option options [String] :wif Active wif
954
+ # @option options [Hash] :params
955
+ # * :delegator (String)
956
+ # * :delegatee (String)
957
+ # * :vesting_shares (String)
958
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
959
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_delegate_vesting_shares
960
+ def self.delegate_vesting_shares(options, &block)
961
+ required_fields = %i(delegator delegatee vesting_shares)
962
+ params = options[:params]
963
+ check_required_fields(params, *required_fields)
964
+
965
+ params[:vesting_shares] = Type::Amount.to_nia(params[:vesting_shares])
966
+ ops = [[:delegate_vesting_shares, params]]
967
+
968
+ process(options.merge(ops: ops), &block)
969
+ end
970
+
971
+ # @param options [Hash] options
972
+ # @option options [String] :wif Active wif
973
+ # @option options [Hash] :params
974
+ # * :fee (String)
975
+ # * :delegation (String)
976
+ # * :creator (String)
977
+ # * :new_account_name (String)
978
+ # * :owner (String)
979
+ # * :active (String)
980
+ # * :posting (String)
981
+ # * :memo_key (String)
982
+ # * :json_metadata (String)
983
+ # * :extensions (Array)
984
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
985
+ # @see https://developers.steem.io/apidefinitions/broadcast-ops#broadcast_ops_account_create_with_delegation
986
+ def self.account_create_with_delegation(options, &block)
987
+ required_fields = %i(fee delegation creator new_account_name owner active posting memo_key json_metadata)
988
+ params = options[:params]
989
+ check_required_fields(params, *required_fields)
990
+
991
+ params[:fee] = Type::Amount.to_nia(params[:fee])
992
+ params[:delegation] = Type::Amount.to_nia(params[:delegation])
993
+ params[:extensions] ||= []
994
+
995
+ ops = [[:account_create_with_delegation, params]]
996
+
997
+ process(options.merge(ops: ops), &block)
998
+ end
999
+
1000
+ # @param options [Hash] options
1001
+ # @option options [Array<Array<Hash>] :ops Operations to process.
1002
+ # @option options [Boolean] :pretend Just validate, do not broadcast.
1003
+ def self.process(options, &block)
1004
+ ops = options[:ops]
1005
+ tx = TransactionBuilder.new(options)
1006
+ response = nil
1007
+
1008
+ loop do; begin
1009
+ tx.operations = ops
1010
+ trx = tx.transaction
1011
+
1012
+ response = if !!options[:pretend]
1013
+ database_api(options).verify_authority(trx: trx)
1014
+ else
1015
+ network_broadcast_api(options).broadcast_transaction_synchronous(trx: trx)
1016
+ end
1017
+
1018
+ break
1019
+ rescue => e
1020
+ if can_retry? e
1021
+ tx.expiration = nil
1022
+ redo
1023
+ end
1024
+
1025
+ raise e
1026
+ end; end
1027
+
1028
+ if !!block
1029
+ block.call response.result
1030
+ else
1031
+ return response.result
1032
+ end
1033
+ end
1034
+ private
1035
+ def self.database_api(options)
1036
+ options[:database_api] ||= Steem::DatabaseApi.new(options)
1037
+ end
1038
+
1039
+ def self.network_broadcast_api(options)
1040
+ options[:network_broadcast_api] ||= Steem::NetworkBroadcastApi.new(options)
1041
+ end
1042
+
1043
+ def self.check_required_fields(hash, *fields)
1044
+ fields.each do |field|
1045
+ value = hash[field]
1046
+
1047
+ raise Steem::ArgumentError, "#{field}: required" if value.nil?
1048
+
1049
+ case value
1050
+ when String, Array, Hash
1051
+ raise Steem::ArgumentError, "#{field}: required" if value.empty?
1052
+ end
1053
+ end
1054
+ end
1055
+ end
1056
+ end