stellar-base 0.23.0 → 0.26.0

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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +114 -1
  3. data/README.md +4 -7
  4. data/generated/stellar-base-generated.rb +29 -1
  5. data/generated/stellar/account_entry.rb +3 -13
  6. data/generated/stellar/account_entry/ext.rb +2 -16
  7. data/generated/stellar/account_entry_extension_v1.rb +32 -0
  8. data/generated/stellar/account_entry_extension_v1/ext.rb +28 -0
  9. data/generated/stellar/account_entry_extension_v2.rb +34 -0
  10. data/generated/stellar/{account_entry/ext/v1 → account_entry_extension_v2}/ext.rb +8 -12
  11. data/generated/stellar/account_merge_result_code.rb +3 -1
  12. data/generated/stellar/begin_sponsoring_future_reserves_op.rb +18 -0
  13. data/generated/stellar/begin_sponsoring_future_reserves_result.rb +25 -0
  14. data/generated/stellar/begin_sponsoring_future_reserves_result_code.rb +29 -0
  15. data/generated/stellar/claim_claimable_balance_op.rb +18 -0
  16. data/generated/stellar/claim_claimable_balance_result.rb +25 -0
  17. data/generated/stellar/claim_claimable_balance_result_code.rb +31 -0
  18. data/generated/stellar/claim_predicate.rb +43 -0
  19. data/generated/stellar/claim_predicate_type.rb +30 -0
  20. data/generated/stellar/claimable_balance_entry.rb +44 -0
  21. data/generated/stellar/claimable_balance_entry/ext.rb +24 -0
  22. data/generated/stellar/claimable_balance_id.rb +23 -0
  23. data/generated/stellar/claimable_balance_id_type.rb +20 -0
  24. data/generated/stellar/claimant.rb +31 -0
  25. data/generated/stellar/claimant/v0.rb +22 -0
  26. data/generated/stellar/claimant_type.rb +20 -0
  27. data/generated/stellar/create_claimable_balance_op.rb +22 -0
  28. data/generated/stellar/create_claimable_balance_result.rb +27 -0
  29. data/generated/stellar/create_claimable_balance_result_code.rb +30 -0
  30. data/generated/stellar/end_sponsoring_future_reserves_result.rb +25 -0
  31. data/generated/stellar/end_sponsoring_future_reserves_result_code.rb +25 -0
  32. data/generated/stellar/envelope_type.rb +3 -1
  33. data/generated/stellar/inner_transaction_result.rb +2 -1
  34. data/generated/stellar/inner_transaction_result/result.rb +3 -1
  35. data/generated/stellar/ledger_entry.rb +4 -0
  36. data/generated/stellar/ledger_entry/data.rb +12 -8
  37. data/generated/stellar/ledger_entry/ext.rb +4 -0
  38. data/generated/stellar/ledger_entry_extension_v1.rb +30 -0
  39. data/generated/stellar/ledger_entry_extension_v1/ext.rb +24 -0
  40. data/generated/stellar/ledger_entry_type.rb +7 -5
  41. data/generated/stellar/ledger_key.rb +17 -8
  42. data/generated/stellar/ledger_key/claimable_balance.rb +20 -0
  43. data/generated/stellar/operation.rb +10 -0
  44. data/generated/stellar/operation/body.rb +45 -26
  45. data/generated/stellar/operation_id.rb +32 -0
  46. data/generated/stellar/operation_id/id.rb +24 -0
  47. data/generated/stellar/operation_result.rb +10 -0
  48. data/generated/stellar/operation_result/tr.rb +48 -28
  49. data/generated/stellar/operation_result_code.rb +3 -1
  50. data/generated/stellar/operation_type.rb +25 -15
  51. data/generated/stellar/path_payment_strict_receive_result.rb +2 -1
  52. data/generated/stellar/revoke_sponsorship_op.rb +36 -0
  53. data/generated/stellar/revoke_sponsorship_op/signer.rb +22 -0
  54. data/generated/stellar/revoke_sponsorship_result.rb +25 -0
  55. data/generated/stellar/revoke_sponsorship_result_code.rb +31 -0
  56. data/generated/stellar/revoke_sponsorship_type.rb +22 -0
  57. data/generated/stellar/transaction_result_code.rb +4 -2
  58. data/lib/stellar-base.rb +18 -5
  59. data/lib/stellar/account_flags.rb +1 -1
  60. data/lib/stellar/asset.rb +10 -0
  61. data/lib/stellar/{version.rb → base/version.rb} +1 -1
  62. data/lib/stellar/claim_predicate.rb +198 -0
  63. data/lib/stellar/compat.rb +2 -15
  64. data/lib/stellar/concerns/transaction.rb +2 -3
  65. data/lib/stellar/dsl.rb +89 -0
  66. data/lib/stellar/ext/xdr.rb +50 -0
  67. data/lib/stellar/key_pair.rb +60 -53
  68. data/lib/stellar/ledger_key.rb +32 -0
  69. data/lib/stellar/muxed_account.rb +16 -0
  70. data/lib/stellar/networks.rb +12 -12
  71. data/lib/stellar/operation.rb +59 -1
  72. data/lib/stellar/price.rb +11 -2
  73. data/lib/stellar/transaction.rb +17 -167
  74. data/lib/stellar/transaction_builder.rb +35 -18
  75. data/lib/stellar/transaction_envelope.rb +7 -43
  76. data/lib/stellar/transaction_v0.rb +5 -1
  77. data/lib/stellar/util/strkey.rb +6 -6
  78. metadata +162 -30
  79. data/generated/stellar/account_entry/ext/v1.rb +0 -34
  80. data/lib/stellar/util/continued_fraction.rb +0 -96
