stellar-base 0.26.0 → 0.30.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -32
  3. data/README.md +3 -3
  4. data/generated/stellar/account_flags.rb +9 -4
  5. data/generated/stellar/account_merge_result.rb +1 -1
  6. data/generated/stellar/allow_trust_op.rb +3 -18
  7. data/generated/stellar/allow_trust_result_code.rb +4 -1
  8. data/generated/stellar/alpha_num12.rb +20 -0
  9. data/generated/stellar/alpha_num4.rb +20 -0
  10. data/generated/stellar/asset.rb +2 -15
  11. data/generated/stellar/asset_code.rb +30 -0
  12. data/generated/stellar/asset_type.rb +3 -1
  13. data/generated/stellar/begin_sponsoring_future_reserves_result.rb +2 -1
  14. data/generated/stellar/change_trust_asset.rb +39 -0
  15. data/generated/stellar/change_trust_op.rb +2 -2
  16. data/generated/stellar/change_trust_result_code.rb +13 -7
  17. data/generated/stellar/claim_atom.rb +31 -0
  18. data/generated/stellar/claim_atom_type.rb +24 -0
  19. data/generated/stellar/claim_liquidity_atom.rb +30 -0
  20. data/generated/stellar/claim_offer_atom_v0.rb +33 -0
  21. data/generated/stellar/claimable_balance_entry/ext.rb +4 -0
  22. data/generated/stellar/claimable_balance_entry.rb +2 -0
  23. data/generated/stellar/{asset/alpha_num12.rb → claimable_balance_entry_extension_v1/ext.rb} +9 -7
  24. data/generated/stellar/{operation_id.rb → claimable_balance_entry_extension_v1.rb} +12 -14
  25. data/generated/stellar/claimable_balance_flags.rb +22 -0
  26. data/generated/stellar/clawback_claimable_balance_op.rb +18 -0
  27. data/generated/stellar/clawback_claimable_balance_result.rb +26 -0
  28. data/generated/stellar/clawback_claimable_balance_result_code.rb +29 -0
  29. data/generated/stellar/clawback_op.rb +22 -0
  30. data/generated/stellar/clawback_result.rb +25 -0
  31. data/generated/stellar/clawback_result_code.rb +31 -0
  32. data/generated/stellar/create_passive_sell_offer_op.rb +1 -1
  33. data/generated/stellar/end_sponsoring_future_reserves_result.rb +2 -1
  34. data/generated/stellar/envelope_type.rb +10 -8
  35. data/generated/stellar/{operation_id/id.rb → hash_id_preimage/operation_id.rb} +4 -4
  36. data/generated/stellar/hash_id_preimage/revoke_id.rb +28 -0
  37. data/generated/stellar/hash_id_preimage.rb +44 -0
  38. data/generated/stellar/ledger_entry/data.rb +4 -0
  39. data/generated/stellar/ledger_entry.rb +2 -0
  40. data/generated/stellar/ledger_entry_type.rb +3 -1
  41. data/generated/stellar/ledger_header/ext.rb +4 -0
  42. data/generated/stellar/ledger_header.rb +2 -0
  43. data/generated/stellar/ledger_header_extension_v1/ext.rb +24 -0
  44. data/generated/stellar/ledger_header_extension_v1.rb +30 -0
  45. data/generated/stellar/ledger_header_flags.rb +24 -0
  46. data/generated/stellar/{asset/alpha_num4.rb → ledger_key/liquidity_pool.rb} +4 -6
  47. data/generated/stellar/ledger_key/trust_line.rb +2 -2
  48. data/generated/stellar/ledger_key.rb +10 -1
  49. data/generated/stellar/ledger_upgrade.rb +4 -0
  50. data/generated/stellar/ledger_upgrade_type.rb +3 -1
  51. data/generated/stellar/liquidity_pool_constant_product_parameters.rb +22 -0
  52. data/generated/stellar/liquidity_pool_deposit_op.rb +26 -0
  53. data/generated/stellar/liquidity_pool_deposit_result.rb +26 -0
  54. data/generated/stellar/liquidity_pool_deposit_result_code.rb +41 -0
  55. data/generated/stellar/liquidity_pool_entry/body/constant_product.rb +31 -0
  56. data/generated/stellar/liquidity_pool_entry/body.rb +37 -0
  57. data/generated/stellar/liquidity_pool_entry.rb +38 -0
  58. data/generated/stellar/liquidity_pool_parameters.rb +23 -0
  59. data/generated/stellar/liquidity_pool_type.rb +20 -0
  60. data/generated/stellar/liquidity_pool_withdraw_op.rb +24 -0
  61. data/generated/stellar/liquidity_pool_withdraw_result.rb +26 -0
  62. data/generated/stellar/liquidity_pool_withdraw_result_code.rb +36 -0
  63. data/generated/stellar/manage_offer_success_result.rb +2 -2
  64. data/generated/stellar/operation/body.rb +20 -0
  65. data/generated/stellar/operation.rb +10 -0
  66. data/generated/stellar/operation_result/tr.rb +20 -0
  67. data/generated/stellar/operation_result.rb +10 -0
  68. data/generated/stellar/operation_type.rb +11 -1
  69. data/generated/stellar/path_payment_strict_receive_result/success.rb +2 -2
  70. data/generated/stellar/path_payment_strict_receive_result.rb +1 -1
  71. data/generated/stellar/path_payment_strict_send_result/success.rb +2 -2
  72. data/generated/stellar/path_payment_strict_send_result.rb +1 -1
  73. data/generated/stellar/payment_result_code.rb +1 -1
  74. data/generated/stellar/revoke_sponsorship_op.rb +1 -2
  75. data/generated/stellar/revoke_sponsorship_result_code.rb +3 -1
  76. data/generated/stellar/scp_quorum_set.rb +2 -2
  77. data/generated/stellar/set_options_result_code.rb +14 -11
  78. data/generated/stellar/set_trust_line_flags_op.rb +25 -0
  79. data/generated/stellar/set_trust_line_flags_result.rb +25 -0
  80. data/generated/stellar/set_trust_line_flags_result_code.rb +34 -0
  81. data/generated/stellar/transaction_result_code.rb +1 -1
  82. data/generated/stellar/trust_line_asset.rb +39 -0
  83. data/generated/stellar/trust_line_entry/ext/v1/ext.rb +4 -0
  84. data/generated/stellar/trust_line_entry/ext/v1.rb +2 -0
  85. data/generated/stellar/trust_line_entry/ext.rb +2 -0
  86. data/generated/stellar/trust_line_entry.rb +7 -5
  87. data/generated/stellar/trust_line_entry_extension_v2/ext.rb +24 -0
  88. data/generated/stellar/trust_line_entry_extension_v2.rb +30 -0
  89. data/generated/stellar/trust_line_flags.rb +5 -1
  90. data/generated/stellar-base-generated.rb +40 -1
  91. data/lib/stellar/account.rb +59 -0
  92. data/lib/stellar/account_flags.rb +1 -1
  93. data/lib/stellar/amount.rb +36 -0
  94. data/lib/stellar/asset.rb +8 -0
  95. data/lib/stellar/compat.rb +6 -3
  96. data/lib/stellar/concerns/transaction.rb +4 -2
  97. data/lib/stellar/dsl.rb +26 -0
  98. data/lib/stellar/ledger_key.rb +5 -3
  99. data/lib/stellar/liquidity_pool/base_pool.rb +47 -0
  100. data/lib/stellar/liquidity_pool/constant_product_pool.rb +15 -0
  101. data/lib/stellar/liquidity_pool.rb +12 -0
  102. data/lib/stellar/operation.rb +357 -386
  103. data/lib/stellar/price.rb +13 -7
  104. data/lib/stellar/transaction_builder.rb +27 -11
  105. data/lib/stellar/trust_line_flags.rb +53 -0
  106. data/lib/stellar/util/strkey.rb +15 -7
  107. data/lib/stellar/version.rb +3 -0
  108. data/lib/stellar-base.rb +5 -2
  109. metadata +61 -16
  110. data/generated/stellar/allow_trust_op/asset.rb +0 -33
  111. data/lib/stellar/base/version.rb +0 -5
