stellar-sdk 0.4.0 → 0.9.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -2
  3. data/{LICENSE.txt → LICENSE} +0 -0
  4. data/README.md +17 -11
  5. data/lib/stellar-sdk.rb +3 -4
  6. data/lib/stellar/account.rb +16 -18
  7. data/lib/stellar/amount.rb +9 -13
  8. data/lib/stellar/client.rb +255 -74
  9. data/lib/stellar/horizon/problem.rb +14 -16
  10. data/lib/stellar/sep10.rb +347 -0
  11. data/lib/stellar/transaction_page.rb +4 -6
  12. data/lib/stellar/version.rb +1 -1
  13. metadata +17 -203
  14. data/.gitignore +0 -16
  15. data/.travis.yml +0 -13
  16. data/.yardopts +0 -7
  17. data/CONTRIBUTING.md +0 -48
  18. data/Gemfile +0 -14
  19. data/Guardfile +0 -5
  20. data/Rakefile +0 -3
  21. data/examples/01_get_funded.rb +0 -37
  22. data/examples/02_payment.rb +0 -15
  23. data/examples/03_transaction_history.rb +0 -21
  24. data/examples/04_setting_trust.rb +0 -12
  25. data/examples/05_fiat_payment.rb +0 -13
  26. data/examples/06_fund_testnet_friendbot.rb +0 -15
  27. data/ruby-stellar-sdk.gemspec +0 -36
  28. data/spec/config.yml.sample +0 -10
  29. data/spec/fixtures/vcr_cassettes/Stellar_Account/_lookup/should_handle_404_request_when_performing_federation_lookup.yml +0 -133
  30. data/spec/fixtures/vcr_cassettes/Stellar_Account/_lookup/should_handle_domains_that_are_not_federation_servers.yml +0 -44
  31. data/spec/fixtures/vcr_cassettes/Stellar_Account/_lookup/should_peforms_federation_lookup.yml +0 -85
  32. data/spec/fixtures/vcr_cassettes/Stellar_Client/_account_info/returns_the_current_details_for_the_account.yml +0 -190
  33. data/spec/fixtures/vcr_cassettes/Stellar_Client/_create_account/creates_the_account.yml +0 -323
  34. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/alphanum12_asset/sends_a_alphanum12_asset_to_the_destination.yml +0 -448
  35. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/alphanum4_asset/sends_a_alphanum4_asset_to_the_destination.yml +0 -448
  36. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/native_asset/sends_a_native_payment_to_the_account.yml +0 -469
  37. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/account_transactions/accepts_a_cursor_to_return_less_data.yml +0 -94
  38. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/account_transactions/returns_a_list_of_transaction_for_an_account.yml +0 -94
  39. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/all_transactions/accepts_a_cursor_to_return_less_data.yml +0 -94
  40. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/all_transactions/returns_a_list_of_transactions.yml +0 -94
  41. data/spec/lib/stellar/account_spec.rb +0 -59
  42. data/spec/lib/stellar/amount_spec.rb +0 -70
  43. data/spec/lib/stellar/client_spec.rb +0 -173
  44. data/spec/spec_helper.rb +0 -14
  45. data/spec/support/config.rb +0 -3
  46. data/spec/support/vcr.rb +0 -10
  47. data/tasks/rspec.rake +0 -6
  48. data/tasks/travis.rake +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f3c1d917a218343ba852380651053255ddc4aa0293d96cfee5ef4856d5aa9fe2
4
- data.tar.gz: 69f8d0f5e220140e02527ff284877a424c284065e3f397a88f28221d2c73af69
3
+ metadata.gz: 3da720d62d3ed03b2eba1ac3e1bcc733da7013952120bcbc2feb31ec53c2eb90
4
+ data.tar.gz: d23901b3e1d9b6d3107cdeae940dda89ca19c180efd3c63be07823493c5c147e
5
5
  SHA512:
