stellar-sdk 0.5.0 → 0.9.0.rc1

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -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 +217 -91
  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 -207
  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 -1
  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 -7
  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/_account_merge/merges_source_account_into_destination.yml +0 -714
  34. data/spec/fixtures/vcr_cassettes/Stellar_Client/_change_trust/given_an_asset_described_as_an_array/creates_updates_or_deletes_a_trustline.yml +0 -1156
  35. data/spec/fixtures/vcr_cassettes/Stellar_Client/_create_account/creates_the_account.yml +0 -323
  36. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/alphanum12_asset/sends_a_alphanum12_asset_to_the_destination.yml +0 -737
  37. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/alphanum4_asset/sends_a_alphanum4_asset_to_the_destination.yml +0 -737
  38. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/native_asset/sends_a_native_payment_to_the_account.yml +0 -469
  39. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/account_transactions/accepts_a_cursor_to_return_less_data.yml +0 -94
  40. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/account_transactions/returns_a_list_of_transaction_for_an_account.yml +0 -94
  41. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/all_transactions/accepts_a_cursor_to_return_less_data.yml +0 -94
  42. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/all_transactions/returns_a_list_of_transactions.yml +0 -94
  43. data/spec/lib/stellar/account_spec.rb +0 -59
  44. data/spec/lib/stellar/amount_spec.rb +0 -70
  45. data/spec/lib/stellar/client_spec.rb +0 -302
  46. data/spec/spec_helper.rb +0 -14
  47. data/spec/support/config.rb +0 -3
  48. data/spec/support/vcr.rb +0 -10
  49. data/tasks/rspec.rake +0 -6
  50. data/tasks/travis.rake +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 545e59b76cae8e040a4ac6041bc6ab576e82ea94d64333eee7033c669af3ccfa
4
- data.tar.gz: a91fa43b9bcd8692d4a98868803ede802f5316bf97cc7aaf30352540c8c6d424
3
+ metadata.gz: d213d5d19844a3e70e85bcc4bb071092cfb1de5eabba4611d5627496fe2b0c99
4
+ data.tar.gz: 28f4745b24ac3b59f6030d8a4cf53a7dd533339341be0396d8a9620e391513b4
5
5
  SHA512:
6
- metadata.gz: 48d8edceac23d22aca3a678ef58ee272cd76bea945491008ecdcaf40cbce79d6cd49afbb59fdccc64e99474fbb23799f79a2ac84c738645d1873814346797df3
7
- data.tar.gz: d3ba53f2235a3f2e8f511d3b947037d46b366f5c690d42fbf0d7b1578c47be81bd95c510f55293198d2a2e4e33ad920fa9bd967baf70157063c05bf4d0b9b18c
6
+ metadata.gz: cb34d288e67b961d6f3e56ced0fdc78a7d8f83a33aa1864169369a7baebe986d485d6cce326fda6229a7ac81eb1fda389535952f5577fde5afafb97d95ceed44
7
+ data.tar.gz: 31a21f576e58177f3103f130ad9547249cd06607c9d06a4ee01e9674cc0e72072e7751c9c589508947b802d6ca9b13eceba206afa63fcfad4003fae91a1d7b2d
@@ -4,12 +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
 
14
30
  ### Added
15
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,30 +1,40 @@
1
- require 'hyperclient'
1
+ require "hyperclient"
2
+ require "active_support/core_ext/object/blank"
3
+ require "securerandom"
2
4
 
3
5
  module Stellar
4
- class Client
5
- include Contracts
6
- C = Contracts
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
7
15
 
16
+ class Client
8
17
  DEFAULT_FEE = 100
9
18
 
10
- HORIZON_LOCALHOST_URL = 'http://127.0.0.1:8000'
11
- HORIZON_MAINNET_URL = 'https://horizon.stellar.org'
12
- HORIZON_TESTNET_URL = 'https://horizon-testnet.stellar.org'
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
13
23
 
14
- def self.default(options={})
24
+ def self.default(options = {})
15
25
  new options.merge(
16
26
  horizon: HORIZON_MAINNET_URL
17
27
  )
18
28
  end
19
29
 
20
- def self.default_testnet(options={})
30
+ def self.default_testnet(options = {})
21
31
  new options.merge(
22
- horizon: HORIZON_TESTNET_URL,
23
- friendbot: HORIZON_TESTNET_URL,
32
+ horizon: HORIZON_TESTNET_URL,
33
+ friendbot: HORIZON_TESTNET_URL
24
34
  )
25
35
  end
26
36
 
27
- def self.localhost(options={})
37
+ def self.localhost(options = {})
28
38
  new options.merge(
29
39
  horizon: HORIZON_LOCALHOST_URL
30
40
  )
@@ -32,10 +42,10 @@ module Stellar
32
42
 
33
43
  attr_reader :horizon
34
44
 
35
- Contract ({horizon: String}) => Any
45
+ # @option options [String] :horizon The Horizon server URL.
36
46
  def initialize(options)
37
47
  @options = options