@@ -3,6 +3,11 @@ require "bigdecimal"
3
3
  module Stellar
4
4
  class Operation
5
5
  MAX_INT64 = 2**63 - 1
6
+ TRUST_LINE_FLAGS_MAPPING = {
7
+ full: Stellar::TrustLineFlags.authorized_flag,
8
+ maintain_liabilities: Stellar::TrustLineFlags.authorized_to_maintain_liabilities_flag,
9
+ clawback_enabled: Stellar::TrustLineFlags.trustline_clawback_enabled_flag
10
+ }.freeze
6
11
 
7
12
  class << self
8
13
  include Stellar::DSL
@@ -10,211 +15,194 @@ module Stellar
10
15
  # Construct a new Stellar::Operation from the provided
11
16
  # source account and body
12
17
  #
13
- # @param [Hash] attributes the attributes to create the operation with
14
- # @option attributes [Stellar::KeyPair] :source_account
15
- # @option attributes [Stellar::Operation::Body] :body
18
+ # @param source_account [KeyPair, nil] the source account for the operation
19
+ # @param [(Symbol, XDR::Struct)] body a tuple containing operation type and operation object
16
20
  #
17
21
  # @return [Stellar::Operation] the built operation
18
- def make(attributes = {})
19
- source_account = attributes[:source_account]
20
- body = Stellar::Operation::Body.new(*attributes[:body])
22
+ def make(body:, source_account: nil)
23
+ raise ArgumentError, "Bad :source_account" if source_account && !source_account.is_a?(Stellar::KeyPair)
21
24
 
22
- op = Stellar::Operation.new(body: body)
25
+ body = Stellar::Operation::Body.new(*body)
23
26
 
24
- if source_account
25
- raise ArgumentError, "Bad :source_account" unless source_account.is_a?(Stellar::KeyPair)
26
- op.source_account = source_account.muxed_account
27
- end
28
-
29
- op
27
+ Stellar::Operation.new(
28
+ source_account: source_account&.muxed_account,
29
+ body: body
30
+ )
30
31
  end
31
32
 
33
+ # Create Account operation builder
32
34
  #
33
- # Helper method to create a valid PaymentOp, wrapped
34
- # in the necessary XDR structs to be included within a
35
- # transactions `operations` array.
35
+ # @param source_account [KeyPair, nil] the source account for the operation
36
+ # @param destination [KeyPair] the account to create
37
+ # @param starting_balance [String, Numeric] the amount to deposit to the newly created account
36
38
  #
37
- # @see Stellar::Asset
38
- #
39
- # @param [Hash] attributes the attributes to create the operation with
40
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
41
- # @option attributes [Array] :amount the amount to pay
42
- # @return [Stellar::Operation] the built operation, containing a
43
- # Stellar::PaymentOp body
44
- def payment(attributes = {})
45
- destination = attributes[:destination]
46
- asset, amount = get_asset_amount(attributes[:amount])
47
-
48
- raise ArgumentError unless destination.is_a?(KeyPair)
49
-
50
- op = PaymentOp.new
51
- op.asset = asset
52
- op.amount = amount
53
- op.destination = destination.muxed_account
39
+ # @return [Stellar::Operation] the built operation
40
+ def create_account(destination:, starting_balance:, source_account: nil)
41
+ op = CreateAccountOp.new(
42
+ destination: KeyPair(destination).account_id,
43
+ starting_balance: interpret_amount(starting_balance)
44
+ )
54
45
 
55
- make(attributes.merge({
56
- body: [:payment, op]
57
- }))
46
+ make(source_account: source_account, body: [:create_account, op])
58
47
  end
59
48
 
49
+ # Account Merge operation builder
60
50
  #