6
- metadata.gz: e4cb249129ec6e825c83d54a095e255f27e91ef7d3202efd66bceab1fd6fb06095feb82b6a1f5f56210c7c87e6db0a2e030dd285364152ea904c65c95cb46fd1
7
- data.tar.gz: 5e0a36fdd2c0de489a39d8582d54f4495db4dbbaf8079c6656d1e96bac19fac3febc08eb19566f75d12c38b4929f2d76e196a374499bc89246c36a84df43d7c3
6
+ metadata.gz: c944e5f554aa13148f1268d6a7d5adaf1f61f942234ae6c87eebce880cc9f419edbfecb384bb76129ef41782c6647667ece34b5bb9fab8b18e04a6e7de068532
7
+ data.tar.gz: dc25b0c39c815dd3817272547d98df7400ad97f55c70e7adc1b72b55661f16d62ea733413b0375c77562586cb025dcbc1b67b049418ac4bb9224e1ae977eaad8
@@ -4,10 +4,29 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
- ## [Unreleased]
7
+ ## [0.8.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.7.0...v0.8.0)
8
+ ### Added
9
+ - SEP-10 Multisig Support [#69](https://github.com/stellar/ruby-stellar-sdk/pull/69)
10
+ - `X-Client-Name` and `X-Client-Version` headers
11
+
12
+ ## [0.7.0] - 2019-04-26
13
+ ### Added
14
+ - Friendbot support
15
+
16
+ ## [0.6.0] - 2018-11-27
17
+ ### Added
18
+ - Allow setting of memo in `Stellar::Client#send_payment`
19
+ - Optionally send payments through a payment channel with `Stellar::Client#send_payment`
20
+ - Clarify variable names for payment channels in `#send_payment`
21
+
22
+ ## [0.5.0] - 2018-07-10
8
23
  ### Changed
9
- - Update stellar-base to `~> 0.12.0`
24
+ - Update stellar-base to `>= 0.16.0`
25
+ - Update hyperclient, excon, contracts, activesupport
10
26
 
11
27
  ### Fixed
12
28
  - `#create_account`, along with `#send_payment`
13
29
 
30
+ ### Added
31
+ - `Stellar::Client#change_trust` to create, update, delete a trustline
32
+ - `Stellar::Client#account_merge` to merge accounts
File without changes
data/README.md CHANGED
@@ -1,27 +1,24 @@
1
1
  # Ruby Stellar
2
2
 
3
- [![Build Status](https://travis-ci.org/stellar/ruby-stellar-sdk.svg)](https://travis-ci.org/stellar/ruby-stellar-sdk)
4
- [![Code Climate](https://codeclimate.com/github/stellar/ruby-stellar-sdk/badges/gpa.svg)](https://codeclimate.com/github/stellar/ruby-stellar-sdk)
5
-
6
- *STATUS: this library is very early and incomplete. The examples provided do not work, yet*
3
+ [![Build Status](https://travis-ci.org/bloom-solutions/ruby-stellar-sdk.svg)](https://travis-ci.org/bloom-solutions/ruby-stellar-sdk)
4
+ [![Code Climate](https://codeclimate.com/github/bloom-solutions/ruby-stellar-sdk/badges/gpa.svg)](https://codeclimate.com/github/bloom-solutions/ruby-stellar-sdk)
7
5
 
8
6
  This library helps you to integrate your application into the [Stellar network](http://stellar.org).
9
7
 
10
8
  ## Installation
11
9
 
12
- Add this line to your application's Gemfile:
10
+ Add this lines to your application's Gemfile:
13
11
 
14
12
  ```ruby
15
13
  gem 'stellar-sdk'
14
+ gem 'xdr', git: 'https://github.com/stellar/ruby-xdr.git', tag: 'v3.0.1'
16
15
  ```
17
16
 
18
17
  And then execute:
19
18
 
20
19
  $ bundle
21
-
22
- Or install it yourself as:
23
-
24
- $ gem install stellar-sdk
20
+
21
+ **Note** we need to add such explicit `xdr` dependency, because version 3.0.1 is not on RubyGems yet. When it's published, you can remove this line
25
22
 
26
23
  Also requires libsodium. Installable via `brew install libsodium` on OS X.
27
24
 
@@ -45,16 +42,25 @@ client.send_payment({
45
42
  })
46
43
  ```
47
44
 
45
+ Be sure to set the network when submitting to the public network (more information in [stellar-base](https://www.github.com/bloom-solutions/ruby-stellar-base)):
46
+
47
+ ```ruby
48
+ Stellar.default_network = Stellar::Networks::PUBLIC
49
+ ```
50
+
48
51
  ## Development
49
52
 
53
+ - Install and activate [rvm](https://rvm.io/rvm/install)
54
+ - Ensure your `bundler` version is up-to-date: `gem install bundler`
55
+ - Run `bundle install`
50
56
  - Copy `spec/config.yml.sample` to `spec/config.yml`
51
57
  - Replace anything in `spec/config.yml` especially if you will re-record specs
52
- - `rspec spec`
58
+ - `bundle exec rspec spec`
53
59
 
54
60
  ## Contributing
55
61
 
56
62
  1. Sign the [Contributor License Agreement](https://docs.google.com/forms/d/1g7EF6PERciwn7zfmfke5Sir2n10yddGGSXyZsq98tVY/viewform?usp=send_form)
57
- 2. Fork it ( https://github.com/stellar/ruby-stellar-lib/fork )
63
+ 2. Fork it ( https://github.com/bloom-solutions/ruby-stellar-lib/fork )
58
64
  2. Create your feature branch (`git checkout -b my-new-feature`)
59
65
  3. Commit your changes (`git commit -am 'Add some feature'`)
60
66
  4. Push to the branch (`git push origin my-new-feature`)
@@ -1,12 +1,11 @@
1
- require 'stellar-base'
2
- require 'contracts'
1
+ require "stellar-base"
2
+ require_relative "./stellar/version"
3
3
 
4
4
  module Stellar
5
-
6
5
  autoload :Account
7
- autoload :AccountInfo
8
6
  autoload :Amount
9
7
  autoload :Client
8
+ autoload :SEP10
10
9
 
11
10
  module Horizon
12
11
  extend ActiveSupport::Autoload
@@ -1,12 +1,10 @@
1
- require 'toml-rb'
2
- require 'uri'
3
- require 'faraday'
4
- require 'json'
1
+ require "toml-rb"
2
+ require "uri"
3
+ require "faraday"
4
+ require "json"
5
5
 
6
6
  module Stellar
7
7
  class Account
8
- include Contracts
9
-
10
8
  delegate :address, to: :keypair
11
9
 
12
10
  def self.random
@@ -25,7 +23,7 @@ module Stellar
25
23
  end
26
24
 
27
25
  def self.lookup(federated_name)
28
- _, domain = federated_name.split('*')
26
+ _, domain = federated_name.split("*")
29
27
  if domain.nil?
30
28
  raise InvalidFederationAddress.new
31
29
  end
@@ -33,25 +31,25 @@ module Stellar
33
31
  domain_req = Faraday.new("https://#{domain}/.well-known/stellar.toml").get
34
32
 
35
33
  unless domain_req.status == 200
36
- raise InvalidStellarDomain.new('Domain does not contain stellar.toml file')
34
+ raise InvalidStellarDomain.new("Domain does not contain stellar.toml file")
37
35
  end
38
-
36
+
39
37
  fed_server_url = TomlRB.parse(domain_req.body)["FEDERATION_SERVER"]
40
38
  if fed_server_url.nil?
41
- raise InvalidStellarTOML.new('Invalid Stellar TOML file')
39
+ raise InvalidStellarTOML.new("Invalid Stellar TOML file")
42
40
  end
43
41
 
44
- unless fed_server_url =~ URI::regexp
45
- raise InvalidFederationURL.new('Invalid Federation Server URL')
42
+ unless fed_server_url&.match?(URI::DEFAULT_PARSER.make_regexp)
43
+ raise InvalidFederationURL.new("Invalid Federation Server URL")
46
44
  end
47
45
 
48
- lookup_req = Faraday.new(fed_server_url).get do |req|
46
+ lookup_req = Faraday.new(fed_server_url).get { |req|
49
47
  req.params[:q] = federated_name
50
- req.params[:type] = 'name'
51
- end
48
+ req.params[:type] = "name"
49
+ }
52
50
 
53
51
  unless lookup_req.status == 200
54
- raise AccountNotFound.new('Account not found')
52
+ raise AccountNotFound.new("Account not found")
55
53
  end
56
54
 
57
55
  JSON.parse(lookup_req.body)["account_id"]
@@ -64,7 +62,7 @@ module Stellar
64
62
 
65
63
  attr_reader :keypair
66
64
 
67
- Contract Stellar::KeyPair => Any
65
+ # @param [Stellar::KeyPair] keypair
68
66
  def initialize(keypair)
69
67
  @keypair = keypair
70
68
  end
@@ -84,4 +82,4 @@ module Stellar
84
82
 
85
83
  class InvalidFederationURL < StandardError
86
84
  end
87
- end
85
+ end
@@ -1,25 +1,21 @@
1
1
  module Stellar
2
2
  class Amount
3
- include Contracts
4
-
5
3
  attr_reader :amount
6
4
  attr_reader :asset
7
5
 
8
- Contract Pos, Asset => Any
9
- def initialize(amount, asset=Stellar::Asset.native())
6
+ # @param [Fixnum] amount
7
+ # @param [Stellar::Asset] asset
8
+ def initialize(amount, asset = Stellar::Asset.native)
10
9
  # TODO: how are we going to handle decimal considerations?
11
-
10
+
12
11
  @amount = amount
13
- @asset = asset
12
+ @asset = asset
14
13
  end
15
14
 
16
-
17
- Contract None => Or[
18
- [Or[:alphanum4, :alphanum12], String, KeyPair, Pos],
19
- [:native, Pos],
20
- ]
15
+ # @return [Array(Symbol, Fixnum)] in case of a native asset
16
+ # @return [Array(Symbol, String, Stellar::KeyPair, Fixnum)] in case of alphanum asset
21
17
  def to_payment
22
- case asset.type
18
+ case asset.type
23
19
  when AssetType.asset_type_native
24
20
  [:native, amount]
25
21
  when AssetType.asset_type_credit_alphanum4
@@ -34,7 +30,7 @@ module Stellar
34
30
  end
35
31
 
36
32
  def inspect
37
- "#<Stellar::Amount #{asset}(#{amount})>"
33
+ "#<Stellar::Amount #{asset}(#{amount})>"
38
34
  end
39
35
  end
40
36
  end
@@ -1,34 +1,51 @@
1
- require 'hyperclient'
1
+ require "hyperclient"
2
+ require "active_support/core_ext/object/blank"
3
+ require "securerandom"
2
4
 
3
5
  module Stellar
6
+ class AccountRequiresMemoError < StandardError
7
+ attr_reader :account_id, :operation_index
8
+
9
+ def initialize(message, account_id, operation_index)
10
+ super(message)
11
+ @account_id = account_id
12
+ @operation_index = operation_index
13
+ end
14
+ end
15
+
4
16
  class Client
5
- include Contracts
17
+ DEFAULT_FEE = 100
6
18
 
7
- def self.default(options={})
8
- new options.merge({
9
- horizon: "https://horizon.stellar.org"
10
- })
19
+ HORIZON_LOCALHOST_URL = "http://127.0.0.1:8000"
20
+ HORIZON_MAINNET_URL = "https://horizon.stellar.org"
21
+ HORIZON_TESTNET_URL = "https://horizon-testnet.stellar.org"
22
+ FRIENDBOT_URL = "https://friendbot.stellar.org".freeze
23
+
24
+ def self.default(options = {})
25
+ new options.merge(
26
+ horizon: HORIZON_MAINNET_URL
27
+ )
11
28
  end
12
29
 
13
- def self.default_testnet(options={})
14
- new options.merge({
15
- horizon: "https://horizon-testnet.stellar.org",
16
- friendbot: "https://horizon-testnet.stellar.org",
17
- })
30
+ def self.default_testnet(options = {})
31
+ new options.merge(
32
+ horizon: HORIZON_TESTNET_URL,
33
+ friendbot: HORIZON_TESTNET_URL
34
+ )
18
35
  end
19
36
 
20
- def self.localhost(options={})
21
- new options.merge({
22
- horizon: "http://127.0.0.1:8000"
23
- })
37
+ def self.localhost(options = {})
38
+ new options.merge(
39
+ horizon: HORIZON_LOCALHOST_URL
40
+ )
24
41
  end
25
42
 
26
43
  attr_reader :horizon
27
44
 
28
- Contract ({horizon: String}) => Any
45
+ # @option options [String] :horizon The Horizon server URL.
29
46
  def initialize(options)
30
47
  @options = options
31
- @horizon = Hyperclient.new(options[:horizon]) do |client|
48
+ @horizon = Hyperclient.new(options[:horizon]) { |client|
32
49
  client.faraday_block = lambda do |conn|
33
50
  conn.use Faraday::Response::RaiseError
34
51
  conn.use FaradayMiddleware::FollowRedirects
@@ -37,71 +54,106 @@ module Stellar
37
54
  conn.adapter :excon
38
55
  end
39
56
  client.headers = {
40
- 'Accept' => 'application/hal+json,application/problem+json,application/json'
57
+ "Accept" => "application/hal+json,application/problem+json,application/json",
58
+ "X-Client-Name" => "ruby-stellar-sdk",
59
+ "X-Client-Version" => VERSION
41
60
  }
61
+ }
62
+ end
63
+
64
+ # @param [Stellar::Account|String] account_or_address
65
+ def account_info(account_or_address)
66
+ account_id = if account_or_address.is_a?(Stellar::Account)
67
+ account_or_address.address
68
+ else
69
+ account_or_address
42
70
  end
71
+ @horizon.account(account_id: account_id)._get
72
+ end
73
+
74
+ # @option options [Stellar::Account] :account
75
+ # @option options [Stellar::Account] :destination
76
+ def account_merge(options = {})
77
+ account = options[:account]
78
+ destination = options[:destination]
79
+ sequence = options[:sequence] || (account_info(account).sequence.to_i + 1)
80
+
81
+ transaction = Stellar::TransactionBuilder.new(
82
+ source_account: destination.keypair,
83
+ sequence_number: sequence
84
+ ).add_operation(
85
+ Stellar::Operation.account_merge(destination: destination.keypair)
86
+ ).set_timeout(0).build
87
+
88
+ envelope = transaction.to_envelope(account.keypair)
89
+ submit_transaction(tx_envelope: envelope)
43
90
  end
44
91
 
45
92
  def friendbot(account)
46
- raise NotImplementedError
47
- end
48
-
49
- Contract Stellar::Account => Any
50
- def account_info(account)
51
- account_id = account.address
52
- @horizon.account(account_id:account_id)._get
53
- end
54
-
55
- Contract ({
56
- from: Stellar::Account,
57
- to: Stellar::Account,
58
- amount: Stellar::Amount
59
- }) => Any
60
- def send_payment(options={})
61
- from = options[:from]
62
- sequence = options[:sequence] || (account_info(from).sequence.to_i + 1)
63
-
64
- payment = Stellar::Transaction.payment({
65
- account: from.keypair,
66
- destination: options[:to].keypair,
67
- sequence: sequence,
68
- amount: options[:amount].to_payment,
69
- })
70
-
71
- envelope_base64 = payment.to_envelope(from.keypair).to_xdr(:base64)
72
- @horizon.transactions._post(tx: envelope_base64)
73
- end
74
-
75
- Contract ({
76
- account: Stellar::Account,
77
- funder: Stellar::Account,
78
- starting_balance: Integer
79
- }) => Any
80
- def create_account(options={})
81
- funder = options[:funder]
93
+ uri = URI.parse(FRIENDBOT_URL)
94
+ uri.query = "addr=#{account.address}"
95
+ Faraday.post(uri.to_s)
96
+ end
97
+
98
+ # @option options [Stellar::Account] :account
99
+ # @option options [Stellar::Account] :funder
100
+ # @option options [Integer] :starting_balance
101
+ def create_account(options = {})
102
+ funder = options[:funder]
82
103
  sequence = options[:sequence] || (account_info(funder).sequence.to_i + 1)
83
104
  # In the future, the fee should be grabbed from the network's last transactions,
84
105
  # instead of using a hard-coded default value.
85
- fee = options[:fee] || 100
86
-
87
- payment = Stellar::Transaction.create_account({
88
- account: funder.keypair,
89
- destination: options[:account].keypair,
90
- sequence: sequence,
91
- starting_balance: options[:starting_balance],
92
- fee: fee,
93
- })
94
-
95
- envelope_base64 = payment.to_envelope(funder.keypair).to_xdr(:base64)
96
- @horizon.transactions._post(tx: envelope_base64)
97
- end
98
-
99
- Contract ({
100
- account: Maybe[Stellar::Account],
101
- limit: Maybe[Pos],
102
- cursor: Maybe[String]
103
- }) => TransactionPage
104
- def transactions(options={})
106
+ fee = options[:fee] || DEFAULT_FEE
107
+
108
+ payment = Stellar::TransactionBuilder.new(
109
+ source_account: funder.keypair,
110
+ sequence_number: sequence,
111
+ base_fee: fee
112
+ ).add_operation(
113
+ Stellar::Operation.create_account({
114
+ destination: options[:account].keypair,
115
+ starting_balance: options[:starting_balance]
116
+ })
117
+ ).set_timeout(0).build
118
+
119
+ envelope = payment.to_envelope(funder.keypair)
120
+ submit_transaction(tx_envelope: envelope)
121
+ end
122
+
123
+ # @option options [Stellar::Account] :from The source account
124
+ # @option options [Stellar::Account] :to The destination account
125
+ # @option options [Stellar::Amount] :amount The amount to send
126
+ def send_payment(options = {})
127
+ from_account = options[:from]
128
+ tx_source_account = options[:transaction_source] || from_account
129
+ op_source_account = from_account if tx_source_account.present?
130
+
131
+ sequence = options[:sequence] ||
132
+ (account_info(tx_source_account).sequence.to_i + 1)
133
+
134
+ payment = Stellar::TransactionBuilder.new(
135
+ source_account: tx_source_account.keypair,
136
+ sequence_number: sequence
137
+ ).add_operation(
138
+ Stellar::Operation.payment(
139
+ source_account: op_source_account.keypair,
140
+ destination: options[:to].keypair,
141
+ amount: options[:amount].to_payment
142
+ )
143
+ ).set_memo(options[:memo]).set_timeout(0).build
144
+
145
+ signers = [tx_source_account, op_source_account].uniq(&:address)
146
+ to_envelope_args = signers.map(&:keypair)
147
+
148
+ envelope = payment.to_envelope(*to_envelope_args)
149
+ submit_transaction(tx_envelope: envelope)
150
+ end
151
+
152
+ # @option options [Stellar::Account] :account
153
+ # @option options [Integer] :limit
154
+ # @option options [Integer] :cursor
155
+ # @return [Stellar::TransactionPage]
156
+ def transactions(options = {})
105
157
  args = options.slice(:limit, :cursor)
106
158
 
107
159
  resource = if options[:account]
@@ -114,5 +166,134 @@ module Stellar
114
166
  TransactionPage.new(resource)
115
167
  end
116
168
 
169
+ # @param [Array(Symbol,String,Stellar::KeyPair|Stellar::Account)] asset
170
+ # @param [Stellar::Account] source
171
+ # @param [Integer] sequence
172
+ # @param [Integer] fee
173
+ # @param [Integer] limit
174
+ def change_trust(
175
+ asset:,
176
+ source:,
177
+ sequence: nil,
178
+ fee: DEFAULT_FEE,
179
+ limit: nil
180
+ )
181
+ sequence ||= (account_info(source).sequence.to_i + 1)
182
+
183
+ args = {
184
+ account: source.keypair,
185
+ sequence: sequence,
186
+ line: asset
187
+ }
188
+ args[:limit] = limit unless limit.nil?
189
+
190
+ tx = Stellar::Transaction.change_trust(args)
191
+
192
+ envelope = tx.to_envelope(source.keypair)
193
+ submit_transaction(tx_envelope: envelope)
194
+ end
195
+
196
+ # @param [Stellar::TransactionEnvelope] tx_envelope
197
+ # @option options [Boolean] :skip_memo_required_check (false)
198
+ def submit_transaction(tx_envelope:, options: {skip_memo_required_check: false})
199
+ unless options[:skip_memo_required_check]
200
+ check_memo_required(tx_envelope)
201
+ end
202
+ @horizon.transactions._post(tx: Base64.encode64(tx_envelope.to_xdr))
203
+ end
204
+
205
+ # Required by SEP-0029
206
+ # @param [Stellar::TransactionEnvelope] tx_envelope
207
+ def check_memo_required(tx_envelope)
208
+ tx = tx_envelope.tx
209
+
210
+ if tx.is_a?(Stellar::FeeBumpTransaction)
211
+ tx = tx.inner_tx.v1!.tx
212
+ end
213
+
214
+ # Check transactions where the .memo field is nil or of type MemoType.memo_none
215
+ if !tx.memo.nil? && tx.memo.type != Stellar::MemoType.memo_none
216
+ return
217
+ end
218
+
219
+ destinations = Set.new
220
+ ot = Stellar::OperationType
221
+
222
+ tx.operations.each_with_index do |op, idx|
223
+ destination = case op.body.type
224
+ when ot.payment, ot.path_payment_strict_receive, ot.path_payment_strict_send
225
+ op.body.value.destination
226
+ when ot.account_merge
227
+ # There is no AccountMergeOp, op.body is an Operation object
228
+ # and op.body.value is a PublicKey (or AccountID) object.
229
+ op.body.value
230
+ else
231
+ next
232
+ end
233
+
234
+ if destinations.include?(destination) || destination.switch == Stellar::CryptoKeyType.key_type_muxed_ed25519
235
+ next
236
+ end
237
+
238
+ destinations.add(destination)
239
+ kp = Stellar::KeyPair.from_public_key(destination.value)
240
+
241
+ begin
242
+ info = account_info(kp.address)
243
+ rescue Faraday::ResourceNotFound
244
+ # Don't raise an error if its a 404, but throw one otherwise
245
+ next
246
+ end
247
+ if info.data["config.memo_required"] == "MQ=="
248
+ # MQ== is the base64 encoded string for the string "1"
249
+ raise AccountRequiresMemoError.new("account requires memo", destination, idx)
250
+ end
251
+ end
252
+ end
253
+
254
+ # DEPRECATED: this function has been moved Stellar::SEP10.build_challenge_tx and
255
+ # will be removed in the next major version release.
256
+ #
257
+ # A wrapper function for Stellar::SEP10::build_challenge_tx.
258
+ #
259
+ # @param server [Stellar::KeyPair] Keypair for server's signing account.
260
+ # @param client [Stellar::KeyPair] Keypair for the account whishing to authenticate with the server.
261
+ # @param anchor_name [String] Anchor's name to be used in the manage_data key.
262
+ # @param timeout [Integer] Challenge duration (default to 5 minutes).
263
+ #
264
+ # @return [String] A base64 encoded string of the raw TransactionEnvelope xdr struct for the transaction.
265
+ def build_challenge_tx(server:, client:, anchor_name:, timeout: 300)
266
+ Stellar::SEP10.build_challenge_tx(
267
+ server: server, client: client, anchor_name: anchor_name, timeout: timeout
268
+ )
269
+ end
270
+
271
+ # DEPRECATED: this function has been moved to Stellar::SEP10::read_challenge_tx and
272
+ # will be removed in the next major version release.
273
+ #
274
+ # A wrapper function for Stellar::SEP10.verify_challenge_transaction
275
+ #
276
+ # @param challenge [String] SEP0010 transaction challenge in base64.
277
+ # @param server [Stellar::KeyPair] Stellar::KeyPair for server where the challenge was generated.
278
+ #
279
+ # @return [Boolean]
280
+ def verify_challenge_tx(challenge:, server:)
281
+ Stellar::SEP10.verify_challenge_tx(challenge_xdr: challenge, server: server)
282
+ true
283
+ end
284
+
285
+ # DEPRECATED: this function has been moved to Stellar::SEP10::verify_tx_signed_by and
286
+ # will be removed in the next major version release.
287
+ #
288
+ # @param transaction_envelope [Stellar::TransactionEnvelope]
289
+ # @param keypair [Stellar::KeyPair]
290
+ #
291
+ # @return [Boolean]
292
+ #
293
+ def verify_tx_signed_by(transaction_envelope:, keypair:)
294
+ Stellar::SEP10.verify_tx_signed_by(
295
+ tx_envelope: transaction_envelope, keypair: keypair
296
+ )
297
+ end
117
298
  end
118
299
  end