stellar-base 0.21.0 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -2
  3. data/{LICENSE.txt → LICENSE} +0 -0
  4. data/README.md +3 -4
  5. data/generated/stellar-base-generated.rb +25 -1
  6. data/generated/stellar/allow_trust_op.rb +3 -2
  7. data/generated/stellar/authenticated_message.rb +4 -4
  8. data/generated/stellar/authenticated_message/v0.rb +4 -4
  9. data/generated/stellar/change_trust_result_code.rb +1 -1
  10. data/generated/stellar/crypto_key_type.rb +8 -4
  11. data/generated/stellar/curve25519_public.rb +1 -1
  12. data/generated/stellar/curve25519_secret.rb +1 -1
  13. data/generated/stellar/envelope_type.rb +9 -5
  14. data/generated/stellar/fee_bump_transaction.rb +39 -0
  15. data/generated/stellar/fee_bump_transaction/ext.rb +24 -0
  16. data/generated/stellar/fee_bump_transaction/inner_tx.rb +25 -0
  17. data/generated/stellar/fee_bump_transaction_envelope.rb +22 -0
  18. data/generated/stellar/hmac_sha256_key.rb +1 -1
  19. data/generated/stellar/hmac_sha256_mac.rb +1 -1
  20. data/generated/stellar/inner_transaction_result.rb +56 -0
  21. data/generated/stellar/inner_transaction_result/ext.rb +24 -0
  22. data/generated/stellar/inner_transaction_result/result.rb +52 -0
  23. data/generated/stellar/inner_transaction_result_pair.rb +20 -0
  24. data/generated/stellar/ledger_close_meta.rb +23 -0
  25. data/generated/stellar/ledger_close_meta_v0.rb +35 -0
  26. data/generated/stellar/manage_buy_offer_result_code.rb +5 -4
  27. data/generated/stellar/manage_sell_offer_result_code.rb +12 -8
  28. data/generated/stellar/message_type.rb +6 -1
  29. data/generated/stellar/muxed_account.rb +35 -0
  30. data/generated/stellar/muxed_account/med25519.rb +22 -0
  31. data/generated/stellar/operation.rb +3 -3
  32. data/generated/stellar/operation/body.rb +2 -2
  33. data/generated/stellar/operation_result.rb +1 -1
  34. data/generated/stellar/operation_result/tr.rb +1 -1
  35. data/generated/stellar/operation_result_code.rb +3 -3
  36. data/generated/stellar/path_payment_strict_receive_op.rb +4 -4
  37. data/generated/stellar/path_payment_strict_receive_result_code.rb +21 -12
  38. data/generated/stellar/path_payment_strict_send_op.rb +6 -6
  39. data/generated/stellar/path_payment_strict_send_result_code.rb +20 -12
  40. data/generated/stellar/payment_op.rb +4 -4
  41. data/generated/stellar/peer_stats.rb +48 -0
  42. data/generated/stellar/signed_survey_request_message.rb +20 -0
  43. data/generated/stellar/signed_survey_response_message.rb +20 -0
  44. data/generated/stellar/stellar_message.rb +22 -12
  45. data/generated/stellar/survey_message_command_type.rb +20 -0
  46. data/generated/stellar/survey_request_message.rb +26 -0
  47. data/generated/stellar/survey_response_body.rb +23 -0
  48. data/generated/stellar/survey_response_message.rb +26 -0
  49. data/generated/stellar/topology_response_body.rb +25 -0
  50. data/generated/stellar/transaction.rb +2 -2
  51. data/generated/stellar/transaction_envelope.rb +17 -8
  52. data/generated/stellar/transaction_meta.rb +4 -0
  53. data/generated/stellar/transaction_meta_v2.rb +24 -0
  54. data/generated/stellar/transaction_result.rb +3 -0
  55. data/generated/stellar/transaction_result/result.rb +9 -3
  56. data/generated/stellar/transaction_result_code.rb +21 -14
  57. data/generated/stellar/transaction_result_meta.rb +22 -0
  58. data/generated/stellar/transaction_signature_payload.rb +3 -1
  59. data/generated/stellar/transaction_signature_payload/tagged_transaction.rb +7 -3
  60. data/generated/stellar/transaction_v0.rb +39 -0
  61. data/generated/stellar/transaction_v0/ext.rb +24 -0
  62. data/generated/stellar/transaction_v0_envelope.rb +22 -0
  63. data/generated/stellar/transaction_v1_envelope.rb +22 -0
  64. data/generated/stellar/trust_line_flags.rb +6 -2
  65. data/generated/stellar/upgrade_entry_meta.rb +20 -0
  66. data/lib/stellar-base.rb +27 -24
  67. data/lib/stellar/account_flags.rb +2 -4
  68. data/lib/stellar/asset.rb +6 -6
  69. data/lib/stellar/base.rb +1 -1
  70. data/lib/stellar/{base/compat.rb → compat.rb} +6 -7
  71. data/lib/stellar/concerns/transaction.rb +49 -0
  72. data/lib/stellar/convert.rb +2 -2
  73. data/lib/stellar/factories.rb +1 -3
  74. data/lib/stellar/fee_bump_transaction.rb +21 -0
  75. data/lib/stellar/key_pair.rb +9 -6
  76. data/lib/stellar/networks.rb +5 -7
  77. data/lib/stellar/operation.rb +426 -392
  78. data/lib/stellar/path_payment_strict_receive_result.rb +1 -2
  79. data/lib/stellar/price.rb +2 -4
  80. data/lib/stellar/signer_key.rb +4 -8
  81. data/lib/stellar/thresholds.rb +5 -7
  82. data/lib/stellar/transaction.rb +154 -187
  83. data/lib/stellar/transaction_builder.rb +149 -0
  84. data/lib/stellar/transaction_envelope.rb +40 -8
  85. data/lib/stellar/transaction_v0.rb +39 -0
  86. data/lib/stellar/util/continued_fraction.rb +19 -19
  87. data/lib/stellar/util/strkey.rb +39 -14
  88. data/lib/stellar/{base/version.rb → version.rb} +1 -1
  89. metadata +50 -204
  90. data/.gitignore +0 -17
  91. data/.travis.yml +0 -16
  92. data/.yardopts +0 -8
  93. data/CONTRIBUTING.md +0 -48
  94. data/Gemfile +0 -15
  95. data/Guardfile +0 -5
  96. data/Rakefile +0 -4
  97. data/examples/allow_trust.rb +0 -51
  98. data/examples/create_account.rb +0 -26
  99. data/examples/low_level_transaction_post.rb +0 -46
  100. data/examples/mid_level_transaction_post.rb +0 -33
  101. data/examples/non_native_payment.rb +0 -60
  102. data/examples/offer.rb +0 -75
  103. data/examples/transaction_merge.rb +0 -23
  104. data/ruby-stellar-base.gemspec +0 -34
  105. data/spec/lib/stellar/account_flags_spec.rb +0 -19
  106. data/spec/lib/stellar/asset_spec.rb +0 -45
  107. data/spec/lib/stellar/convert_spec.rb +0 -61
  108. data/spec/lib/stellar/key_pair_spec.rb +0 -251
  109. data/spec/lib/stellar/networks_spec.rb +0 -77
  110. data/spec/lib/stellar/operation_spec.rb +0 -133
  111. data/spec/lib/stellar/path_payment_strict_receive_result_spec.rb +0 -95
  112. data/spec/lib/stellar/price_spec.rb +0 -34
  113. data/spec/lib/stellar/signer_key_spec.rb +0 -26
  114. data/spec/lib/stellar/thresholds_spec.rb +0 -62
  115. data/spec/lib/stellar/transaction_envelope_spec.rb +0 -93
  116. data/spec/lib/stellar/transaction_spec.rb +0 -132
  117. data/spec/lib/stellar/util/strkey_spec.rb +0 -54
  118. data/spec/spec_helper.rb +0 -16
  119. data/spec/support/matchers/be_strkey.rb +0 -9
  120. data/spec/support/matchers/eq_bytes.rb +0 -5
  121. data/spec/support/matchers/have_length.rb +0 -5
  122. data/tasks/rspec.rake +0 -6
  123. data/tasks/travis.rake +0 -1
  124. data/tasks/xdr.rake +0 -45
  125. data/xdr/Stellar-SCP.x +0 -86
  126. data/xdr/Stellar-ledger-entries.x +0 -295
  127. data/xdr/Stellar-ledger.x +0 -318
  128. data/xdr/Stellar-overlay.x +0 -146
  129. data/xdr/Stellar-transaction.x +0 -901
  130. data/xdr/Stellar-types.x +0 -81