61
- # Helper method to create a valid PathPaymentStrictReceiveOp, wrapped
62
- # in the necessary XDR structs to be included within a
63
- # transactions `operations` array.
64
- #
65
- # @deprecated Please use Operation.path_payment_strict_receive
66
- #
67
- # @see Stellar::Asset
51
+ # @param [Stellar::KeyPair, nil] source_account the source account for the operation
52
+ # @param [Stellar::KeyPair] destination the account to merge into
68
53
  #
69
- # @param [Hash] attributes the attributes to create the operation with
70
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
71
- # @option attributes [Array] :amount the destination asset and the amount to pay
72
- # @option attributes [Array] :with the source asset and maximum allowed source amount to pay with
73
- # @option attributes [Array<Stellar::Asset>] :path the payment path to use
74
- #
75
- # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
76
- #
77
- def path_payment(attributes = {})
78
- path_payment_strict_receive(attributes)
54
+ # @return [Stellar::Operation] the built operation
55
+ def account_merge(destination:, source_account: nil)
56
+ raise ArgumentError, "Bad destination" unless destination.is_a?(KeyPair)
57
+
58
+ make(source_account: source_account, body: [:account_merge, destination.muxed_account])
79
59
  end
80
60
 
61
+ # Set Options operation builder.
81
62
  #
82
- # Helper method to create a valid PathPaymentStrictReceiveOp, wrapped
83
- # in the necessary XDR structs to be included within a
84
- # transactions `operations` array.
85
- #
86
- # @see Stellar::Asset
63
+ # @param source_account [KeyPair, nil] the source account for the operation
64
+ # @param home_domain [String, nil\] the home domain of the account
65
+ # @param signer [Signer, nil] add, remove or adjust weight of the co-signer
66
+ # @param set [Array<AccountFlags>] flags to set
67
+ # @param clear [Array<AccountFlags>] flags to clear
68
+ # @param inflation_dest [KeyPair, nil] the inflation destination of the account
87
69
  #
88
- # @param [Hash] attributes the attributes to create the operation with
89
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
90
- # @option attributes [Array] :amount the destination asset and the amount to pay
91
- # @option attributes [Array] :with the source asset and maximum allowed source amount to pay with
92
- # @option attributes [Array<Stellar::Asset>] :path the payment path to use
70
+ # @return [Stellar::Operation] the built operation
71
+ def set_options(set: [], clear: [], home_domain: nil, signer: nil, inflation_dest: nil, source_account: nil, **attributes)
72
+ raise ArgumentError, "Bad inflation_dest" if inflation_dest && !inflation_dest.is_a?(KeyPair)
73
+
74
+ op = SetOptionsOp.new(
75
+ set_flags: Stellar::AccountFlags.make_mask(set),
76
+ clear_flags: Stellar::AccountFlags.make_mask(clear),
77
+ master_weight: attributes[:master_weight],
78
+ low_threshold: attributes[:low_threshold],
79
+ med_threshold: attributes[:med_threshold],
80
+ high_threshold: attributes[:high_threshold],
81
+ signer: signer,
82
+ home_domain: home_domain,
83
+ inflation_dest: inflation_dest&.account_id
84
+ )
85
+
86
+ make(source_account: source_account, body: [:set_options, op])
87
+ end
88
+
89
+ # Bump Sequence operation builder
93
90
  #
94
- # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
91
+ # @param [Stellar::KeyPair] source_account the source account for the operation
92
+ # @param [Integer] bump_to the target sequence number for the account
95
93
  #
96
- def path_payment_strict_receive(attributes = {})
97
- destination = attributes[:destination]
98
- asset, amount = get_asset_amount(attributes[:amount])
99
- send_asset, send_max = get_asset_amount(attributes[:with])
100
- path = (attributes[:path] || []).map { |p|
101
- p.is_a?(Array) ? Stellar::Asset.send(*p) : p
102
- }
94
+ # @return [Stellar::Operation] the built operation
95
+ def bump_sequence(bump_to:, source_account: nil)
96
+ raise ArgumentError, ":bump_to too big" unless bump_to <= MAX_INT64
103
97
 
104
- raise ArgumentError unless destination.is_a?(KeyPair)
98
+ op = BumpSequenceOp.new(
99
+ bump_to: bump_to
100
+ )
105
101
 
106
- op = PathPaymentStrictReceiveOp.new
107
- op.send_asset = send_asset
108
- op.send_max = send_max
109
- op.destination = destination.muxed_account
110
- op.dest_asset = asset
111
- op.dest_amount = amount
112
- op.path = path
113
-
114
- make(attributes.merge({
115
- body: [:path_payment_strict_receive, op]
116
- }))
102
+ make(source_account: source_account, body: [:bump_sequence, op])
117
103
  end
118
104
 
105
+ # Manage Data operation builder
119
106
  #
120
- # Helper method to create a valid PathPaymentStrictSendOp, wrapped
121
- # in the necessary XDR structs to be included within a
122
- # transactions `operations` array.
123
- #
124
- # @see Stellar::Asset
125
- #
126
- # @param [Hash] attributes the attributes to create the operation with
127
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
128
- # @option attributes [Array] :amount the destination asset and the minimum amount of destination asset to be received
129
- # @option attributes [Array] :with the source asset and amount to pay with
130
- # @option attributes [Array<Stellar::Asset>] :path the payment path to use
131
- #
132
- # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
107
+ # @param [Stellar::KeyPair, nil] source_account the source account for the operation
108
+ # @param [String] name the name of the data entry
109
+ # @param [String, nil] value the value of the data entry (nil to remove the entry)
133
110
  #
134
- def path_payment_strict_send(attributes = {})
135
- destination = attributes[:destination]
136
- asset, dest_min = get_asset_amount(attributes[:amount])
137
- send_asset, send_amount = get_asset_amount(attributes[:with])
138
- path = (attributes[:path] || []).map { |p|
139
- p.is_a?(Array) ? Stellar::Asset.send(*p) : p
140
- }
111
+ # @return [Stellar::Operation] the built operation
112
+ def manage_data(name:, value: nil, source_account: nil)
113
+ raise ArgumentError, "Invalid :name" unless name.is_a?(String)
114
+ raise ArgumentError, ":name too long" if name.bytesize > 64
115
+ raise ArgumentError, ":value too long" if value && value.bytesize > 64
141
116
 
