stellar-horizon 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7f21b25ec3403a5aa4a6d118fb428e7e4de949ea8530ab7fc10d99f96de75477
4
+ data.tar.gz: 79258881494240f18edaaba909e7afb2602ebdeaadd0cf47959383745d8d7870
5
+ SHA512:
6
+ metadata.gz: 42d1ebd3df2be5f4d436e6d83e2d04fd643aa751bc490e546420e844b7b3085fb9124139d47a0ee87d6cb41fc3a743f654b52ac8f0c0334c758f10b972da2d91
7
+ data.tar.gz: 7658aac83aa40803f806eb95e7d3728c2a9bada248f0330883efe75cc99b4eaf76a0d7c4f64d9aa4557015553649e3d6f0e25025faf6e2e5b432196fcb33963d
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this
4
+ file. The format is based on [Keep a Changelog](https://keepachangelog.com/)
5
+ and this project adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ As this project is pre 1.0, breaking changes may happen for minor version
8
+ bumps. A breaking change will get clearly notified in this log.
9
+
10
+ ## [0.29.0](https://www.github.com/astroband/ruby-stellar-sdk/compare/v0.28.0...v0.29.0) (2021-09-07)
11
+
12
+ ### Added
13
+ * Initial setup of the gem, copying all Horizon-related features from `sdk` gem
data/LICENSE ADDED
File without changes
data/README.md ADDED
File without changes
@@ -0,0 +1,298 @@
1
+ require "hyperclient"
2
+ require "active_support/core_ext/object/blank"
3
+ require "securerandom"
4
+
5
+ module Stellar::Horizon
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
+
16
+ class Client
17
+ DEFAULT_FEE = 100
18
+
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
+ )
28
+ end
29
+
30
+ def self.default_testnet(options = {})
31
+ new options.merge(
32
+ horizon: HORIZON_TESTNET_URL,
33
+ friendbot: HORIZON_TESTNET_URL
34
+ )
35
+ end
36
+
37
+ def self.localhost(options = {})
38
+ new options.merge(
39
+ horizon: HORIZON_LOCALHOST_URL
40
+ )
41
+ end
42
+
43
+ attr_reader :horizon
44
+
45
+ # @option options [String] :horizon The Horizon server URL.
46
+ def initialize(options)
47
+ @options = options
48
+ @horizon = Hyperclient.new(options[:horizon]) { |client|
49
+ client.faraday_block = lambda do |conn|
50
+ conn.use Faraday::Response::RaiseError
51
+ conn.use FaradayMiddleware::FollowRedirects
52
+ conn.request :url_encoded
53
+ conn.response :hal_json, content_type: /\bjson$/
54
+ conn.adapter :excon
55
+ end
56
+ client.headers = {
57
+ "Accept" => "application/hal+json,application/problem+json,application/json",
58
+ "X-Client-Name" => "ruby-stellar-sdk",
59
+ "X-Client-Version" => Stellar::Horizon::VERSION
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
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.account_merge(
82
+ source_account: destination.keypair,
83
+ sequence_number: sequence,
84
+ destination: destination.keypair
85
+ )
86
+
87
+ envelope = transaction.to_envelope(account.keypair)
88
+ submit_transaction(tx_envelope: envelope)
89
+ end
90
+
91
+ def friendbot(account)
92
+ uri = URI.parse(FRIENDBOT_URL)
93
+ uri.query = "addr=#{account.address}"
94
+ Faraday.post(uri.to_s)
95
+ end
96
+
97
+ # @option options [Stellar::Account] :account
98
+ # @option options [Stellar::Account] :funder
99
+ # @option options [Integer] :starting_balance
100
+ def create_account(options = {})
101
+ funder = options[:funder]
102
+ sequence = options[:sequence] || (account_info(funder).sequence.to_i + 1)
103
+ # In the future, the fee should be grabbed from the network's last transactions,
104
+ # instead of using a hard-coded default value.
105
+ fee = options[:fee] || DEFAULT_FEE
106
+
107
+ payment = Stellar::TransactionBuilder.create_account(
108
+ source_account: funder.keypair,
109
+ sequence_number: sequence,
110
+ base_fee: fee,
111
+ destination: options[:account].keypair,
112
+ starting_balance: options[:starting_balance]
113
+ )
114
+ envelope = payment.to_envelope(funder.keypair)
115
+ submit_transaction(tx_envelope: envelope)
116
+ end
117
+
118
+ # @option options [Stellar::Account] :from The source account
119
+ # @option options [Stellar::Account] :to The destination account
120
+ # @option options [Stellar::Amount] :amount The amount to send
121
+ def send_payment(options = {})
122
+ from_account = options[:from]
123
+ tx_source_account = options[:transaction_source] || from_account
124
+ op_source_account = from_account if tx_source_account.present?
125
+
126
+ sequence = options[:sequence] ||
127
+ (account_info(tx_source_account).sequence.to_i + 1)
128
+
129
+ payment = Stellar::TransactionBuilder.new(
130
+ source_account: tx_source_account.keypair,
131
+ sequence_number: sequence
132
+ ).add_operation(
133
+ Stellar::Operation.payment(
134
+ source_account: op_source_account.keypair,
135
+ destination: options[:to].keypair,
136
+ amount: options[:amount].to_payment
137
+ )
138
+ ).set_memo(options[:memo]).set_timeout(0).build
139
+
140
+ signers = [tx_source_account, op_source_account].uniq(&:address)
141
+ to_envelope_args = signers.map(&:keypair)
142
+
143
+ envelope = payment.to_envelope(*to_envelope_args)
144
+ submit_transaction(tx_envelope: envelope)
145
+ end
146
+
147
+ # @option options [Stellar::Account] :account
148
+ # @option options [Integer] :limit
149
+ # @option options [Integer] :cursor
150
+ # @return [Stellar::TransactionPage]
151
+ def transactions(options = {})
152
+ args = options.slice(:limit, :cursor)
153
+
154
+ resource = if options[:account]
155
+ args = args.merge(account_id: options[:account].address)
156
+ @horizon.account_transactions(args)
157
+ else
158
+ @horizon.transactions(args)
159
+ end
160
+
161
+ Stellar::TransactionPage.new(resource)
162
+ end
163
+
164
+ # @param [Array(Symbol,String,Stellar::KeyPair|Stellar::Account)] asset
165
+ # @param [Stellar::Account] source
166
+ # @param [Integer] sequence
167
+ # @param [Integer] fee
168
+ # @param [Integer] limit
169
+ def change_trust(
170
+ asset:,
171
+ source:,
172
+ sequence: nil,
173
+ fee: DEFAULT_FEE,
174
+ limit: nil
175
+ )
176
+ sequence ||= (account_info(source).sequence.to_i + 1)
177
+
178
+ op_args = {
179
+ account: source.keypair,
180
+ sequence: sequence,
181
+ line: asset
182
+ }
183
+ op_args[:limit] = limit unless limit.nil?
184
+
185
+ tx = Stellar::TransactionBuilder.change_trust(
186
+ source_account: source.keypair,
187
+ sequence_number: sequence,
188
+ **op_args
189
+ )
190
+
191
+ envelope = tx.to_envelope(source.keypair)
192
+ submit_transaction(tx_envelope: envelope)
193
+ end
194
+
195
+ # @param [Stellar::TransactionEnvelope] tx_envelope
196
+ # @option options [Boolean] :skip_memo_required_check (false)
197
+ def submit_transaction(tx_envelope:, options: {skip_memo_required_check: false})
198
+ unless options[:skip_memo_required_check]
199
+ check_memo_required(tx_envelope)
200
+ end
201
+ @horizon.transactions._post(tx: tx_envelope.to_xdr(:base64))
202
+ end
203
+
204
+ # Required by SEP-0029
205
+ # @param [Stellar::TransactionEnvelope] tx_envelope
206
+ def check_memo_required(tx_envelope)
207
+ tx = tx_envelope.tx
208
+
209
+ if tx.is_a?(Stellar::FeeBumpTransaction)
210
+ tx = tx.inner_tx.v1!.tx
211
+ end
212
+
213
+ # Check transactions where the .memo field is nil or of type MemoType.memo_none
214
+ if !tx.memo.nil? && tx.memo.type != Stellar::MemoType.memo_none
215
+ return
216
+ end
217
+
218
+ destinations = Set.new
219
+ ot = Stellar::OperationType
220
+
221
+ tx.operations.each_with_index do |op, idx|
222
+ destination = case op.body.type
223
+ when ot.payment, ot.path_payment_strict_receive, ot.path_payment_strict_send
224
+ op.body.value.destination
225
+ when ot.account_merge
226
+ # There is no AccountMergeOp, op.body is an Operation object
227
+ # and op.body.value is a PublicKey (or AccountID) object.
228
+ op.body.value
229
+ else
230
+ next
231
+ end
232
+
233
+ if destinations.include?(destination) || destination.switch == Stellar::CryptoKeyType.key_type_muxed_ed25519
234
+ next
235
+ end
236
+
237
+ destinations.add(destination)
238
+ kp = Stellar::KeyPair.from_public_key(destination.value)
239
+
240
+ begin
241
+ info = account_info(kp.address)
242
+ rescue Faraday::ResourceNotFound
243
+ # Don't raise an error if its a 404, but throw one otherwise
244
+ next
245
+ end
246
+ if info.data["config.memo_required"] == "MQ=="
247
+ # MQ== is the base64 encoded string for the string "1"
248
+ raise AccountRequiresMemoError.new("account requires memo", destination, idx)
249
+ end
250
+ end
251
+ end
252
+
253
+ # DEPRECATED: this function has been moved Stellar::SEP10.build_challenge_tx and
254
+ # will be removed in the next major version release.
255
+ #
256
+ # A wrapper function for Stellar::SEP10::build_challenge_tx.
257
+ #
258
+ # @param server [Stellar::KeyPair] Keypair for server's signing account.
259
+ # @param client [Stellar::KeyPair] Keypair for the account whishing to authenticate with the server.
260
+ # @param anchor_name [String] Anchor's name to be used in the manage_data key.
261
+ # @param timeout [Integer] Challenge duration (default to 5 minutes).
262
+ #
263
+ # @return [String] A base64 encoded string of the raw TransactionEnvelope xdr struct for the transaction.
264
+ def build_challenge_tx(server:, client:, anchor_name:, timeout: 300)
265
+ Stellar::SEP10.build_challenge_tx(
266
+ server: server, client: client, anchor_name: anchor_name, timeout: timeout
267
+ )
268
+ end
269
+
270
+ # DEPRECATED: this function has been moved to Stellar::SEP10::read_challenge_tx and
271
+ # will be removed in the next major version release.
272
+ #
273
+ # A wrapper function for Stellar::SEP10.verify_challenge_transaction
274
+ #
275
+ # @param challenge [String] SEP0010 transaction challenge in base64.
276
+ # @param server [Stellar::KeyPair] Stellar::KeyPair for server where the challenge was generated.
277
+ #
278
+ # @return [Boolean]
279
+ def verify_challenge_tx(challenge:, server:)
280
+ Stellar::SEP10.verify_challenge_tx(challenge_xdr: challenge, server: server)
281
+ true
282
+ end
283
+
284
+ # DEPRECATED: this function has been moved to Stellar::SEP10::verify_tx_signed_by and
285
+ # will be removed in the next major version release.
286
+ #
287
+ # @param transaction_envelope [Stellar::TransactionEnvelope]
288
+ # @param keypair [Stellar::KeyPair]
289
+ #
290
+ # @return [Boolean]
291
+ #
292
+ def verify_tx_signed_by(transaction_envelope:, keypair:)
293
+ Stellar::SEP10.verify_tx_signed_by(
294
+ tx_envelope: transaction_envelope, keypair: keypair
295
+ )
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,9 @@
1
+ require "stellar-sdk"
2
+
3
+ module Stellar
4
+ module Horizon
5
+ VERSION = ::Stellar::VERSION
6
+
7
+ autoload :Client, "#{__dir__}/stellar/horizon/client.rb"
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stellar-horizon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.29.0
5
+ platform: ruby
6
+ authors:
7
+ - Sergey Nebolsin
8
+ - Timur Ramazanov
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2021-09-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: stellar-sdk
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.29.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.29.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: excon
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.71.0
35
+ - - "<"
36
+ - !ruby/object:Gem::Version
37
+ version: '1.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 0.71.0
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: hyperclient
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.7.0
55
+ - - "<"
56
+ - !ruby/object:Gem::Version
57
+ version: '2.0'
58
+ type: :runtime
59
+ prerelease: false
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 0.7.0
65
+ - - "<"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: toml-rb
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.1.1
75
+ - - "<"
76
+ - !ruby/object:Gem::Version
77
+ version: '3.0'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.1.1
85
+ - - "<"
86
+ - !ruby/object:Gem::Version
87
+ version: '3.0'
88
+ - !ruby/object:Gem::Dependency
89
+ name: bundler
90
+ requirement: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '2.0'
95
+ type: :development
96
+ prerelease: false
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '2.0'
102
+ - !ruby/object:Gem::Dependency
103
+ name: rake
104
+ requirement: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '13'
109
+ type: :development
110
+ prerelease: false
111
+ version_requirements: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '13'
116
+ - !ruby/object:Gem::Dependency
117
+ name: rspec
118
+ requirement: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '3.9'
123
+ type: :development
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '3.9'
130
+ description:
131
+ email:
132
+ executables: []
133
+ extensions: []
134
+ extra_rdoc_files:
135
+ - README.md
136
+ - LICENSE
137
+ - CHANGELOG.md
138
+ files:
139
+ - CHANGELOG.md
140
+ - LICENSE
141
+ - README.md
142
+ - lib/stellar-horizon.rb
143
+ - lib/stellar/horizon/client.rb
144
+ homepage: https://github.com/stellar/ruby-stellar-sdk/tree/master/horizon
145
+ licenses:
146
+ - Apache-2.0
147
+ metadata:
148
+ github_repo: ssh://github.com/astroband/ruby-stellar-sdk
149
+ documentation_uri: https://rubydoc.info/gems/stellar-sdk/0.29.0/
150
+ changelog_uri: https://github.com/astroband/ruby-stellar-sdk/blob/v0.29.0/horizon/CHANGELOG.md
151
+ source_code_uri: https://github.com/astroband/ruby-stellar-sdk/tree/v0.29.0/horizon
152
+ post_install_message:
153
+ rdoc_options: []
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: 2.5.0
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubygems_version: 3.1.4
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Stellar Horizon client library
171
+ test_files: []