@@ -3,10 +3,10 @@ module Stellar
3
3
  # Generic format conversion module
4
4
  #
5
5
  module Convert
6
- require 'base64'
6
+ require "base64"
7
7
 
8
8
  def to_hex(string)
9
- string.unpack("H*").first
9
+ string.unpack1("H*")
10
10
  end
11
11
 
12
12
  def from_hex(hex_string)
@@ -1,5 +1,4 @@
1
1
  FactoryBot.define do
2
-
3
2
  factory :stellar_ledger, class: Hyperclient::Resource do
4
3
  initialize_with { new(attributes.stringify_keys, nil, nil) }
5
4
 
@@ -39,7 +38,7 @@ FactoryBot.define do
39
38
  fee_meta_xdr { "AAAAAgAAAAMAAAABAAAAAAAAAAABlHJijueOuScU0i0DkJY8JNkn6gCZmUhuiR+sLaqcIQ3gtrOnZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAEAAAADAAAAAAAAAAABlHJijueOuScU0i0DkJY8JNkn6gCZmUhuiR+sLaqcIQ3gtrOnY/7UAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA==" }
40
39
  memo_type { "text" }
41
40
  signatures do
42
- [ "SsKlst02jsaBp35vXlI300Qbz39+HbwwNDX/gfM+MwaG/dFF7bgqpkKsDAsh/qJDiN3NOW695IZB9Mj+JAsHBA==" ]
41
+ ["SsKlst02jsaBp35vXlI300Qbz39+HbwwNDX/gfM+MwaG/dFF7bgqpkKsDAsh/qJDiN3NOW695IZB9Mj+JAsHBA=="]
43
42
  end
44
43
  end
45
44
 
@@ -57,5 +56,4 @@ FactoryBot.define do
57
56
  funder { "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7" }
58
57
  account { "GALPCCZN4YXA3YMJHKL6CVIECKPLJJCTVMSNYWBTKJW4K5HQLYLDMZTB" }
59
58
  end
60
-
61
59
  end
@@ -0,0 +1,21 @@
1
+ module Stellar
2
+ class FeeBumpTransaction
3
+ include Stellar::Concerns::Transaction
4
+
5
+ def to_envelope(*key_pairs)
6
+ signatures = (key_pairs || []).map(&method(:sign_decorated))
7
+
8
+ TransactionEnvelope.fee_bump(signatures: signatures, tx: self)
9
+ end
10
+
11
+ def signature_base_prefix
12
+ val = Stellar::EnvelopeType.envelope_type_tx_fee_bump
13
+
14
+ Stellar.current_network_id + Stellar::EnvelopeType.to_xdr(val)
15
+ end
16
+
17
+ def source_account
18
+ source_account_ed25519
19
+ end
20
+ end
21
+ end
@@ -36,7 +36,7 @@ module Stellar
36
36
  from_raw_seed(Stellar.current_network_id)
37
37
  end
38
38
 
39
- def initialize(public_key, secret_key=nil)
39
+ def initialize(public_key, secret_key = nil)
40
40
  @public_key = public_key
41
41
  @secret_key = secret_key
42
42
  end