142
- raise ArgumentError unless destination.is_a?(KeyPair)
117
+ op = ManageDataOp.new(
118
+ data_name: name,
119
+ data_value: value
120
+ )
143
121
 
144
- op = PathPaymentStrictSendOp.new
145
- op.send_asset = send_asset
146
- op.send_amount = send_amount
147
- op.destination = destination.muxed_account
148
- op.dest_asset = asset
149
- op.dest_min = dest_min
150
- op.path = path
151
-
152
- make(attributes.merge({
153
- body: [:path_payment_strict_send, op]
154
- }))
122
+ make(source_account: source_account, body: [:manage_data, op])
155
123
  end
156
124
 
157
- def create_account(attributes = {})
158
- destination = attributes[:destination]
159
- starting_balance = interpret_amount(attributes[:starting_balance])
125
+ # Change Trust operation builder
126
+ #
127
+ # @param source_account [KeyPair, nil] the source account for the operation
128
+ # @param asset [Asset] the asset to trust
129
+ # @param limit [String, Numeric] the maximum amount to trust, defaults to max int64 (0 deletes the trustline)
130
+ #
131
+ # @return [Stellar::Operation] the built operation
132
+ def change_trust(asset: nil, limit: nil, source_account: nil, **attrs)
133
+ if attrs.key?(:line) && !asset
134
+ Stellar::Deprecation.warn("`line` parameter is deprecated, use `asset` instead")
135
+ asset = attrs[:line]
136
+ end
137
+
138
+ op = ChangeTrustOp.new(
139
+ line: Asset(asset).to_change_trust_asset,
140
+ limit: limit ? interpret_amount(limit) : MAX_INT64
141
+ )
160
142
 
161
- raise ArgumentError unless destination.is_a?(KeyPair)
143
+ make(source_account: source_account, body: [:change_trust, op])
144
+ end
162
145
 
163
- op = CreateAccountOp.new
164
- op.destination = destination.account_id
165
- op.starting_balance = starting_balance
146
+ # Set Trustline Flags operation builder
147
+ #
148
+ # @param source_account [KeyPair, nil] the source account for the operation
149
+ # @param asset [Stellar::Asset]
150
+ # @param trustor [Stellar::KeyPair]
151
+ # @param flags [{String, Symbol, Stellar::TrustLineFlags => true, false}] flags to to set or clear
152
+ #
153
+ # @return [Stellar::Operation] the built operation
154
+ def set_trust_line_flags(asset:, trustor:, flags: {}, source_account: nil)
155
+ op = Stellar::SetTrustLineFlagsOp.new(
156
+ trustor: KeyPair(trustor).account_id,
157
+ asset: Asset(asset),
158
+ attributes: TrustLineFlags.set_clear_masks(flags)
159
+ )
166
160
 
167
- make(attributes.merge({
168
- body: [:create_account, op]
169
- }))
161
+ make(source_account: source_account, body: [:set_trust_line_flags, op])
170
162
  end
171
163
 
172
- # Helper method to create a valid ChangeTrustOp, wrapped
173
- # in the necessary XDR structs to be included within a
174
- # transactions `operations` array.
175
- #
176
- # @param [Hash] attributes the attributes to create the operation with
177
- # @option attributes [Stellar::Asset] :line the asset to trust
178
- # @option attributes [Fixnum] :limit the maximum amount to trust, defaults to max int64,
179
- # if the limit is set to 0 it deletes the trustline.
180
- #
181
- # @return [Stellar::Operation] the built operation, containing a
182
- # Stellar::ChangeTrustOp body
183
- def change_trust(attributes = {})
184
- line = attributes[:line]
185
- unless line.is_a?(Asset)
186
- unless Asset::TYPES.include?(line[0])
187
- fail ArgumentError, "must be one of #{Asset::TYPES}"
188
- end
189
- line = Asset.send(*line)
190
- end
164
+ # Clawback operation builder
165
+ #
166
+ # @param [Stellar::KeyPair] source_account the source account for the operation
167
+ # @param [String|Account|PublicKey|SignerKey|KeyPair] from the account to clawback from
168
+ # @param [(Asset, Numeric)] amount the amount of asset to subtract from the balance
169
+ #
170
+ # @return [Stellar::Operation] the built operation
171
+ def clawback(from:, amount:, source_account: nil)
172
+ asset, amount = get_asset_amount(amount)
191
173
 
192
- limit = attributes.key?(:limit) ? interpret_amount(attributes[:limit]) : MAX_INT64
174
+ if amount == 0
175
+ raise ArgumentError, "Amount can not be zero"
176
+ end
193
177
 
194
- raise ArgumentError, "Bad :limit #{limit}" unless limit.is_a?(Integer)
178
+ if amount < 0
179
+ raise ArgumentError, "Negative amount is not allowed"
180
+ end
195
181
 
196
- op = ChangeTrustOp.new(line: line, limit: limit)
182
+ op = ClawbackOp.new(
183
+ amount: amount,
184
+ from: KeyPair(from).muxed_account,
185
+ asset: asset
186
+ )
197
187
 
198
- make(attributes.merge({
199
- body: [:change_trust, op]
200
- }))
188
+ make(source_account: source_account, body: [:clawback, op])
201
189
  end
202
190
 
203
- # Helper method to create a valid CreateClaimableBalanceOp, ready to be used
204
- # within a transactions `operations` array.
191
+ # Create Claimable Balance operation builder.
205
192
  #
206
193
  # @see Stellar::DSL::Claimant
207
194
  # @see https://github.com/astroband/ruby-stellar-sdk/tree/master/base/examples/claimable_balances.rb
208
195
  #
196
+ # @param source_account [KeyPair, nil] the source account for the operation
209
197
  # @param asset [Asset] the asset to transfer to a claimable balance