@@ -0,0 +1,32 @@
1
+ require "stellar/convert"
2
+ require "stellar/dsl"
3
+
4
+ module Stellar
5
+ class LedgerKey
6
+ class << self
7
+ include Stellar::DSL
8
+
9
+ def switch_for_arm(name)
10
+ (@switch_by_arm ||= switches.invert).fetch(name)
11
+ end
12
+
13
+ def from(account_id:, **options)
14
+ field, value = options.first
15
+ case field
16
+ when nil
17
+ account(account_id: KeyPair(account_id).account_id)
18
+ when :balance_id
19
+ claimable_balance(balance_id: ClaimableBalanceID.v0(Stellar::Convert.from_hex(value.to_s)))
20
+ when :offer_id
21
+ offer(seller_id: account_id, offer_id: Integer(value))
22
+ when :data_name
23
+ data(account_id: account_id, data_name: value.to_s)
24
+ when :asset
25
+ trust_line(account_id: account_id, asset: Asset(value))
26
+ else
27
+ raise ArgumentError, "unknown option #{field} (not in :asset, :offer_id, :data_name, :balance_id)"
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module Stellar
2
+ class MuxedAccount
3
+ def to_keypair
4
+ case arm
5
+ when :ed25519 then KeyPair.from_public_key(value)
6
+ when :med25519 then KeyPair.from_public_key(value.ed25519)
7
+ else
8
+ raise "impossible"
9
+ end
10
+ end
11
+
12
+ def address
13
+ to_keypair.address
14
+ end
15
+ end
16
+ end
@@ -12,18 +12,18 @@ module Stellar
12
12
  # methods of specifying a network if you need two threads in the same process to communicate with
13
13
  # different networks
14
14
  #
15
- # @see Stellar.default_network
16
15
  # @see Stellar.on_network
17
- def self.default_network=(passphrase)
18
- @default_network = passphrase
19
- end
16
+ mattr_accessor :default_network, default: Networks::TESTNET
17
+
18
+ # Stellar network passphrase selected for current thread
19
+ #
20
+ # @see Stellar.current_network
21
+ # @see Stellar.on_network
22
+ thread_mattr_accessor :network
20
23
 
21
- # Returns the passphrase for the currently-configured network, as set by Stellar.default_network
22
- # or Stellar.on_network
24
+ # Returns the passphrase for the network currently active per-thread with a fallback to `Stellar.default_network`
23
25
  def self.current_network