@@ -45,6 +45,10 @@ module Stellar
45
45
  Stellar::AccountID.new :public_key_type_ed25519, raw_public_key
46
46
  end
47
47
 
48
+ def muxed_account
49
+ Stellar::MuxedAccount.new :key_type_ed25519, raw_public_key
50
+ end
51
+
48
52
  def public_key
49
53
  Stellar::PublicKey.new :public_key_type_ed25519, raw_public_key
50
54
  end
@@ -81,9 +85,9 @@ module Stellar
81
85
 
82
86
  def seed
83
87
  raise "no private key" if @secret_key.nil?
84
- #TODO: improve the error class above
88
+ # TODO: improve the error class above
85
89
  seed_bytes = raw_seed
86
- encoder = Util::StrKey.check_encode(:seed, seed_bytes)
90
+ Util::StrKey.check_encode(:seed, seed_bytes)
87
91
  end
88
92
 
89
93
  def sign?
@@ -92,14 +96,14 @@ module Stellar
92
96
 
93
97
  def sign(message)
94
98
  raise "no private key" if @secret_key.nil?
95
- #TODO: improve the error class above
99
+ # TODO: improve the error class above
96
100
  @secret_key.sign(message)
97
101
  end
98
102
 
99
103
  def sign_decorated(message)
100
104
  raw_signature = sign(message)
101
105
  Stellar::DecoratedSignature.new({
102
- hint: signature_hint,
106
+ hint: signature_hint,
103
107
  signature: raw_signature
104
108
  })
105
109
  end
@@ -111,6 +115,5 @@ module Stellar
111
115
  rescue RbNaCl::BadSignatureError
112
116
  false
113
117
  end
114
-
115
118
  end
116
119
  end
@@ -1,10 +1,8 @@
1
1
  module Stellar
2
2
  # Provides a container for well-known network passphrases, such as the main network and SDF test network
3
3
  module Networks
4
-
5
- PUBLIC = "Public Global Stellar Network ; September 2015"
4
+ PUBLIC = "Public Global Stellar Network ; September 2015"
6
5
  TESTNET = "Test SDF Network ; September 2015"
7
-
8
6
  end
9
7
 
10
8
  # Configures the default stellar network passphrase for the current process. Unless otherwise
@@ -23,15 +21,15 @@ module Stellar
23
21
  # Returns the passphrase for the currently-configured network, as set by Stellar.default_network
24
22
  # or Stellar.on_network
25
23
  def self.current_network
26
- Thread.current["stellar_network_passphrase"] ||
27
- @default_network ||
28
- Stellar::Networks::TESTNET
24
+ Thread.current["stellar_network_passphrase"] ||
25
+ @default_network ||
26
+ Stellar::Networks::TESTNET
29
27
  end
30
28
 
31
29
  # Returns the id for the currently configured network, suitable for use in generating
32
30
  # a signature base string or making the root account's keypair.
33
31
  def self.current_network_id
34
- Digest::SHA256.digest(self.current_network)
32
+ Digest::SHA256.digest(current_network)
35
33
  end
36
34
 
37
35
  # Executes the provided block in the context of the provided network.
@@ -1,444 +1,478 @@
1
- require 'bigdecimal'
1
+ require "bigdecimal"
2
2
 
3
3
  module Stellar
4
4
  class Operation
5
-
6
5
  MAX_INT64 = 2**63 - 1
7
6
 
8
- #
9
- # Construct a new Stellar::Operation from the provided
10
- # source account and body
11
- #
12
- # @param [Hash] attributes the attributes to create the operation with
13
- # @option attributes [Stellar::KeyPair] :source_account
14
- # @option attributes [Stellar::Operation::Body] :body
15
- #
16
- # @return [Stellar::Operation] the built operation
17
- def self.make(attributes={})
18
- source_account = attributes[:source_account]
19
- body = Stellar::Operation::Body.new(*attributes[:body])
20
-
21
- op = Stellar::Operation.new(body:body)
22
-
23
- if source_account
24
- raise ArgumentError, "Bad :source_account" unless source_account.is_a?(Stellar::KeyPair)
25
- op.source_account = source_account.account_id
7
+ class << self
8
+ #
9
+ # Construct a new Stellar::Operation from the provided
10
+ # source account and body
11
+ #
12
+ # @param [Hash] attributes the attributes to create the operation with
13
+ # @option attributes [Stellar::KeyPair] :source_account
14
+ # @option attributes [Stellar::Operation::Body] :body
15
+ #
16
+ # @return [Stellar::Operation] the built operation
17
+ def make(attributes = {})
18
+ source_account = attributes[:source_account]
19
+ body = Stellar::Operation::Body.new(*attributes[:body])
20
+
21
+ op = Stellar::Operation.new(body: body)
22
+
23
+ if source_account
24
+ raise ArgumentError, "Bad :source_account" unless source_account.is_a?(Stellar::KeyPair)
25
+ op.source_account = source_account.muxed_account
26
+ end
27
+
28
+ op
26
29
  end
27
30
 
28
- return op
29
- end
31
+ #
32
+ # Helper method to create a valid PaymentOp, wrapped
33
+ # in the necessary XDR structs to be included within a
34
+ # transactions `operations` array.
35
+ #
36
+ # @see Stellar::Asset
37
+ #
38
+ # @param [Hash] attributes the attributes to create the operation with
39
+ # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
40
+ # @option attributes [Array] :amount the amount to pay
41
+ # @return [Stellar::Operation] the built operation, containing a
42
+ # Stellar::PaymentOp body
43
+ def payment(attributes = {})
44
+ destination = attributes[:destination]
45
+ asset, amount = get_asset_amount(attributes[:amount])
46
+
47
+ raise ArgumentError unless destination.is_a?(KeyPair)
48
+
49
+ op = PaymentOp.new
50
+ op.asset = asset
51
+ op.amount = amount
52
+ op.destination = destination.muxed_account
53
+
54
+ make(attributes.merge({
55
+ body: [:payment, op]
56
+ }))
57
+ end
30
58
 