210
198
  # @param amount [Fixnum] the amount of `asset` to put into a claimable balance
211
199
  # @param claimants [Array<Claimant>] accounts authorized to claim the balance in the future
212
200
  #
213
201
  # @return [Operation] the built operation
214
- def create_claimable_balance(asset:, amount:, claimants:, **attributes)
202
+ def create_claimable_balance(asset:, amount:, claimants:, source_account: nil)
215
203
  op = CreateClaimableBalanceOp.new(asset: asset, amount: amount, claimants: claimants)
216
204
 
217
- make(attributes.merge(body: [:create_claimable_balance, op]))
205
+ make(source_account: source_account, body: [:create_claimable_balance, op])
218
206
  end
219
207
 
220
208
  # Helper method to create a valid CreateClaimableBalanceOp, ready to be used
@@ -223,274 +211,276 @@ module Stellar
223
211
  # @see Stellar::DSL::Claimant
224
212
  # @see https://github.com/astroband/ruby-stellar-sdk/tree/master/base/examples/claimable_balances.rb
225
213
  #
214
+ # @param source_account [KeyPair, nil] the source account for the operation
226
215
  # @param balance_id [ClaimableBalanceID] unique ID of claimable balance
227
216
  #
228
- # @return [Operation] the built operation, containing a Stellar::ChangeTrustOp body
229
- def claim_claimable_balance(balance_id:, **attributes)
217
+ # @return [Operation] the built operation
218
+ def claim_claimable_balance(balance_id:, source_account: nil)
230
219
  op = ClaimClaimableBalanceOp.new(balance_id: balance_id)
231
220
 
232
- make(attributes.merge(body: [:claim_claimable_balance, op]))
221
+ make(source_account: source_account, body: [:claim_claimable_balance, op])
233
222
  end
234
223
 
235
- def begin_sponsoring_future_reserves(sponsored:, **attributes)
236
- op = BeginSponsoringFutureReservesOp.new(
237
- sponsored_id: KeyPair(sponsored).account_id
224
+ # Clawback Claimable Balance operation builder
225
+ #
226
+ # @param [Stellar::KeyPair] source_account the source account for the operation
227
+ # @param [String] balance_id claimable balance ID as a hexadecimal string
228
+ #
229
+ # @return [Stellar::Operation] the built operation
230
+ def clawback_claimable_balance(balance_id:, source_account: nil)
231
+ balance_id = Stellar::ClaimableBalanceID.from_xdr(balance_id, :hex)
232
+ op = ClawbackClaimableBalanceOp.new(balance_id: balance_id)
233
+
234
+ make(source_account: source_account, body: [:clawback_claimable_balance, op])
235
+ rescue XDR::ReadError
236
+ raise ArgumentError, "Claimable balance id '#{balance_id}' is invalid"
237
+ end
238
+
239
+ # Payment Operation builder
240
+ #
241
+ # @param source_account [KeyPair, nil] the source account for the operation
242
+ # @param [Stellar::KeyPair] destination the receiver of the payment
243
+ # @param [(Asset, Numeric)] amount the amount to pay
244
+ #
245
+ # @return [Stellar::Operation] the built operation
246
+ def payment(destination:, amount:, source_account: nil)
247
+ raise ArgumentError unless destination.is_a?(KeyPair)
248
+ asset, amount = get_asset_amount(amount)
249
+
250
+ op = PaymentOp.new(
251
+ asset: asset,
252
+ amount: amount,
253
+ destination: destination.muxed_account
238
254
  )
239
255
 
240
- make(attributes.merge(body: [:begin_sponsoring_future_reserves, op]))
256
+ make(
257
+ source_account: source_account,
258
+ body: [:payment, op]
259
+ )
241
260
  end
242
261
 
243
- def end_sponsoring_future_reserves(**attributes)
244
- make(attributes.merge(body: [:end_sponsoring_future_reserves]))
262
+ # Path Payment Strict Receive operation builder.
263
+ #
264
+ # @param source_account [KeyPair, nil] the source account for the operation
265
+ # @param destination [Stellar::KeyPair] the receiver of the payment
266
+ # @param amount [Array] the destination asset and the amount to pay
267
+ # @param with [Array] the source asset and maximum allowed source amount to pay with
268
+ # @param path [Array<Stellar::Asset>] the payment path to use
269
+ #
270
+ # @return [Stellar::Operation] the built operation
271
+ def path_payment_strict_receive(destination:, amount:, with:, path: [], source_account: nil)
272
+ raise ArgumentError unless destination.is_a?(KeyPair)
273
+
274
+ dest_asset, dest_amount = get_asset_amount(amount)
275
+ send_asset, send_max = get_asset_amount(with)
276
+
277
+ op = PathPaymentStrictReceiveOp.new(
278
+ destination: destination.muxed_account,
279
+ dest_asset: dest_asset,
280
+ dest_amount: dest_amount,
281
+ send_asset: send_asset,
282
+ send_max: send_max,
283
+ path: path.map { |p| Asset(p) }
284
+ )
285
+
286
+ make(source_account: source_account, body: [:path_payment_strict_receive, op])
245
287
  end
288
+ alias_method :path_payment, :path_payment_strict_receive
246
289
 
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]))
290
+ # Path Payment Strict Receive operation builder.
291
+ #
292
+ # @param source_account [KeyPair, nil] the source account for the operation
293
+ # @param destination [Stellar::KeyPair] the receiver of the payment
294
+ # @param amount [Array] the destination asset and the minimum amount of destination asset to be received
295
+ # @param with [Array] the source asset and amount to pay with
296
+ # @param path [Array<Stellar::Asset>] the payment path to use
297
+ #
298
+ # @return [Stellar::Operation] the built operation
299
+ def path_payment_strict_send(destination:, amount:, with:, path: [], source_account: nil)
300
+ raise ArgumentError unless destination.is_a?(KeyPair)
301
+
302
+ dest_asset, dest_min = get_asset_amount(amount)
303
+ send_asset, send_amount = get_asset_amount(with)
304
+
305
+ op = PathPaymentStrictSendOp.new(
306
+ destination: destination.muxed_account,
307
+ send_asset: send_asset,
308
+ send_amount: send_amount,
309
+ dest_asset: dest_asset,
310
+ dest_min: dest_min,
311
+ path: path.map { |p| Asset(p) }
312
+ )
313
+
314
+ make(source_account: source_account, body: [:path_payment_strict_send, op])
259
315
  end