24
- Thread.current["stellar_network_passphrase"] ||
25
- @default_network ||
26
- Stellar::Networks::TESTNET
26
+ network.presence || default_network
27
27
  end
28
28
 
29
29
  # Returns the id for the currently configured network, suitable for use in generating
@@ -34,10 +34,10 @@ module Stellar
34
34
 
35
35
  # Executes the provided block in the context of the provided network.
36
36
  def self.on_network(passphrase, &block)
37
- old = Thread.current["stellar_network_passphrase"]
38
- Thread.current["stellar_network_passphrase"] = passphrase
37
+ old = network
38
+ self.network = passphrase
39
39
  block.call
40
40
  ensure
41
- Thread.current["stellar_network_passphrase"] = old
41
+ self.network = old
42
42
  end
43
43
  end
@@ -5,6 +5,7 @@ module Stellar
5
5
  MAX_INT64 = 2**63 - 1
6
6
 
7
7
  class << self
8
+ include Stellar::DSL
8
9
  #
9
10
  # Construct a new Stellar::Operation from the provided
10
11
  # source account and body
@@ -168,7 +169,6 @@ module Stellar
168
169
  }))
169
170
  end
170
171
 
171
- #
172
172
  # Helper method to create a valid ChangeTrustOp, wrapped
173
173
  # in the necessary XDR structs to be included within a
174
174
  # transactions `operations` array.
@@ -200,6 +200,64 @@ module Stellar
200
200
  }))
201
201
  end
202
202
 
203
+ # Helper method to create a valid CreateClaimableBalanceOp, ready to be used
204
+ # within a transactions `operations` array.
205
+ #
206
+ # @see Stellar::DSL::Claimant
207
+ # @see https://github.com/astroband/ruby-stellar-sdk/tree/master/base/examples/claimable_balances.rb
208
+ #
209
+ # @param asset [Asset] the asset to transfer to a claimable balance
210
+ # @param amount [Fixnum] the amount of `asset` to put into a claimable balance
211
+ # @param claimants [Array<Claimant>] accounts authorized to claim the balance in the future
212
+ #
213
+ # @return [Operation] the built operation
214
+ def create_claimable_balance(asset:, amount:, claimants:, **attributes)
215
+ op = CreateClaimableBalanceOp.new(asset: asset, amount: amount, claimants: claimants)
216
+
217
+ make(attributes.merge(body: [:create_claimable_balance, op]))
218
+ end
219
+
220
+ # Helper method to create a valid CreateClaimableBalanceOp, ready to be used
221
+ # within a transactions `operations` array.
222
+ #
223
+ # @see Stellar::DSL::Claimant
224
+ # @see https://github.com/astroband/ruby-stellar-sdk/tree/master/base/examples/claimable_balances.rb
225
+ #
226
+ # @param balance_id [ClaimableBalanceID] unique ID of claimable balance
227
+ #
228
+ # @return [Operation] the built operation, containing a Stellar::ChangeTrustOp body
229
+ def claim_claimable_balance(balance_id:, **attributes)
230
+ op = ClaimClaimableBalanceOp.new(balance_id: balance_id)
231
+
232
+ make(attributes.merge(body: [:claim_claimable_balance, op]))
233
+ end
234
+
235
+ def begin_sponsoring_future_reserves(sponsored:, **attributes)
236
+ op = BeginSponsoringFutureReservesOp.new(
237
+ sponsored_id: KeyPair(sponsored).account_id
238
+ )
239
+
240
+ make(attributes.merge(body: [:begin_sponsoring_future_reserves, op]))
241
+ end
242
+
243
+ def end_sponsoring_future_reserves(**attributes)
244
+ make(attributes.merge(body: [:end_sponsoring_future_reserves]))
245
+ end
246
+
247
+ # @param sponsored [#to_keypair] owner of sponsored entry
248
+ def revoke_sponsorship(sponsored:, **attributes)
249
+ key_fields = attributes.slice(:offer_id, :data_name, :balance_id, :asset, :signer)
250
+ raise ArgumentError, "conflicting attributes: #{key_fields.keys.join(", ")}" if key_fields.size > 1
251
+ account_id = KeyPair(sponsored).account_id
252
+ key, value = key_fields.first
253
+ op = if key == :signer
254
+ RevokeSponsorshipOp.signer(account_id: account_id, signer_key: SignerKey(value))
255
+ else
256
+ RevokeSponsorshipOp.ledger_key(LedgerKey.from(account_id: account_id, **key_fields))
257
+ end
258
+ make(attributes.merge(body: [:revoke_sponsorship, op]))
259
+ end
260
+
203
261
  def manage_sell_offer(attributes = {})