59
+ #
60
+ # Helper method to create a valid PathPaymentStrictReceiveOp, wrapped
61
+ # in the necessary XDR structs to be included within a
62
+ # transactions `operations` array.
63
+ #
64
+ # @deprecated Please use Operation.path_payment_strict_receive
65
+ #
66
+ # @see Stellar::Asset
67
+ #
68
+ # @param [Hash] attributes the attributes to create the operation with
69
+ # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
70
+ # @option attributes [Array] :amount the destination asset and the amount to pay
71
+ # @option attributes [Array] :with the source asset and maximum allowed source amount to pay with
72
+ # @option attributes [Array<Stellar::Asset>] :path the payment path to use
73
+ #
74
+ # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
75
+ #
76
+ def path_payment(attributes = {})
77
+ path_payment_strict_receive(attributes)
78
+ end
31
79
 
32
- #
33
- # Helper method to create a valid PaymentOp, wrapped
34
- # in the necessary XDR structs to be included within a
35
- # transactions `operations` array.
36
- #
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 self.payment(attributes={})
45
- destination = attributes[:destination]
46
- asset, amount = extract_amount(attributes[:amount])
47
-
48
- raise ArgumentError unless destination.is_a?(KeyPair)
49
-
50
-
51
- op = PaymentOp.new
52
- op.asset = asset
53
- op.amount = amount
54
- op.destination = destination.account_id
55
-
56
- return make(attributes.merge({
57
- body:[:payment, op]
58
- }))
59
- end
80
+ #
81
+ # Helper method to create a valid PathPaymentStrictReceiveOp, wrapped
82
+ # in the necessary XDR structs to be included within a
83
+ # transactions `operations` array.
84
+ #
85
+ # @see Stellar::Asset
86
+ #
87
+ # @param [Hash] attributes the attributes to create the operation with
88
+ # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
89
+ # @option attributes [Array] :amount the destination asset and the amount to pay
90
+ # @option attributes [Array] :with the source asset and maximum allowed source amount to pay with
91
+ # @option attributes [Array<Stellar::Asset>] :path the payment path to use
92
+ #
93
+ # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
94
+ #
95
+ def path_payment_strict_receive(attributes = {})
96
+ destination = attributes[:destination]
97
+ asset, amount = get_asset_amount(attributes[:amount])
98
+ send_asset, send_max = get_asset_amount(attributes[:with])
99
+ path = (attributes[:path] || []).map { |p|
100
+ p.is_a?(Array) ? Stellar::Asset.send(*p) : p
101
+ }
102
+
103
+ raise ArgumentError unless destination.is_a?(KeyPair)
104
+
105
+ op = PathPaymentStrictReceiveOp.new
106
+ op.send_asset = send_asset
107
+ op.send_max = send_max
108
+ op.destination = destination.muxed_account
109
+ op.dest_asset = asset
110
+ op.dest_amount = amount
111
+ op.path = path
112
+
113
+ make(attributes.merge({
114
+ body: [:path_payment_strict_receive, op]
115
+ }))
116
+ end
60
117
 
61
- #
62
- # Helper method to create a valid PathPaymentStrictReceiveOp, wrapped
63
- # in the necessary XDR structs to be included within a
64
- # transactions `operations` array.
65
- #
66
- # @deprecated Please use Operation.path_payment_strict_receive
67
- #
68
- # @see Stellar::Asset
69
- #
70
- # @param [Hash] attributes the attributes to create the operation with
71
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
72
- # @option attributes [Array] :amount the destination asset and the amount to pay
73
- # @option attributes [Array] :with the source asset and maximum allowed source amount to pay with
74
- # @option attributes [Array<Stellar::Asset>] :path the payment path to use
75
- #
76
- # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
77
- #
78
- def self.path_payment(attributes={})
79
- path_payment_strict_receive(attributes)
80
- end
118
+ #
119
+ # Helper method to create a valid PathPaymentStrictSendOp, wrapped
120
+ # in the necessary XDR structs to be included within a
121
+ # transactions `operations` array.
122
+ #
123
+ # @see Stellar::Asset
124
+ #
125
+ # @param [Hash] attributes the attributes to create the operation with
126
+ # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
127
+ # @option attributes [Array] :amount the destination asset and the minimum amount of destination asset to be received
128
+ # @option attributes [Array] :with the source asset and amount to pay with
129
+ # @option attributes [Array<Stellar::Asset>] :path the payment path to use
130
+ #
131
+ # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
132
+ #
133
+ def path_payment_strict_send(attributes = {})
134
+ destination = attributes[:destination]
135
+ asset, dest_min = get_asset_amount(attributes[:amount])
136
+ send_asset, send_amount = get_asset_amount(attributes[:with])
137
+ path = (attributes[:path] || []).map { |p|
138
+ p.is_a?(Array) ? Stellar::Asset.send(*p) : p
139
+ }
140
+
141
+ raise ArgumentError unless destination.is_a?(KeyPair)
142
+
143
+ op = PathPaymentStrictSendOp.new
144
+ op.send_asset = send_asset
145
+ op.send_amount = send_amount
146
+ op.destination = destination.muxed_account
147
+ op.dest_asset = asset
148
+ op.dest_min = dest_min
149
+ op.path = path
150
+
151
+ make(attributes.merge({
152
+ body: [:path_payment_strict_send, op]
153
+ }))
154
+ end
81
155
 
