stellar-sdk 0.27.0 → 0.31.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 +4 -4
- data/CHANGELOG.md +25 -0
- data/lib/stellar/federation.rb +51 -0
- data/lib/stellar/sep10.rb +42 -8
- data/lib/stellar-sdk.rb +3 -12
- metadata +25 -77
- data/lib/stellar/account.rb +0 -89
- data/lib/stellar/amount.rb +0 -36
- data/lib/stellar/client.rb +0 -298
- data/lib/stellar/horizon/problem.rb +0 -45
- data/lib/stellar/transaction_page.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e6374a1f2407fd63aeaf4ec40ab27409bd0b187aed21ac9d34eceb19b6f0eb48
|
4
|
+
data.tar.gz: 1198273f4bea602f9d9062b1ecf143bdbd7414172680ceaaf92c89edb940bd4f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3308f77ed5f5dcaec0f83fdef87220d318466f7775e08e1f93deed41562ebb4ae307383545b621337b8f07570a387be185b3575ea16d8350a0cd9c9a5b0ac761
|
7
|
+
data.tar.gz: 2e3f360405f67c0d9a2c9e3674bb531ddfd7e8d91ef7a3975c1cf8ff19e890d0d231b16a1eaf10e6283c9d102519ddd09d183297e572a9190245f5d2676f8c29
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
6
6
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
7
7
|
|
8
|
+
## [0.31.0](https://github.com/astroband/ruby-stellar-sdk/compare/v0.30.0...v0.31.0) (2022-02-20)
|
9
|
+
### Features
|
10
|
+
- `Stellar::SEP10` uses 5 minutes grace period for challenge tx ([#256](https://github.com/astroband/ruby-stellar-sdk/issues/256)) ([0d02663](https://github.com/astroband/ruby-stellar-sdk/commit/0d02663ff41a878f5c4d373f31988313e6ee4f46))
|
11
|
+
|
12
|
+
## [0.30.0](https://www.github.com/astroband/ruby-stellar-sdk/compare/v0.29.0...v0.30.0) (2021-10-14)
|
13
|
+
### Features
|
14
|
+
- `stellar-sdk` now depends on `stellar-horizon`
|
15
|
+
### Refactoring
|
16
|
+
- `Stellar::Amount` class moved to `stellar-base` gem
|
17
|
+
- `Stellar::Horizon::Problem` class moved to `stellar-horizon` gem
|
18
|
+
- `Stellar::TransactionPage` is now `Stellar::Horizon::TransactionPage` in `stellar-horizon` gem
|
19
|
+
- `toml-rb` gem is replaced with `tomlrb` gem to work around [segfaults in Ruby 3.0](https://github.com/mjackson/citrus/issues/60)
|
20
|
+
|
21
|
+
## [0.29.0](https://www.github.com/astroband/ruby-stellar-sdk/compare/v0.28.0...v0.29.0) (2021-09-07)
|
22
|
+
### Deprecations
|
23
|
+
- `Stellar::Client` class is marked as deprecated in favour of new `stellar-horizon` gem
|
24
|
+
### Features
|
25
|
+
- support for client domain in SEP-10
|
26
|
+
|
27
|
+
## [0.28.0](https://www.github.com/astroband/ruby-stellar-sdk/compare/v0.27.0...v0.28.0) (2021-07-17)
|
28
|
+
### Deprecations
|
29
|
+
- `Stellar::Account.lookup` is deprecated, use `Stellar::Federation.lookup` instead
|
30
|
+
### Refactoring
|
31
|
+
- `Stellar::Account` class is now part of `stellar-base` gem
|
32
|
+
|
8
33
|
## [0.27.0](https://github.com/astroband/ruby-stellar-sdk/compare/v0.26.0...v0.27.0) (2021-05-08)
|
9
34
|
- No changes
|
10
35
|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "tomlrb"
|
2
|
+
require "uri"
|
3
|
+
require "faraday"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Stellar
|
7
|
+
class Federation
|
8
|
+
def self.lookup(federated_name)
|
9
|
+
_, domain = federated_name.split("*")
|
10
|
+
if domain.nil?
|
11
|
+
raise InvalidFederationAddress.new
|
12
|
+
end
|
13
|
+
|
14
|
+
domain_req = Faraday.new("https://#{domain}/.well-known/stellar.toml").get
|
15
|
+
|
16
|
+
unless domain_req.status == 200
|
17
|
+
raise InvalidStellarDomain, "Domain does not contain stellar.toml file"
|
18
|
+
end
|
19
|
+
|
20
|
+
fed_server_url = Tomlrb.parse(domain_req.body)["FEDERATION_SERVER"]
|
21
|
+
if fed_server_url.nil?
|
22
|
+
raise InvalidStellarTOML, "Invalid Stellar TOML file"
|
23
|
+
end
|
24
|
+
|
25
|
+
unless fed_server_url&.match?(URI::DEFAULT_PARSER.make_regexp)
|
26
|
+
raise InvalidFederationURL, "Invalid Federation Server URL"
|
27
|
+
end
|
28
|
+
|
29
|
+
lookup_req = Faraday.new(fed_server_url).get { |req|
|
30
|
+
req.params[:q] = federated_name
|
31
|
+
req.params[:type] = "name"
|
32
|
+
}
|
33
|
+
|
34
|
+
unless lookup_req.status == 200
|
35
|
+
raise AccountNotFound, "Account not found"
|
36
|
+
end
|
37
|
+
|
38
|
+
JSON.parse(lookup_req.body)["account_id"]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class AccountNotFound < StandardError; end
|
43
|
+
|
44
|
+
class InvalidStellarTOML < StandardError; end
|
45
|
+
|
46
|
+
class InvalidFederationAddress < StandardError; end
|
47
|
+
|
48
|
+
class InvalidStellarDomain < StandardError; end
|
49
|
+
|
50
|
+
class InvalidFederationURL < StandardError; end
|
51
|
+
end
|
data/lib/stellar/sep10.rb
CHANGED
@@ -4,6 +4,10 @@ module Stellar
|
|
4
4
|
class SEP10
|
5
5
|
include Stellar::DSL
|
6
6
|
|
7
|
+
# We use a small grace period for the challenge transaction time bounds
|
8
|
+
# to compensate possible clock drift on client's machine
|
9
|
+
GRACE_PERIOD = 5.minutes
|
10
|
+
|
7
11
|
# Helper method to create a valid {SEP0010}[https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md]
|
8
12
|
# challenge transaction which you can use for Stellar Web Authentication.
|
9
13
|
#
|
@@ -64,6 +68,20 @@ module Stellar
|
|
64
68
|
)
|
65
69
|
end
|
66
70
|
|
71
|
+
if options[:client_domain].present?
|
72
|
+
if options[:client_domain_account].blank?
|
73
|
+
raise "`client_domain_account` is required, if `client_domain` is provided"
|
74
|
+
end
|
75
|
+
|
76
|
+
tb.add_operation(
|
77
|
+
Stellar::Operation.manage_data(
|
78
|
+
name: "client_domain",
|
79
|
+
value: options[:client_domain],
|
80
|
+
source_account: options[:client_domain_account]
|
81
|
+
)
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
67
85
|
tb.build.to_envelope(server).to_xdr(:base64)
|
68
86
|
end
|
69
87
|
|
@@ -125,16 +143,14 @@ module Stellar
|
|
125
143
|
|
126
144
|
rest_ops.each do |op|
|
127
145
|
body = op.body
|
146
|
+
op_params = body.value
|
128
147
|
|
129
148
|
if body.arm != :manage_data_op
|
130
149
|
raise InvalidSep10ChallengeError, "The transaction has operations that are not of type 'manageData'"
|
131
|
-
elsif op.source_account != server.muxed_account
|
150
|
+
elsif op.source_account != server.muxed_account && op_params.data_name != "client_domain"
|
132
151
|
raise InvalidSep10ChallengeError, "The transaction has operations that are unrecognized"
|
133
|
-
|
134
|
-
|
135
|
-
if op_params.data_name == "web_auth_domain" && options.key?(:auth_domain) && op_params.data_value != options[:auth_domain]
|
136
|
-
raise InvalidSep10ChallengeError, "The transaction has 'manageData' operation with 'web_auth_domain' key and invalid value"
|
137
|
-
end
|
152
|
+
elsif op_params.data_name == "web_auth_domain" && options.key?(:auth_domain) && op_params.data_value != options[:auth_domain]
|
153
|
+
raise InvalidSep10ChallengeError, "The transaction has 'manageData' operation with 'web_auth_domain' key and invalid value"
|
138
154
|
end
|
139
155
|
end
|
140
156
|
|
@@ -145,7 +161,7 @@ module Stellar
|
|
145
161
|
time_bounds = transaction.time_bounds
|
146
162
|
now = Time.now.to_i
|
147
163
|
|
148
|
-
if time_bounds.blank? || !now.between?(time_bounds.min_time, time_bounds.max_time)
|
164
|
+
if time_bounds.blank? || !now.between?(time_bounds.min_time - GRACE_PERIOD, time_bounds.max_time + GRACE_PERIOD)
|
149
165
|
raise InvalidSep10ChallengeError, "The transaction has expired"
|
150
166
|
end
|
151
167
|
|
@@ -210,6 +226,9 @@ module Stellar
|
|
210
226
|
client_signers = signers.select { |s| s =~ /G[A-Z0-9]{55}/ && s != server.address }.to_set
|
211
227
|
raise InvalidSep10ChallengeError, "at least one regular signer must be provided" if client_signers.empty?
|
212
228
|
|
229
|
+
client_domain_account_address = extract_client_domain_account(te.tx)
|
230
|
+
client_signers.add(client_domain_account_address) if client_domain_account_address.present?
|
231
|
+
|
213
232
|
# verify all signatures in one pass
|
214
233
|
client_signers.add(server.address)
|
215
234
|
signers_found = verify_tx_signatures(tx_envelope: te, signers: client_signers)
|
@@ -229,6 +248,10 @@ module Stellar
|
|
229
248
|
raise InvalidSep10ChallengeError, "Transaction has unrecognized signatures."
|
230
249
|
end
|
231
250
|
|
251
|
+
if client_domain_account_address.present? && !signers_found.include?(client_domain_account_address)
|
252
|
+
raise InvalidSep10ChallengeError, "Transaction not signed by client domain account."
|
253
|
+
end
|
254
|
+
|
232
255
|
signers_found
|
233
256
|
end
|
234
257
|
|
@@ -249,7 +272,7 @@ module Stellar
|
|
249
272
|
to_keypair = Stellar::DSL.method(:KeyPair)
|
250
273
|
keys_by_hint = signers.map(&to_keypair).index_by(&:signature_hint)
|
251
274
|
|
252
|
-
|
275
|
+
signatures.each_with_object(Set.new) do |sig, result|
|
253
276
|
key = keys_by_hint.delete(sig.hint)
|
254
277
|
result.add(key.address) if key&.verify(sig.signature, tx_hash)
|
255
278
|
end
|
@@ -272,5 +295,16 @@ module Stellar
|
|
272
295
|
keypair.verify(sig.signature, tx_hash)
|
273
296
|
end
|
274
297
|
end
|
298
|
+
|
299
|
+
def self.extract_client_domain_account(transaction)
|
300
|
+
client_domain_account_op =
|
301
|
+
transaction
|
302
|
+
.operations
|
303
|
+
.find { |op| op.body.value.data_name == "client_domain" }
|
304
|
+
|
305
|
+
return if client_domain_account_op.blank?
|
306
|
+
|
307
|
+
Util::StrKey.encode_muxed_account(client_domain_account_op.source_account)
|
308
|
+
end
|
275
309
|
end
|
276
310
|
end
|
data/lib/stellar-sdk.rb
CHANGED
@@ -1,21 +1,12 @@
|
|
1
1
|
require "stellar-base"
|
2
|
+
require "stellar-horizon"
|
2
3
|
|
3
4
|
module Stellar
|
4
5
|
module SDK
|
5
6
|
VERSION = ::Stellar::VERSION
|
6
7
|
end
|
8
|
+
Client = Horizon::Client
|
7
9
|
|
8
|
-
autoload :
|
9
|
-
autoload :Amount
|
10
|
-
autoload :Client
|
10
|
+
autoload :Federation
|
11
11
|
autoload :SEP10
|
12
|
-
|
13
|
-
module Horizon
|
14
|
-
extend ActiveSupport::Autoload
|
15
|
-
|
16
|
-
autoload :Problem
|
17
|
-
autoload :Result
|
18
|
-
end
|
19
|
-
|
20
|
-
autoload :TransactionPage
|
21
12
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stellar-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.31.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Scott Fleckenstein
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2022-02-21 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: stellar-base
|
@@ -18,61 +18,55 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - '='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 0.31.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - '='
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: 0.
|
28
|
+
version: 0.31.0
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
|
-
name:
|
30
|
+
name: stellar-horizon
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
|
-
- -
|
34
|
-
- !ruby/object:Gem::Version
|
35
|
-
version: 5.0.0
|
36
|
-
- - "<"
|
33
|
+
- - '='
|
37
34
|
- !ruby/object:Gem::Version
|
38
|
-
version:
|
35
|
+
version: 0.31.0
|
39
36
|
type: :runtime
|
40
37
|
prerelease: false
|
41
38
|
version_requirements: !ruby/object:Gem::Requirement
|
42
39
|
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 5.0.0
|
46
|
-
- - "<"
|
40
|
+
- - '='
|
47
41
|
- !ruby/object:Gem::Version
|
48
|
-
version:
|
42
|
+
version: 0.31.0
|
49
43
|
- !ruby/object:Gem::Dependency
|
50
|
-
name:
|
44
|
+
name: activesupport
|
51
45
|
requirement: !ruby/object:Gem::Requirement
|
52
46
|
requirements:
|
53
47
|
- - ">="
|
54
48
|
- !ruby/object:Gem::Version
|
55
|
-
version: 0.
|
49
|
+
version: 5.0.0
|
56
50
|
- - "<"
|
57
51
|
- !ruby/object:Gem::Version
|
58
|
-
version: '
|
52
|
+
version: '8.0'
|
59
53
|
type: :runtime
|
60
54
|
prerelease: false
|
61
55
|
version_requirements: !ruby/object:Gem::Requirement
|
62
56
|
requirements:
|
63
57
|
- - ">="
|
64
58
|
- !ruby/object:Gem::Version
|
65
|
-
version: 0.
|
59
|
+
version: 5.0.0
|
66
60
|
- - "<"
|
67
61
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
62
|
+
version: '8.0'
|
69
63
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
64
|
+
name: faraday
|
71
65
|
requirement: !ruby/object:Gem::Requirement
|
72
66
|
requirements:
|
73
67
|
- - ">="
|
74
68
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
69
|
+
version: 1.6.0
|
76
70
|
- - "<"
|
77
71
|
- !ruby/object:Gem::Version
|
78
72
|
version: '2.0'
|
@@ -82,17 +76,17 @@ dependencies:
|
|
82
76
|
requirements:
|
83
77
|
- - ">="
|
84
78
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
79
|
+
version: 1.6.0
|
86
80
|
- - "<"
|
87
81
|
- !ruby/object:Gem::Version
|
88
82
|
version: '2.0'
|
89
83
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
84
|
+
name: tomlrb
|
91
85
|
requirement: !ruby/object:Gem::Requirement
|
92
86
|
requirements:
|
93
87
|
- - ">="
|
94
88
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
89
|
+
version: 2.0.1
|
96
90
|
- - "<"
|
97
91
|
- !ruby/object:Gem::Version
|
98
92
|
version: '3.0'
|
@@ -102,52 +96,10 @@ dependencies:
|
|
102
96
|
requirements:
|
103
97
|
- - ">="
|
104
98
|
- !ruby/object:Gem::Version
|
105
|
-
version:
|
99
|
+
version: 2.0.1
|
106
100
|
- - "<"
|
107
101
|
- !ruby/object:Gem::Version
|
108
102
|
version: '3.0'
|
109
|
-
- !ruby/object:Gem::Dependency
|
110
|
-
name: bundler
|
111
|
-
requirement: !ruby/object:Gem::Requirement
|
112
|
-
requirements:
|
113
|
-
- - "~>"
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: '2.2'
|
116
|
-
type: :development
|
117
|
-
prerelease: false
|
118
|
-
version_requirements: !ruby/object:Gem::Requirement
|
119
|
-
requirements:
|
120
|
-
- - "~>"
|
121
|
-
- !ruby/object:Gem::Version
|
122
|
-
version: '2.2'
|
123
|
-
- !ruby/object:Gem::Dependency
|
124
|
-
name: rake
|
125
|
-
requirement: !ruby/object:Gem::Requirement
|
126
|
-
requirements:
|
127
|
-
- - "~>"
|
128
|
-
- !ruby/object:Gem::Version
|
129
|
-
version: '13'
|
130
|
-
type: :development
|
131
|
-
prerelease: false
|
132
|
-
version_requirements: !ruby/object:Gem::Requirement
|
133
|
-
requirements:
|
134
|
-
- - "~>"
|
135
|
-
- !ruby/object:Gem::Version
|
136
|
-
version: '13'
|
137
|
-
- !ruby/object:Gem::Dependency
|
138
|
-
name: rspec
|
139
|
-
requirement: !ruby/object:Gem::Requirement
|
140
|
-
requirements:
|
141
|
-
- - "~>"
|
142
|
-
- !ruby/object:Gem::Version
|
143
|
-
version: '3.9'
|
144
|
-
type: :development
|
145
|
-
prerelease: false
|
146
|
-
version_requirements: !ruby/object:Gem::Requirement
|
147
|
-
requirements:
|
148
|
-
- - "~>"
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: '3.9'
|
151
103
|
description:
|
152
104
|
email:
|
153
105
|
executables: []
|
@@ -161,22 +113,18 @@ files:
|
|
161
113
|
- LICENSE
|
162
114
|
- README.md
|
163
115
|
- lib/stellar-sdk.rb
|
164
|
-
- lib/stellar/
|
165
|
-
- lib/stellar/amount.rb
|
166
|
-
- lib/stellar/client.rb
|
167
|
-
- lib/stellar/horizon/problem.rb
|
116
|
+
- lib/stellar/federation.rb
|
168
117
|
- lib/stellar/sep10.rb
|
169
|
-
- lib/stellar/transaction_page.rb
|
170
118
|
homepage: https://github.com/astroband/ruby-stellar-sdk
|
171
119
|
licenses:
|
172
120
|
- Apache-2.0
|
173
121
|
metadata:
|
174
122
|
bug_tracker_uri: https://github.com/astroband/ruby-stellar-sdk/issues
|
175
|
-
changelog_uri: https://github.com/astroband/ruby-stellar-sdk/blob/v0.
|
176
|
-
documentation_uri: https://rubydoc.info/gems/stellar-sdk/0.
|
123
|
+
changelog_uri: https://github.com/astroband/ruby-stellar-sdk/blob/v0.31.0/sdk/CHANGELOG.md
|
124
|
+
documentation_uri: https://rubydoc.info/gems/stellar-sdk/0.31.0/
|
177
125
|
github_repo: ssh://github.com/astroband/ruby-stellar-sdk
|
178
126
|
homepage_uri: https://github.com/astroband/ruby-stellar-sdk/tree/main/sdk
|
179
|
-
source_code_uri: https://github.com/astroband/ruby-stellar-sdk/tree/v0.
|
127
|
+
source_code_uri: https://github.com/astroband/ruby-stellar-sdk/tree/v0.31.0/sdk
|
180
128
|
post_install_message:
|
181
129
|
rdoc_options: []
|
182
130
|
require_paths:
|
@@ -192,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
192
140
|
- !ruby/object:Gem::Version
|
193
141
|
version: '0'
|
194
142
|
requirements: []
|
195
|
-
rubygems_version: 3.
|
143
|
+
rubygems_version: 3.3.5
|
196
144
|
signing_key:
|
197
145
|
specification_version: 4
|
198
146
|
summary: Stellar client library
|
data/lib/stellar/account.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
require "toml-rb"
|
2
|
-
require "uri"
|
3
|
-
require "faraday"
|
4
|
-
require "json"
|
5
|
-
|
6
|
-
module Stellar
|
7
|
-
class Account
|
8
|
-
delegate :address, to: :keypair
|
9
|
-
|
10
|
-
def self.random
|
11
|
-
keypair = Stellar::KeyPair.random
|
12
|
-
new(keypair)
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.from_seed(seed)
|
16
|
-
keypair = Stellar::KeyPair.from_seed(seed)
|
17
|
-
new(keypair)
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.from_address(address)
|
21
|
-
keypair = Stellar::KeyPair.from_address(address)
|
22
|
-
new(keypair)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.lookup(federated_name)
|
26
|
-
_, domain = federated_name.split("*")
|
27
|
-
if domain.nil?
|
28
|
-
raise InvalidFederationAddress.new
|
29
|
-
end
|
30
|
-
|
31
|
-
domain_req = Faraday.new("https://#{domain}/.well-known/stellar.toml").get
|
32
|
-
|
33
|
-
unless domain_req.status == 200
|
34
|
-
raise InvalidStellarDomain.new("Domain does not contain stellar.toml file")
|
35
|
-
end
|
36
|
-
|
37
|
-
fed_server_url = TomlRB.parse(domain_req.body)["FEDERATION_SERVER"]
|
38
|
-
if fed_server_url.nil?
|
39
|
-
raise InvalidStellarTOML.new("Invalid Stellar TOML file")
|
40
|
-
end
|
41
|
-
|
42
|
-
unless fed_server_url&.match?(URI::DEFAULT_PARSER.make_regexp)
|
43
|
-
raise InvalidFederationURL.new("Invalid Federation Server URL")
|
44
|
-
end
|
45
|
-
|
46
|
-
lookup_req = Faraday.new(fed_server_url).get { |req|
|
47
|
-
req.params[:q] = federated_name
|
48
|
-
req.params[:type] = "name"
|
49
|
-
}
|
50
|
-
|
51
|
-
unless lookup_req.status == 200
|
52
|
-
raise AccountNotFound.new("Account not found")
|
53
|
-
end
|
54
|
-
|
55
|
-
JSON.parse(lookup_req.body)["account_id"]
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.master
|
59
|
-
keypair = Stellar::KeyPair.from_raw_seed("allmylifemyhearthasbeensearching")
|
60
|
-
new(keypair)
|
61
|
-
end
|
62
|
-
|
63
|
-
attr_reader :keypair
|
64
|
-
|
65
|
-
# @param [Stellar::KeyPair] keypair
|
66
|
-
def initialize(keypair)
|
67
|
-
@keypair = keypair
|
68
|
-
end
|
69
|
-
|
70
|
-
def to_keypair
|
71
|
-
keypair
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class AccountNotFound < StandardError
|
76
|
-
end
|
77
|
-
|
78
|
-
class InvalidStellarTOML < StandardError
|
79
|
-
end
|
80
|
-
|
81
|
-
class InvalidFederationAddress < StandardError
|
82
|
-
end
|
83
|
-
|
84
|
-
class InvalidStellarDomain < StandardError
|
85
|
-
end
|
86
|
-
|
87
|
-
class InvalidFederationURL < StandardError
|
88
|
-
end
|
89
|
-
end
|
data/lib/stellar/amount.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
module Stellar
|
2
|
-
class Amount
|
3
|
-
attr_reader :amount
|
4
|
-
attr_reader :asset
|
5
|
-
|
6
|
-
# @param [Fixnum] amount
|
7
|
-
# @param [Stellar::Asset] asset
|
8
|
-
def initialize(amount, asset = Stellar::Asset.native)
|
9
|
-
# TODO: how are we going to handle decimal considerations?
|
10
|
-
|
11
|
-
@amount = amount
|
12
|
-
@asset = asset
|
13
|
-
end
|
14
|
-
|
15
|
-
# @return [Array(Symbol, Fixnum)] in case of a native asset
|
16
|
-
# @return [Array(Symbol, String, Stellar::KeyPair, Fixnum)] in case of alphanum asset
|
17
|
-
def to_payment
|
18
|
-
case asset.type
|
19
|
-
when AssetType.asset_type_native
|
20
|
-
[:native, amount]
|
21
|
-
when AssetType.asset_type_credit_alphanum4
|
22
|
-
keypair = KeyPair.from_public_key(asset.issuer.value)
|
23
|
-
[:alphanum4, asset.code, keypair, amount]
|
24
|
-
when AssetType.asset_type_credit_alphanum12
|
25
|
-
keypair = KeyPair.from_public_key(asset.issuer.value)
|
26
|
-
[:alphanum12, asset.code, keypair, amount]
|
27
|
-
else
|
28
|
-
raise "Unknown asset type: #{asset.type}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def inspect
|
33
|
-
"#<Stellar::Amount #{asset}(#{amount})>"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/stellar/client.rb
DELETED
@@ -1,298 +0,0 @@
|
|
1
|
-
require "hyperclient"
|
2
|
-
require "active_support/core_ext/object/blank"
|
3
|
-
require "securerandom"
|
4
|
-
|
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
|
-
|
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" => 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
|
-
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
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Stellar
|
2
|
-
module Horizon
|
3
|
-
class Problem
|
4
|
-
def initialize(attributes)
|
5
|
-
@attributes = attributes.reverse_merge({
|
6
|
-
type: "about:blank",
|
7
|
-
title: "Unknown Error",
|
8
|
-
status: 500
|
9
|
-
})
|
10
|
-
|
11
|
-
@meta = @attributes.except!(:type, :title, :status, :detail, :instance)
|
12
|
-
end
|
13
|
-
|
14
|
-
# @return [String]
|
15
|
-
def type
|
16
|
-
@attributes[:type]
|
17
|
-
end
|
18
|
-
|
19
|
-
# @return [String]
|
20
|
-
def title
|
21
|
-
@attributes[:title]
|
22
|
-
end
|
23
|
-
|
24
|
-
# @return [Integer]
|
25
|
-
def status
|
26
|
-
@attributes[:status]
|
27
|
-
end
|
28
|
-
|
29
|
-
# @return [String]
|
30
|
-
def detail
|
31
|
-
@attributes[:detail]
|
32
|
-
end
|
33
|
-
|
34
|
-
# @return [String]
|
35
|
-
def instance
|
36
|
-
@attributes[:instance]
|
37
|
-
end
|
38
|
-
|
39
|
-
# @return [{String => Object}]
|
40
|
-
def meta
|
41
|
-
@attributes[:instance]
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Stellar
|
2
|
-
class TransactionPage
|
3
|
-
include Enumerable
|
4
|
-
|
5
|
-
# @param [Hyperclient::Link] resource
|
6
|
-
def initialize(resource)
|
7
|
-
@resource = resource
|
8
|
-
end
|
9
|
-
|
10
|
-
def each
|
11
|
-
@resource.records.each do |tx|
|
12
|
-
yield tx if block_given?
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
# @return [Stellar::TransactionPage]
|
17
|
-
def next_page
|
18
|
-
self.class.new(@resource.next)
|
19
|
-
end
|
20
|
-
|
21
|
-
def next_page!
|
22
|
-
@resource = @resource.next
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|