260
316
 
261
- def manage_sell_offer(attributes = {})
262
- buying = attributes[:buying]
263
- if buying.is_a?(Array)
264
- buying = Asset.send(*buying)
265
- end
266
- selling = attributes[:selling]
267
- if selling.is_a?(Array)
268
- selling = Asset.send(*selling)
269
- end
270
- amount = interpret_amount(attributes[:amount])
271
- offer_id = attributes[:offer_id] || 0
272
- price = interpret_price(attributes[:price])
317
+ # Manage Sell Offer operation builder
318
+ #
319
+ # @param source_account [KeyPair, nil] the source account for the operation
320
+ # @param selling [Asset] the asset to sell
321
+ # @param buying [Asset] the asset to buy
322
+ # @param amount [String, Numeric] the amount of asset to sell
323
+ # @param price [String, Numeric, Price] the price of the selling asset in terms of buying asset
324
+ # @param offer_id [Integer] the offer ID to modify (0 to create a new offer)
325
+ #
326
+ # @return [Operation] the built operation
327
+ def manage_sell_offer(selling:, buying:, amount:, price:, offer_id: 0, source_account: nil)
328
+ selling = Asset.send(*selling) if selling.is_a?(Array)
329
+ buying = Asset.send(*buying) if buying.is_a?(Array)
273
330
 
274
- op = ManageSellOfferOp.new({
331
+ op = ManageSellOfferOp.new(
275
332
  buying: buying,
276
333
  selling: selling,
277
- amount: amount,
278
- price: price,
334
+ amount: interpret_amount(amount),
335
+ price: Price.from(price),
279
336
  offer_id: offer_id
280
- })
337
+ )
281
338
 
282
- make(attributes.merge({
283
- body: [:manage_sell_offer, op]
284
- }))
339
+ make(source_account: source_account, body: [:manage_sell_offer, op])
285
340
  end
286
341
 
287
- def manage_buy_offer(attributes = {})
288
- buying = attributes[:buying]
289
- if buying.is_a?(Array)
290
- buying = Asset.send(*buying)
291
- end
292
- selling = attributes[:selling]
293
- if selling.is_a?(Array)
294
- selling = Asset.send(*selling)
295
- end
296
- amount = interpret_amount(attributes[:amount])
297
- offer_id = attributes[:offer_id] || 0
298
- price = interpret_price(attributes[:price])
342
+ # Manage Buy Offer operation builder
343
+ #
344
+ # @param source_account [KeyPair, nil] the source account for the operation
345
+ # @param buying [Asset] the asset to buy
346
+ # @param selling [Asset] the asset to sell
347
+ # @param amount [String, Numeric] the amount of asset to buy
348
+ # @param price [String, Numeric, Price] the price of the buying asset in terms of the selling asset
349
+ # @param offer_id [Integer] the offer ID to modify (0 to create a new offer)
350
+ #
351
+ # @return [Operation] the built operation
352
+ def manage_buy_offer(buying:, selling:, amount:, price:, offer_id: 0, source_account: nil)
353
+ buying = Asset.send(*buying) if buying.is_a?(Array)
354
+ selling = Asset.send(*selling) if selling.is_a?(Array)
299
355
 
300
- op = ManageBuyOfferOp.new({
356
+ op = ManageBuyOfferOp.new(
301
357
  buying: buying,
302
358
  selling: selling,
303
- amount: amount,
304
- price: price,
359
+ buy_amount: interpret_amount(amount),
360
+ price: Price.from(price),
305
361
  offer_id: offer_id
306
- })
362
+ )
307
363
 
308
- make(attributes.merge({
309
- body: [:manage_buy_offer, op]
310
- }))
364
+ make(source_account: source_account, body: [:manage_buy_offer, op])
311
365
  end
312
366
 
313
- def create_passive_sell_offer(attributes = {})
314
- buying = attributes[:buying]
315
- if buying.is_a?(Array)
316
- buying = Asset.send(*buying)
317
- end
318
- selling = attributes[:selling]
319
- if selling.is_a?(Array)
320
- selling = Asset.send(*selling)
321
- end
322
- amount = interpret_amount(attributes[:amount])
323
- price = interpret_price(attributes[:price])
367
+ # Create Passive Sell Offer operation builder
368
+ #
369
+ # @param source_account [KeyPair, nil] the source account for the operation
370
+ # @param selling [Asset] the asset to sell
371
+ # @param buying [Asset] the asset to buy
372
+ # @param amount [String, Numeric] the amount of asset to sell
373
+ # @param price [String, Numeric, Price] the price of the selling asset in terms of buying asset
374
+ #
375
+ # @return [Operation] the built operation
376
+ def create_passive_sell_offer(selling:, buying:, amount:, price:, source_account: nil)
377
+ selling = Asset.send(*selling) if selling.is_a?(Array)
378
+ buying = Asset.send(*buying) if buying.is_a?(Array)
324
379
 
325
- op = CreatePassiveSellOfferOp.new({
380
+ op = CreatePassiveSellOfferOp.new(
326
381
  buying: buying,
327
382
  selling: selling,
328
- amount: amount,
329
- price: price
330
- })
383
+ amount: interpret_amount(amount),
384
+ price: Price.from(price)
385
+ )
331
386
 
332
- make(attributes.merge({
333
- body: [:create_passive_sell_offer, op]
334
- }))
387
+ make(source_account: source_account, body: [:create_passive_sell_offer, op])
335
388
  end
336
389
 
390
+ # Liquidity Pool Deposit operation builder
337
391
  #