82
- #
83
- # Helper method to create a valid PathPaymentStrictReceiveOp, wrapped
84
- # in the necessary XDR structs to be included within a
85
- # transactions `operations` array.
86
- #
87
- # @see Stellar::Asset
88
- #
89
- # @param [Hash] attributes the attributes to create the operation with
90
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
91
- # @option attributes [Array] :amount the destination asset and the amount to pay
92
- # @option attributes [Array] :with the source asset and maximum allowed source amount to pay with
93
- # @option attributes [Array<Stellar::Asset>] :path the payment path to use
94
- #
95
- # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
96
- #
97
- def self.path_payment_strict_receive(attributes={})
98
- destination = attributes[:destination]
99
- asset, amount = extract_amount(attributes[:amount])
100
- send_asset, send_max = extract_amount(attributes[:with])
101
- path = (attributes[:path] || []).map{|p| Stellar::Asset.send(*p)}
102
-
103
- raise ArgumentError unless destination.is_a?(KeyPair)
104
-
105
- op = PathPaymentStrictReceiveOp.new
106
- op.send_asset = send_asset
107
- op.send_max = send_max
108
- op.destination = destination.account_id
109
- op.dest_asset = asset
110
- op.dest_amount = amount
111
- op.path = path
112
-
113
- return make(attributes.merge({
114
- body:[:path_payment_strict_receive, op]
115
- }))
116
- end
156
+ def create_account(attributes = {})
157
+ destination = attributes[:destination]
158
+ starting_balance = interpret_amount(attributes[:starting_balance])
117
159
 
118
- #
119
- # Helper method to create a valid PathPaymentStrictSendOp, wrapped
120
- # in the necessary XDR structs to be included within a
121
- # transactions `operations` array.
122
- #
123
- # @see Stellar::Asset
124
- #
125
- # @param [Hash] attributes the attributes to create the operation with
126
- # @option attributes [Stellar::KeyPair] :destination the receiver of the payment
127
- # @option attributes [Array] :amount the destination asset and the minimum amount of destination asset to be received
128
- # @option attributes [Array] :with the source asset and amount to pay with
129
- # @option attributes [Array<Stellar::Asset>] :path the payment path to use
130
- #
131
- # @return [Stellar::Operation] the built operation, containing a Stellar::PaymentOp body
132
- #
133
- def self.path_payment_strict_send(attributes={})
134
- destination = attributes[:destination]
135
- asset, dest_min = extract_amount(attributes[:amount])
136
- send_asset, send_amount = extract_amount(attributes[:with])
137
- path = (attributes[:path] || []).map{|p| Stellar::Asset.send(*p)}
138
-
139
- raise ArgumentError unless destination.is_a?(KeyPair)
140
-
141
- op = PathPaymentStrictSendOp.new
142
- op.send_asset = send_asset
143
- op.send_amount = send_amount
144
- op.destination = destination.account_id
145
- op.dest_asset = asset
146
- op.dest_min = dest_min
147
- op.path = path
148
-
149
- return make(attributes.merge({
150
- body:[:path_payment_strict_send, op]
151
- }))
152
- end
160
+ raise ArgumentError unless destination.is_a?(KeyPair)
153
161
 
154
- def self.create_account(attributes={})
155
- destination = attributes[:destination]
156
- starting_balance = interpret_amount(attributes[:starting_balance])
162
+ op = CreateAccountOp.new
163
+ op.destination = destination.account_id
164
+ op.starting_balance = starting_balance
157
165
 
158
- raise ArgumentError unless destination.is_a?(KeyPair)
166
+ make(attributes.merge({
167
+ body: [:create_account, op]
168
+ }))
169
+ end
159
170
 
160
- op = CreateAccountOp.new()
161
- op.destination = destination.account_id
162
- op.starting_balance = starting_balance
171
+ #
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
163
191
 
164
- return make(attributes.merge({
165
- body:[:create_account, op]
166
- }))
167
- end
192
+ limit = attributes.key?(:limit) ? interpret_amount(attributes[:limit]) : MAX_INT64
193
+
194
+ raise ArgumentError, "Bad :limit #{limit}" unless limit.is_a?(Integer)
168
195
 
169
- #
170
- # Helper method to create a valid ChangeTrustOp, wrapped
171
- # in the necessary XDR structs to be included within a
172
- # transactions `operations` array.
173
- #
174
- # @param [Hash] attributes the attributes to create the operation with
175
- # @option attributes [Stellar::Asset] :line the asset to trust
176
- # @option attributes [Fixnum] :limit the maximum amount to trust, defaults to max int64,
177
- # if the limit is set to 0 it deletes the trustline.
178
- #
179
- # @return [Stellar::Operation] the built operation, containing a
180
- # Stellar::ChangeTrustOp body
181
- def self.change_trust(attributes={})
182
- line = attributes[:line]
183
- if !line.is_a?(Asset)
184
- if !Asset::TYPES.include?(line[0])
185
- fail ArgumentError, "must be one of #{Asset::TYPES}"
196
+ op = ChangeTrustOp.new(line: line, limit: limit)
197
+
198
+ make(attributes.merge({
199
+ body: [:change_trust, op]
200
+ }))
201
+ end
202
+
203
+ def manage_sell_offer(attributes = {})
204
+ buying = attributes[:buying]
205
+ if buying.is_a?(Array)
206
+ buying = Asset.send(*buying)
207
+ end
208
+ selling = attributes[:selling]
209
+ if selling.is_a?(Array)
210
+ selling = Asset.send(*selling)
186
211
  end
187
- line = Asset.send(*line)
212
+ amount = interpret_amount(attributes[:amount])
213
+ offer_id = attributes[:offer_id] || 0
214
+ price = interpret_price(attributes[:price])
215
+
216
+ op = ManageSellOfferOp.new({
217
+ buying: buying,
218
+ selling: selling,
219
+ amount: amount,
220
+ price: price,
221
+ offer_id: offer_id
222
+ })
223
+
224
+ make(attributes.merge({
225
+ body: [:manage_sell_offer, op]
226
+ }))
188
227
  end
189
228
 