204
262
  buying = attributes[:buying]
205
263
  if buying.is_a?(Array)
data/lib/stellar/price.rb CHANGED
@@ -4,7 +4,12 @@ module Stellar
4
4
  MAX_PRECISION = (2**31) - 1
5
5
 
6
6
  def self.from_f(number)
7
- best_r = Util::ContinuedFraction.best_r(number, MAX_PRECISION)
7
+ best_r = number.to_r.rationalize(1.0e-7)
8
+
9
+ if best_r.numerator > MAX_PRECISION || best_r.denominator > MAX_PRECISION
10
+ raise ArgumentError("Couldn't find price approximation")
11
+ end
12
+
8
13
  new({
9
14
  n: best_r.numerator,
10
15
  d: best_r.denominator
@@ -15,8 +20,12 @@ module Stellar
15
20
  self.class.new(n: d, d: n)
16
21
  end
17
22
 
23
+ def to_d
24
+ n.to_d / d
25
+ end
26
+
18
27
  def to_f
19
- n / d.to_f
28
+ n.to_f / d
20
29
  end
21
30
 
22
31
  def to_s
@@ -2,172 +2,22 @@ module Stellar
2
2
  class Transaction
3
3
  include Stellar::Concerns::Transaction
4
4
 
5
- class << self
6
- #
7
- # @see Stellar::Operation.payment
8
- def payment(attributes = {})
9
- make :payment, attributes
10
- end
11
-
12
- #
13
- # @see Stellar::Operation.path_payment
14
- def path_payment(attributes = {})
15
- make :path_payment, attributes
16
- end
17
-
18
- #
19
- # @see Stellar::Operation.path_payment_strict_receive
20
- def path_payment_strict_receive(attributes = {})
21
- make :path_payment_strict_receive, attributes
22
- end
23
-
24
- #
25
- # @see Stellar::Operation.path_payment_strict_send
26
- def path_payment_strict_send(attributes = {})
27
- make :path_payment_strict_send, attributes
28
- end
29
-
30
- #
31
- # @see Stellar::Operation.create_account
32
- def create_account(attributes = {})
33
- make :create_account, attributes
34
- end
35
-
36
- #
37
- # @see Stellar::Operation.change_trust
38
- def change_trust(attributes = {})
39
- make :change_trust, attributes
40
- end
41
-
42
- #
43
- # @see Stellar::Operation.manage_sell_offer
44
- def manage_sell_offer(attributes = {})
45
- make :manage_sell_offer, attributes
46
- end
47
-
48
- #
49
- # @see Stellar::Operation.manage_buy_offer
50
- def manage_buy_offer(attributes = {})
51
- make :manage_buy_offer, attributes
52
- end
53
-
54
- #
55
- # @see Stellar::Operation.create_passive_sell_offer
56
- def create_passive_sell_offer(attributes = {})
57
- make :create_passive_sell_offer, attributes
58
- end
59
-
60
- #
61
- # @see Stellar::Operation.set_options
62
- def set_options(attributes = {})
63
- make :set_options, attributes
64
- end
65
-
66
- #
67
- # @see Stellar::Operation.allow_trust
68
- def allow_trust(attributes = {})
69
- make :allow_trust, attributes
70
- end
71
-
72
- #
73
- # @see Stellar::Operation.account_merge
74
- def account_merge(attributes = {})
75
- make :account_merge, attributes
76
- end
77
-
78
- #
79
- # @see Stellar::Operation.inflation
80
- def inflation(attributes = {})
81
- make :inflation, attributes
82
- end
83
-
84
- #
85
- # @see Stellar::Operation.manage_data
86
- def manage_data(attributes = {})
87
- make :manage_data, attributes
88
- end
89
-
90
- #
91
- # @see Stellar::Operation.manage_data
92
- def bump_sequence(attributes = {})
93
- make :bump_sequence, attributes
94
- end
95
-
96
- #
97
- # DEPRECATED
98
- #
99
- # All methods calling make() have been deprecated in favor of Stellar::TransactionBuilder.
100
- # These functions only create single-operation transactions and essentially duplicate the
101
- # methods provided by Stellar::Operation. Stellar::TransactionBuilder enables the construction
102
- # of multi-operation transactions and mirrors the functionality provided by the Python and
103
- # JavaScript SDKs.
104
- #
105
- # Helper method to create a transaction with a single
106
- # operation of the provided type. See class methods
107
- # on Stellar::Operation for available values for
108
- # operation_type.
109
- #
110
- # @see Stellar::Operation
111
- #
112
- # @param operation_type [Symbol] the operation to use
113
- # @param attributes={} [Hash] attributes to use for both the transaction and the operation
114
- #
115
- # @return [Stellar::Transaction] the resulting transaction
116
- def make(operation_type, attributes = {})
117
- Stellar::Deprecation.warn(
118
- "Transaction.#{operation_type} is deprecated. Use Stellar::TransactionBuilder instead."
119
- )
120
- for_account(attributes).tap do |result|
121
- result.operations << Operation.send(operation_type, attributes)
122
- end
123
- end
124
-
125
- #
126
- # Helper method to create the skeleton of a transaction.
127
- # The resulting transaction will have its source account,
128
- # sequence, fee, min ledger and max ledger set.
129
- #
130
- #
131
- # @param attributes={} [type] [description]
132
- #
133
- # @return [Stellar::Transaction] the resulting skeleton
134
- def for_account(attributes = {})
135
- account = attributes[:account]
136
- sequence = attributes[:sequence]
137
- fee = attributes[:fee]
138
-
139
- raise ArgumentError, "Bad :account" unless account.is_a?(KeyPair)
140
- raise ArgumentError, "Bad :sequence #{sequence}" unless sequence.is_a?(Integer)
141
- raise ArgumentError, "Bad :fee #{sequence}" if fee.present? && !fee.is_a?(Integer)
142
-
143
- new.tap do |result|
144
- result.seq_num = sequence
145
- result.fee = fee
146
- result.memo = make_memo(attributes[:memo])
147
- result.source_account = account.muxed_account
148
- result.apply_defaults
149
- end
150
- end
151
-
152
- private
153
-
154
- def make_memo(memo)
155
- case memo
156
- when Stellar::Memo
157
- memo
158
- when nil
159
- nil
160
- when Integer
161
- Memo.new(:memo_id, memo)
162
- when String
163
- Memo.new(:memo_text, memo)
164
- when Array
165
- t, val = *memo
166
- Memo.new(:"memo_#{t}", val)
167
- else
168
- raise ArgumentError, "Bad :memo"
169
- end
170
- end
5
+ def to_v0
6
+ ed25519 = if source_account.switch == Stellar::CryptoKeyType.key_type_ed25519
7
+ source_account.ed25519!
8
+ else
9
+ source_account.med25519!.ed25519
10
+ end
11
+
12
+ TransactionV0.new(
13
+ source_account_ed25519: ed25519,
14
+ seq_num: seq_num,
15
+ operations: operations,
16
+ fee: fee,
17
+ memo: memo,
18
+ time_bounds: time_bounds,
19
+ ext: ext
20
+ )
171
21
  end
172
22
 
173
23
  def signature_base
@@ -179,7 +29,7 @@ module Stellar
179
29
  end
180
30
 
181
31
  def to_envelope(*key_pairs)
182
- signatures = (key_pairs || []).map(&method(:sign_decorated))
32
+ signatures = key_pairs.map(&method(:sign_decorated))
183
33
 
184
34
  TransactionEnvelope.v1(signatures: signatures, tx: self)
185
35
  end
@@ -2,13 +2,34 @@ module Stellar
2
2
  class TransactionBuilder
3
3
  attr_reader :source_account, :sequence_number, :base_fee, :time_bounds, :memo, :operations
4
4
 
5
+ class << self
6
+ # This enable user to call shortcut methods, like
7
+ # TransactionBuilder.payment(...),
8
+ # TransactionBuilder.manage_data(...) and etc.
9
+ # It reduces the boilerplate, when you just need to
10
+ # shoot a single operation in transaction
11
+ def method_missing(method_name, *args, **kwargs)
12
+ unless Stellar::Operation.respond_to?(method_name)
13
+ return super
14
+ end
15
+
16
+ op = Stellar::Operation.send(method_name, **kwargs)
17
+
18
+ new(**kwargs).add_operation(op).build
19
+ end
20
+
21
+ def respond_to_missing?(method_name, include_private = false)
22
+ Stellar::Operation.respond_to?(method_name) || super
23
+ end
24
+ end
25
+
5
26
  def initialize(
6
27
  source_account:,
7
28
  sequence_number:,
8
29
  base_fee: 100,
9
30
  time_bounds: nil,
10
31
  memo: nil,
11
- v1: false
32
+ **_ # ignore any additional parameters without errors
12
33
  )
13
34
  raise ArgumentError, "Bad :source_account" unless source_account.is_a?(Stellar::KeyPair)
14
35
  raise ArgumentError, "Bad :sequence_number" unless sequence_number.is_a?(Integer) && sequence_number >= 0
@@ -19,9 +40,13 @@ module Stellar
19
40
  @sequence_number = sequence_number
20
41
  @base_fee = base_fee
21
42
  @time_bounds = time_bounds
43
+
44
+ if time_bounds.nil?
45
+ set_timeout(0)
46
+ end
47
+
22
48
  @memo = make_memo(memo)
23
49
  @operations = []
24
- @v1 = v1
25
50
  end
26
51
 
27
52
  def build
@@ -34,6 +59,7 @@ module Stellar
34
59
  end
35
60
 
36
61
  attrs = {
62
+ source_account: @source_account.muxed_account,
37
63
  fee: @base_fee * @operations.length,
38
64
  seq_num: @sequence_number,
39
65
  time_bounds: @time_bounds,
@@ -42,21 +68,16 @@ module Stellar
42
68
  ext: Stellar::Transaction::Ext.new(0)
43
69
  }
44
70
 
45
- tx = if @v1
46
- attrs[:source_account] = @source_account.muxed_account
47
- Stellar::Transaction.new(attrs)
48
- else
49
- attrs[:source_account_ed25519] = @source_account.raw_public_key
50
- Stellar::TransactionV0.new(attrs)
51
- end
52
-
53
71
  @sequence_number += 1
54
- tx
72
+
73
+ Stellar::Transaction.new(attrs)
55
74
  end
56
75
 
57
76
  def build_fee_bump(inner_txe:)
58
- if inner_txe.switch != Stellar::EnvelopeType.envelope_type_tx
59
- raise "Invalid inner transaction type, it should be a `envelope_type_tx` but received a #{inner_tx.to_envelope.switch}."
77
+ if inner_txe.switch == Stellar::EnvelopeType.envelope_type_tx_v0
78
+ inner_txe = Stellar::TransactionEnvelope.v1(tx: inner_txe.tx.to_v1, signatures: inner_txe.signatures)
79
+ elsif inner_txe.switch != Stellar::EnvelopeType.envelope_type_tx
80
+ raise ArgumentError, "Invalid inner transaction type #{inner_txe.switch}"
60
81
  end
61
82
 
62
83
  inner_tx = inner_txe.tx
@@ -108,11 +129,7 @@ module Stellar
108
129
  @time_bounds = Stellar::TimeBounds.new(min_time: 0, max_time: nil)
109
130
  end
110
131
 
111
- @time_bounds.max_time = if timeout == 0
112
- timeout
113
- else
114
- Time.now.to_i + timeout
115
- end
132
+ @time_bounds.max_time = timeout == 0 ? timeout : Time.now.to_i + timeout
116
133
 
117
134
  self
118
135
  end