38
- @horizon = Hyperclient.new(options[:horizon]) do |client|
48
+ @horizon = Hyperclient.new(options[:horizon]) { |client|
39
49
  client.faraday_block = lambda do |conn|
40
50
  conn.use Faraday::Response::RaiseError
41
51
  conn.use FaradayMiddleware::FollowRedirects
@@ -44,90 +54,106 @@ module Stellar
44
54
  conn.adapter :excon
45
55
  end
46
56
  client.headers = {
47
- '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
48
60
  }
49
- end
61
+ }
50
62
  end
51
63
 
52
- Contract Stellar::Account => Any
53
- def account_info(account)
54
- account_id = account.address
55
- @horizon.account(account_id:account_id)._get
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
70
+ end
71
+ @horizon.account(account_id: account_id)._get
56
72
  end
57
73
 
58
- Contract ({
59
- account: Stellar::Account,
60
- destination: Stellar::Account
61
- }) => Any
62
- def account_merge(options={})
63
- account = options[:account]
74
+ # @option options [Stellar::Account] :account
75
+ # @option options [Stellar::Account] :destination
76
+ def account_merge(options = {})
77
+ account = options[:account]
64
78
  destination = options[:destination]
65
- sequence = options[:sequence] || (account_info(account).sequence.to_i + 1)
79
+ sequence = options[:sequence] || (account_info(account).sequence.to_i + 1)
66
80
 
67
- transaction = Stellar::Transaction.account_merge({
68
- account: account.keypair,
69
- destination: destination.keypair,
70
- sequence: sequence
71
- })
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
72
87
 
73
- envelope_base64 = transaction.to_envelope(account.keypair).to_xdr(:base64)
74
- @horizon.transactions._post(tx: envelope_base64)
88
+ envelope = transaction.to_envelope(account.keypair)
89
+ submit_transaction(tx_envelope: envelope)
75
90
  end
76
91
 
77
92
  def friendbot(account)
78
- raise NotImplementedError
93
+ uri = URI.parse(FRIENDBOT_URL)
94
+ uri.query = "addr=#{account.address}"
95
+ Faraday.post(uri.to_s)
79
96
  end
80
97
 
81
- Contract ({
82
- account: Stellar::Account,
83
- funder: Stellar::Account,
84
- starting_balance: Integer
85
- }) => Any
86
- def create_account(options={})
87
- funder = options[:funder]
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]
88
103
  sequence = options[:sequence] || (account_info(funder).sequence.to_i + 1)
89
104
  # In the future, the fee should be grabbed from the network's last transactions,
90
105
  # instead of using a hard-coded default value.
91
106
  fee = options[:fee] || DEFAULT_FEE
92
107
 
93
- payment = Stellar::Transaction.create_account({
94
- account: funder.keypair,
95
- destination: options[:account].keypair,
96
- sequence: sequence,
97
- starting_balance: options[:starting_balance],
98
- fee: fee,
99
- })
100
-
101
- envelope_base64 = payment.to_envelope(funder.keypair).to_xdr(:base64)
102
- @horizon.transactions._post(tx: envelope_base64)
103
- end
104
-
105
- Contract ({
106
- from: Stellar::Account,
107
- to: Stellar::Account,
108
- amount: Stellar::Amount
109
- }) => Any
110
- def send_payment(options={})
111
- from = options[:from]
112
- sequence = options[:sequence] || (account_info(from).sequence.to_i + 1)
113
-
114
- payment = Stellar::Transaction.payment({
115
- account: from.keypair,
116
- destination: options[:to].keypair,
117
- sequence: sequence,
118
- amount: options[:amount].to_payment,
119
- })
120
-
121
- envelope_base64 = payment.to_envelope(from.keypair).to_xdr(:base64)
122
- @horizon.transactions._post(tx: envelope_base64)
123
- end
124
-
125
- Contract ({
126
- account: Maybe[Stellar::Account],
127
- limit: Maybe[Pos],
128
- cursor: Maybe[String]
129
- }) => TransactionPage
130
- def transactions(options={})
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 = {})
131
157
  args = options.slice(:limit, :cursor)
132
158
 
133
159
  resource = if options[:account]
@@ -140,13 +166,11 @@ module Stellar
140
166
  TransactionPage.new(resource)
141
167
  end
142
168
 
143
- Contract(C::KeywordArgs[
144
- asset: [Symbol, String, Xor[Stellar::KeyPair, Stellar::Account]],
145
- source: Stellar::Account,
146
- sequence: Maybe[Integer],
147
- fee: Maybe[Integer],
148
- limit: Maybe[Integer],
149
- ] => Any)
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
150
174
  def change_trust(
151
175
  asset:,
152
176
  source:,
@@ -159,15 +183,117 @@ module Stellar
159
183
  args = {
160
184
  account: source.keypair,
161
185
  sequence: sequence,
162
- line: asset,
186
+ line: asset
163
187
  }
164
- args[:limit] = limit if !limit.nil?
188
+ args[:limit] = limit unless limit.nil?
165
189
 
166
190
  tx = Stellar::Transaction.change_trust(args)
167
191
 
168
- envelope_base64 = tx.to_envelope(source.keypair).to_xdr(:base64)
169
- horizon.transactions._post(tx: envelope_base64)
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
170
252
  end
171
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
172
298
  end
173
299
  end