190
- limit = attributes.key?(:limit) ? interpret_amount(attributes[:limit]) : MAX_INT64
229
+ def manage_buy_offer(attributes = {})
230
+ buying = attributes[:buying]
231
+ if buying.is_a?(Array)
232
+ buying = Asset.send(*buying)
233
+ end
234
+ selling = attributes[:selling]
235
+ if selling.is_a?(Array)
236
+ selling = Asset.send(*selling)
237
+ end
238
+ amount = interpret_amount(attributes[:amount])
239
+ offer_id = attributes[:offer_id] || 0
240
+ price = interpret_price(attributes[:price])
241
+
242
+ op = ManageBuyOfferOp.new({
243
+ buying: buying,
244
+ selling: selling,
245
+ amount: amount,
246
+ price: price,
247
+ offer_id: offer_id
248
+ })
249
+
250
+ make(attributes.merge({
251
+ body: [:manage_buy_offer, op]
252
+ }))
253
+ end
191
254
 
192
- raise ArgumentError, "Bad :limit #{limit}" unless limit.is_a?(Integer)
255
+ def create_passive_sell_offer(attributes = {})
256
+ buying = attributes[:buying]
257
+ if buying.is_a?(Array)
258
+ buying = Asset.send(*buying)
259
+ end
260
+ selling = attributes[:selling]
261
+ if selling.is_a?(Array)
262
+ selling = Asset.send(*selling)
263
+ end
264
+ amount = interpret_amount(attributes[:amount])
265
+ price = interpret_price(attributes[:price])
266
+
267
+ op = CreatePassiveSellOfferOp.new({
268
+ buying: buying,
269
+ selling: selling,
270
+ amount: amount,
271
+ price: price
272
+ })
273
+
274
+ make(attributes.merge({
275
+ body: [:create_passive_sell_offer, op]
276
+ }))
277
+ end
193
278
 
194
- op = ChangeTrustOp.new(line: line, limit: limit)
279
+ #
280
+ # Helper method to create a valid SetOptionsOp, wrapped
281
+ # in the necessary XDR structs to be included within a
282
+ # transactions `operations` array.
283
+ #
284
+ # @param [Hash] attributes the attributes to create the operation with
285
+ # @option attributes [Stellar::KeyPair] :inflation_dest
286
+ # @option attributes [Array<Stellar::AccountFlags>] :set flags to set
287
+ # @option attributes [Array<Stellar::AccountFlags>] :clear flags to clear
288
+ # @option attributes [String] :thresholds
289
+ # @option attributes [Stellar::Signer] :signer
290
+ #
291
+ # @return [Stellar::Operation] the built operation, containing a
292
+ # Stellar::SetOptionsOp body
293
+ def set_options(attributes = {})
294
+ op = SetOptionsOp.new
295
+ op.set_flags = Stellar::AccountFlags.make_mask attributes[:set]
296
+ op.clear_flags = Stellar::AccountFlags.make_mask attributes[:clear]
297
+ op.master_weight = attributes[:master_weight]
298
+ op.low_threshold = attributes[:low_threshold]
299
+ op.med_threshold = attributes[:med_threshold]
300
+ op.high_threshold = attributes[:high_threshold]
301
+
302
+ op.signer = attributes[:signer]
303
+ op.home_domain = attributes[:home_domain]
304
+
305
+ inflation_dest = attributes[:inflation_dest]
306
+ if inflation_dest
307
+ raise ArgumentError, "Bad :inflation_dest" unless inflation_dest.is_a?(Stellar::KeyPair)
308
+ op.inflation_dest = inflation_dest.account_id
309
+ end
195
310
 
196
- return make(attributes.merge({
197
- body:[:change_trust, op]
198
- }))
199
- end
311
+ make(attributes.merge({
312
+ body: [:set_options, op]
313
+ }))
314
+ end
200
315
 
201
- def self.manage_sell_offer(attributes={})
202
- buying = Asset.send(*attributes[:buying])
203
- selling = Asset.send(*attributes[:selling])
204
- amount = interpret_amount(attributes[:amount])
205
- offer_id = attributes[:offer_id] || 0
206
- price = interpret_price(attributes[:price])
207
-
208
- op = ManageSellOfferOp.new({
209
- buying: buying,
210
- selling: selling,
211
- amount: amount,
212
- price: price,
213
- offer_id: offer_id
214
- })
215
-
216
- return make(attributes.merge({
217
- body:[:manage_sell_offer, op]
218
- }))
219
- end
316
+ #
317
+ # Helper method to create a valid AllowTrustOp, wrapped
318
+ # in the necessary XDR structs to be included within a
319
+ # transactions `operations` array.
320
+ #
321
+ # @param [Hash] attributes the attributes to create the operation with
322
+ # @option attributes [Stellar::KeyPair] :trustor
323
+ # @option attributes [Stellar::Asset] :asset
324
+ # @option attributes [Symbol, Boolean] :authorize :full, maintain_liabilities or :none
325
+ #
326
+ # @return [Stellar::Operation] the built operation, containing a
327
+ # Stellar::AllowTrustOp body
328
+ def allow_trust(attributes = {})
329
+ op = AllowTrustOp.new
330
+
331
+ trustor = attributes[:trustor]
332
+ authorize = attributes[:authorize]
333
+ asset = attributes[:asset]
334
+ if asset.is_a?(Array)
335
+ asset = Asset.send(*asset)
336
+ end
220
337
 
221
- def self.manage_buy_offer(attributes={})
222
- buying = Asset.send(*attributes[:buying])
223
- selling = Asset.send(*attributes[:selling])
224
- amount = interpret_amount(attributes[:amount])
225
- offer_id = attributes[:offer_id] || 0
226
- price = interpret_price(attributes[:price])
227
-
228
- op = ManageBuyOfferOp.new({
229
- buying: buying,
230
- selling: selling,
231
- amount: amount,
232
- price: price,
233
- offer_id: offer_id
234
- })
235
-
236
- return make(attributes.merge({
237
- body:[:manage_buy_offer, op]
238
- }))
239
- end
338
+ raise ArgumentError, "Bad :trustor" unless trustor.is_a?(Stellar::KeyPair)
240
339
 