338
- # Helper method to create a valid SetOptionsOp, wrapped
339
- # in the necessary XDR structs to be included within a
340
- # transactions `operations` array.
341
- #
342
- # @param [Hash] attributes the attributes to create the operation with
343
- # @option attributes [Stellar::KeyPair] :inflation_dest
344
- # @option attributes [Array<Stellar::AccountFlags>] :set flags to set
345
- # @option attributes [Array<Stellar::AccountFlags>] :clear flags to clear
346
- # @option attributes [String] :thresholds
347
- # @option attributes [Stellar::Signer] :signer
348
- #
349
- # @return [Stellar::Operation] the built operation, containing a
350
- # Stellar::SetOptionsOp body
351
- def set_options(attributes = {})
352
- op = SetOptionsOp.new
353
- op.set_flags = Stellar::AccountFlags.make_mask attributes[:set]
354
- op.clear_flags = Stellar::AccountFlags.make_mask attributes[:clear]
355
- op.master_weight = attributes[:master_weight]
356
- op.low_threshold = attributes[:low_threshold]
357
- op.med_threshold = attributes[:med_threshold]
358
- op.high_threshold = attributes[:high_threshold]
359
-
360
- op.signer = attributes[:signer]
361
- op.home_domain = attributes[:home_domain]
362
-
363
- inflation_dest = attributes[:inflation_dest]
364
- if inflation_dest
365
- raise ArgumentError, "Bad :inflation_dest" unless inflation_dest.is_a?(Stellar::KeyPair)
366
- op.inflation_dest = inflation_dest.account_id
367
- end
392
+ # @param [Stellar::KeyPair] source_account the source account for the operation
393
+ # @param [String] liquidity_pool_id the liquidity pool id as hexadecimal string
394
+ # @param [String, Numeric] max_amount_a the maximum amount of asset A to deposit
395
+ # @param [String, Numeric] max_amount_b the maximum amount of asset B to deposit
396
+ # @param [String, Numeric, Stellar::Price] min_price the minimum valid price of asset A in terms of asset B
397
+ # @param [String, Numeric, Stellar::Price] max_price the maximum valid price of asset A in terms of asset B
398
+ #
399
+ # @return [Stellar::Operation] the built operation
400
+ def liquidity_pool_deposit(liquidity_pool_id:, max_amount_a:, max_amount_b:, min_price:, max_price:, source_account: nil)
401
+ op = LiquidityPoolDepositOp.new(
402
+ liquidity_pool_id: PoolID.from_xdr(liquidity_pool_id, :hex),
403
+ max_amount_a: interpret_amount(max_amount_a),
404
+ max_amount_b: interpret_amount(max_amount_b),
405
+ min_price: Price.from(min_price),
406
+ max_price: Price.from(max_price)
407
+ )
368
408
 
369
- make(attributes.merge({
370
- body: [:set_options, op]
371
- }))
409
+ make(source_account: source_account, body: [:liquidity_pool_deposit, op])
410
+ rescue XDR::ReadError
411
+ raise ArgumentError, "invalid liquidity pool ID '#{balance_id}'"
372
412
  end
373
413
 
414
+ # Liquidity Pool Withdraw operation builder
374
415
  #
375
- # Helper method to create a valid AllowTrustOp, wrapped
376
- # in the necessary XDR structs to be included within a
377
- # transactions `operations` array.
416
+ # @param [Stellar::KeyPair] source_account the source account for the operation
417
+ # @param [String] liquidity_pool_id the liquidity pool id as hexadecimal string
418
+ # @param [String, Numeric] amount the number of pool shares to withdraw
419
+ # @param [String, Numeric] min_amount_a the minimum amount of asset A to withdraw
420
+ # @param [String, Numeric] min_amount_b the minimum amount of asset B to withdraw
378
421
  #
379
- # @param [Hash] attributes the attributes to create the operation with
380
- # @option attributes [Stellar::KeyPair] :trustor
381
- # @option attributes [Stellar::Asset] :asset
382
- # @option attributes [Symbol, Boolean] :authorize :full, maintain_liabilities or :none
383
- #
384
- # @return [Stellar::Operation] the built operation, containing a
385
- # Stellar::AllowTrustOp body
386
- def allow_trust(attributes = {})
387
- op = AllowTrustOp.new
388
-
389
- trustor = attributes[:trustor]
390
- authorize = attributes[:authorize]
391
- asset = attributes[:asset]
392
- if asset.is_a?(Array)
393
- asset = Asset.send(*asset)
394
- end
395
-
396
- raise ArgumentError, "Bad :trustor" unless trustor.is_a?(Stellar::KeyPair)
397
-
398
- op.authorize = case authorize
399
- when :none, false then 0 # we handle booleans here for the backward compatibility
400
- when :full, true then TrustLineFlags.authorized_flag.value
401
- when :maintain_liabilities then TrustLineFlags.authorized_to_maintain_liabilities_flag.value
402
- else
403
- raise ArgumentError, "Bad :authorize, supported values: :full, :maintain_liabilities, :none"
404
- end
405
-
406
- raise ArgumentError, "Bad :asset" unless asset.type == Stellar::AssetType.asset_type_credit_alphanum4
407
-
408
- atc = AllowTrustOp::Asset.new(:asset_type_credit_alphanum4, asset.code)
409
-
410
- op.trustor = trustor.account_id
411
- op.asset = atc
422
+ # @return [Stellar::Operation] the built operation
423
+ def liquidity_pool_withdraw(liquidity_pool_id:, amount:, min_amount_a:, min_amount_b:, source_account: nil)
424
+ op = LiquidityPoolWithdrawOp.new(
425
+ liquidity_pool_id: PoolID.from_xdr(liquidity_pool_id, :hex),
426
+ amount: interpret_amount(amount),
427
+ min_amount_a: interpret_amount(min_amount_a),
428
+ min_amount_b: interpret_amount(min_amount_b)
429
+ )
412
430
 