241
- def self.create_passive_sell_offer(attributes={})
242
- buying = Asset.send(*attributes[:buying])
243
- selling = Asset.send(*attributes[:selling])
244
- amount = interpret_amount(attributes[:amount])
245
- price = interpret_price(attributes[:price])
246
-
247
- op = CreatePassiveSellOfferOp.new({
248
- buying: buying,
249
- selling: selling,
250
- amount: amount,
251
- price: price,
252
- })
253
-
254
- return make(attributes.merge({
255
- body:[:create_passive_sell_offer, op]
256
- }))
257
- end
340
+ op.authorize = case authorize
341
+ when :none, false then 0 # we handle booleans here for the backward compatibility
342
+ when :full, true then TrustLineFlags.authorized_flag.value
343
+ when :maintain_liabilities then TrustLineFlags.authorized_to_maintain_liabilities_flag.value
344
+ else
345
+ raise ArgumentError, "Bad :authorize, supported values: :full, :maintain_liabilities, :none"
346
+ end
258
347
 
259
- #
260
- # Helper method to create a valid SetOptionsOp, wrapped
261
- # in the necessary XDR structs to be included within a
262
- # transactions `operations` array.
263
- #
264
- # @param [Hash] attributes the attributes to create the operation with
265
- # @option attributes [Stellar::KeyPair] :inflation_dest
266
- # @option attributes [Array<Stellar::AccountFlags>] :set flags to set
267
- # @option attributes [Array<Stellar::AccountFlags>] :clear flags to clear
268
- # @option attributes [String] :thresholds
269
- # @option attributes [Stellar::Signer] :signer
270
- #
271
- # @return [Stellar::Operation] the built operation, containing a
272
- # Stellar::SetOptionsOp body
273
- def self.set_options(attributes={})
274
- op = SetOptionsOp.new()
275
- op.set_flags = Stellar::AccountFlags.make_mask attributes[:set]
276
- op.clear_flags = Stellar::AccountFlags.make_mask attributes[:clear]
277
- op.master_weight = attributes[:master_weight]
278
- op.low_threshold = attributes[:low_threshold]
279
- op.med_threshold = attributes[:med_threshold]
280
- op.high_threshold = attributes[:high_threshold]
281
-
282
- op.signer = attributes[:signer]
283
- op.home_domain = attributes[:home_domain]
284
-
285
-
286
- inflation_dest = attributes[:inflation_dest]
287
- if inflation_dest
288
- raise ArgumentError, "Bad :inflation_dest" unless inflation_dest.is_a?(Stellar::KeyPair)
289
- op.inflation_dest = inflation_dest.account_id
290
- end
348
+ raise ArgumentError, "Bad :asset" unless asset.type == Stellar::AssetType.asset_type_credit_alphanum4
291
349
 
350
+ atc = AllowTrustOp::Asset.new(:asset_type_credit_alphanum4, asset.code)
292
351
 
293
- return make(attributes.merge({
294
- body:[:set_options, op]
295
- }))
296
- end
352
+ op.trustor = trustor.account_id
353
+ op.asset = atc
297
354
 
298
- #
299
- # Helper method to create a valid AllowTrustOp, wrapped
300
- # in the necessary XDR structs to be included within a
301
- # transactions `operations` array.
302
- #
303
- # @param [Hash] attributes the attributes to create the operation with
304
- # @option attributes [Stellar::KeyPair] :trustor
305
- # @option attributes [Stellar::Asset] :asset
306
- #
307
- # @return [Stellar::Operation] the built operation, containing a
308
- # Stellar::AllowTrustOp body
309
- def self.allow_trust(attributes={})
310
- op = AllowTrustOp.new()
311
-
312
- trustor = attributes[:trustor]
313
- authorize = attributes[:authorize]
314
- asset = Asset.send(*attributes[:asset])
315
-
316
- raise ArgumentError, "Bad :trustor" unless trustor.is_a?(Stellar::KeyPair)
317
- raise ArgumentError, "Bad :authorize" unless authorize == !!authorize # check boolean
318
- raise ArgumentError, "Bad :asset" unless asset.type == Stellar::AssetType.asset_type_credit_alphanum4
319
-
320
- atc = AllowTrustOp::Asset.new(:asset_type_credit_alphanum4, asset.code)
321
-
322
- op.trustor = trustor.account_id
323
- op.authorize = authorize
324
- op.asset = atc
325
-
326
- return make(attributes.merge({
327
- body:[:allow_trust, op]
328
- }))
329
- end
355
+ make(attributes.merge({
356
+ body: [:allow_trust, op]
357
+ }))
358
+ end
330
359
 
331
- #
332
- # Helper method to create an account merge operation
333
- #
334
- # @param [Hash] attributes the attributes to create the operation with
335
- # @option attributes [Stellar::KeyPair] :destination
336
- #
337
- # @return [Stellar::Operation] the built operation
338
- def self.account_merge(attributes={})
339
- destination = attributes[:destination]
340
-
341
- raise ArgumentError, "Bad :destination" unless destination.is_a?(KeyPair)
342
-
343
- # TODO: add source_account support
344
- return make(attributes.merge({
345
- body:[:account_merge, destination.account_id]
346
- }))
347
- end
360
+ #
361
+ # Helper method to create an account merge operation
362
+ #
363
+ # @param [Hash] attributes the attributes to create the operation with
364
+ # @option attributes [Stellar::KeyPair] :destination
365
+ #
366
+ # @return [Stellar::Operation] the built operation
367
+ def account_merge(attributes = {})
368
+ destination = attributes[:destination]
369
+
370
+ raise ArgumentError, "Bad :destination" unless destination.is_a?(KeyPair)
371
+
372
+ # TODO: add source_account support
373
+ make(attributes.merge({
374
+ body: [:account_merge, destination.muxed_account]
375
+ }))
376
+ end
348
377
 
349
- #
350
- # Helper method to create an inflation operation
351
- #
352
- # @param [Hash] attributes the attributes to create the operation with
353
- # @option attributes [Integer] :sequence
354
- #
355
- # @return [Stellar::Operation] the built operation
356
- def self.inflation(attributes={})
357
- sequence = attributes[:sequence]
358
-
359
- raise ArgumentError, "Bad :sequence #{sequence}" unless sequence.is_a?(Integer)
360
-
361
- # TODO: add source_account support
362
- return make(attributes.merge({
363
- body:[:inflation]
364
- }))
365
- end
378
+ #
379
+ # Helper method to create an inflation operation
380
+ #
381
+ # @param [Hash] attributes the attributes to create the operation with
382
+ # @option attributes [Integer] :sequence
383
+ #
384
+ # @return [Stellar::Operation] the built operation
385
+ def inflation(attributes = {})
386
+ sequence = attributes[:sequence]
387
+
388
+ raise ArgumentError, "Bad :sequence #{sequence}" unless sequence.is_a?(Integer)
389
+
390
+ # TODO: add source_account support
391
+ make(attributes.merge({
392
+ body: [:inflation]
393
+ }))
394
+ end
366
395
 
367
- #
368
- # Helper method to create an manage data operation
369
- #
370
- # @param [Hash] attributes the attributes to create the operation with
371
- # @option attributes [Integer] :sequence
372
- #
373
- # @return [Stellar::Operation] the built operation
374
- def self.manage_data(attributes={})
375
- op = ManageDataOp.new()
396
+ #
397
+ # Helper method to create an manage data operation
398
+ #
399
+ # @param [Hash] attributes the attributes to create the operation with
400
+ # @option attributes [Integer] :sequence
401
+ #
402
+ # @return [Stellar::Operation] the built operation
403
+ def manage_data(attributes = {})
404
+ op = ManageDataOp.new
376
405
 
377
- name = attributes[:name]
378
- value = attributes[:value]
406
+ name = attributes[:name]
407
+ value = attributes[:value]
379
408
 
380
- raise ArgumentError, "Invalid :name" unless name.is_a?(String)
381
- raise ArgumentError, ":name too long" unless name.bytesize <= 64
409
+ raise ArgumentError, "Invalid :name" unless name.is_a?(String)
410
+ raise ArgumentError, ":name too long" unless name.bytesize <= 64
382
411
 
383
- if value.present?
384
- raise ArgumentError, ":value too long" unless value.bytesize <= 64
385
- end
412
+ if value.present?
413
+ raise ArgumentError, ":value too long" unless value.bytesize <= 64
414
+ end
386
415
 
387
- op.data_name = name
388
- op.data_value = value
416
+ op.data_name = name
417
+ op.data_value = value
389
418
 
390
- return make(attributes.merge({
391
- body:[:manage_data, op]
392
- }))
393
- end
419
+ make(attributes.merge({
420
+ body: [:manage_data, op]
421
+ }))
422
+ end
394
423
 
395
- def self.bump_sequence(attributes={})
396
- op = BumpSequenceOp.new()
424
+ def bump_sequence(attributes = {})
425
+ op = BumpSequenceOp.new
397
426
 
398
- bump_to = attributes[:bump_to]
427
+ bump_to = attributes[:bump_to]
399
428
 
400
- raise ArgumentError, ":bump_to too big" unless bump_to <= MAX_INT64
429
+ raise ArgumentError, ":bump_to too big" unless bump_to <= MAX_INT64
401
430
 
402
- op.bump_to = bump_to
431
+ op.bump_to = bump_to
403
432
 
404
- return make(attributes.merge({
405
- body:[:bump_sequence, op]
406
- }))
407
- end
433
+ make(attributes.merge({
434
+ body: [:bump_sequence, op]
435
+ }))
436
+ end
408
437
 
409
- private
410
- def self.extract_amount(a)
411
- amount = interpret_amount(a.last)
412
- asset = Stellar::Asset.send(*a[0...-1])
438
+ private
413
439
 
414
- return asset, amount
415
- end
440
+ def get_asset_amount(values)
441
+ amount = interpret_amount(values.last)
442
+ asset = if values[0].is_a?(Stellar::Asset)
443
+ values.first
444
+ else
445
+ Stellar::Asset.send(*values[0...-1])
446
+ end
416
447
 
417
- def self.interpret_amount(amount)
418
- case amount
419
- when String
420
- (BigDecimal(amount) * Stellar::ONE).floor
421
- when Integer
422
- amount * Stellar::ONE
423
- when Numeric
424
- (amount * Stellar::ONE).floor
425
- else
426
- raise ArgumentError, "Invalid amount type: #{amount.class}. Must be String or Numeric"
448
+ [asset, amount]
427
449
  end
428
- end
429
450
 
451
+ def interpret_amount(amount)
452
+ case amount
453
+ when String
454
+ (BigDecimal(amount) * Stellar::ONE).floor
455
+ when Integer
456
+ amount * Stellar::ONE
457
+ when Numeric
458
+ (amount * Stellar::ONE).floor
459
+ else
460
+ raise ArgumentError, "Invalid amount type: #{amount.class}. Must be String or Numeric"
461
+ end
462
+ end
430
463
 
431
- def self.interpret_price(price)
432
- case price
433
- when String
434
- bd = BigDecimal.new(price)
435
- Price.from_f(bd)
436
- when Numeric
437
- Price.from_f(price)
438
- when Stellar::Price
439
- price
440
- else
441
- raise ArgumentError, "Invalid price type: #{price.class}. Must be String, Numeric, or Stellar::Price"
464
+ def interpret_price(price)
465
+ case price
466
+ when String
467
+ bd = BigDecimal(price)
468
+ Price.from_f(bd)
469
+ when Numeric
470
+ Price.from_f(price)
471
+ when Stellar::Price
472
+ price
473
+ else
474
+ raise ArgumentError, "Invalid price type: #{price.class}. Must be String, Numeric, or Stellar::Price"
475
+ end
442
476
  end
443
477
  end
444
478
  end