413
- make(attributes.merge({
414
- body: [:allow_trust, op]
415
- }))
431
+ make(source_account: source_account, body: [:liquidity_pool_withdraw, op])
432
+ rescue XDR::ReadError
433
+ raise ArgumentError, "invalid liquidity pool ID '#{balance_id}'"
416
434
  end
417
435
 
436
+ # Begin Sponsoring Future Reserves operation builder
418
437
  #
419
- # Helper method to create an account merge operation
420
- #
421
- # @param [Hash] attributes the attributes to create the operation with
422
- # @option attributes [Stellar::KeyPair] :destination
438
+ # @param source_account [KeyPair, nil] the source account for the operation
423
439
  #
424
- # @return [Stellar::Operation] the built operation
425
- def account_merge(attributes = {})
426
- destination = attributes[:destination]
427
-
428
- raise ArgumentError, "Bad :destination" unless destination.is_a?(KeyPair)
440
+ # @return [Operation] the built operation
441
+ def begin_sponsoring_future_reserves(sponsored:, source_account: nil)
442
+ op = BeginSponsoringFutureReservesOp.new(
443
+ sponsored_id: KeyPair(sponsored).account_id
444
+ )
429
445
 
430
- # TODO: add source_account support
431
- make(attributes.merge({
432
- body: [:account_merge, destination.muxed_account]
433
- }))
446
+ make(source_account: source_account, body: [:begin_sponsoring_future_reserves, op])
434
447
  end
435
448
 
449
+ # End Sponsoring Future Reserves operation builder
436
450
  #
437
- # Helper method to create an inflation operation
438
- #
439
- # @param [Hash] attributes the attributes to create the operation with
440
- # @option attributes [Integer] :sequence
451
+ # @param source_account [KeyPair, nil] the source account for the operation
441
452
  #
442
- # @return [Stellar::Operation] the built operation
443
- def inflation(attributes = {})
444
- sequence = attributes[:sequence]
445
-
446
- raise ArgumentError, "Bad :sequence #{sequence}" unless sequence.is_a?(Integer)
447
-
448
- # TODO: add source_account support
449
- make(attributes.merge({
450
- body: [:inflation]
451
- }))
453
+ # @return [Operation] the built operation
454
+ def end_sponsoring_future_reserves(source_account: nil)
455
+ make(source_account: source_account, body: [:end_sponsoring_future_reserves])
452
456
  end
453
457
 
458
+ # Revoke Sponsorship operation builder
454
459
  #
455
- # Helper method to create an manage data operation
456
- #
457
- # @param [Hash] attributes the attributes to create the operation with
458
- # @option attributes [Integer] :sequence
460
+ # @param source_account [KeyPair, nil] the source account for the operation
461
+ # @param sponsored [#to_keypair] owner of sponsored entry
459
462
  #
460
- # @return [Stellar::Operation] the built operation
461
- def manage_data(attributes = {})
462
- op = ManageDataOp.new
463
-
464
- name = attributes[:name]
465
- value = attributes[:value]
466
-
467
- raise ArgumentError, "Invalid :name" unless name.is_a?(String)
468
- raise ArgumentError, ":name too long" unless name.bytesize <= 64
469
-
470
- if value.present?
471
- raise ArgumentError, ":value too long" unless value.bytesize <= 64
463
+ # @return [Operation] the built operation
464
+ def revoke_sponsorship(sponsored:, source_account: nil, **attributes)
465
+ key_fields = attributes.slice(:offer_id, :data_name, :balance_id, :liquidity_pool_id, :asset, :signer)
466
+ raise ArgumentError, "conflicting attributes: #{key_fields.keys.join(", ")}" if key_fields.size > 1
467
+ account_id = KeyPair(sponsored).account_id
468
+ key, value = key_fields.first
469
+ op = if key == :signer
470
+ RevokeSponsorshipOp.signer(account_id: account_id, signer_key: SignerKey(value))
471
+ else
472
+ RevokeSponsorshipOp.ledger_key(LedgerKey.from(account_id: account_id, **key_fields))
472
473
  end
473
-
474
- op.data_name = name
475
- op.data_value = value
476
-
477
- make(attributes.merge({
478
- body: [:manage_data, op]
479
- }))
474
+ make(source_account: source_account, body: [:revoke_sponsorship, op])
480
475
  end
481
476
 
482
- def bump_sequence(attributes = {})
483
- op = BumpSequenceOp.new
484
-
485
- bump_to = attributes[:bump_to]
486
-
487
- raise ArgumentError, ":bump_to too big" unless bump_to <= MAX_INT64
488
-
489
- op.bump_to = bump_to
490
-
491
- make(attributes.merge({
492
- body: [:bump_sequence, op]
493
- }))
477
+ # Inflation operation builder
478
+ #
479
+ # @param [Stellar::KeyPair, nil] source_account the source account for the operation
480
+ #
481
+ # @return [Stellar::Operation] the built operation
482
+ def inflation(source_account: nil)
483
+ make(source_account: source_account, body: [:inflation])
494
484
  end
495
485
 
496
486
  private
@@ -507,29 +497,10 @@ module Stellar
507
497
  end
508
498
 
509
499
  def interpret_amount(amount)
510
- case amount
511
- when String
512
- (BigDecimal(amount) * Stellar::ONE).floor
513
- when Integer
514
- amount * Stellar::ONE
515
- when Numeric
500
+ if amount.is_a?(Float)
516
501
  (amount * Stellar::ONE).floor
517
502
  else
518
- raise ArgumentError, "Invalid amount type: #{amount.class}. Must be String or Numeric"
519
- end
520
- end
521
-
522
- def interpret_price(price)
523
- case price
524
- when String
525
- bd = BigDecimal(price)
526
- Price.from_f(bd)
527
- when Numeric
528
- Price.from_f(price)
529
- when Stellar::Price
530
- price
531
- else
532
- raise ArgumentError, "Invalid price type: #{price.class}. Must be String, Numeric, or Stellar::Price"
503
+ (BigDecimal(amount) * Stellar::ONE).floor
533
504
  end
534
505
  end
535
506
  end