mobius-client 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: aa4d61727ba66679c6a5089ec75012d4c87e1d24
4
- data.tar.gz: a2418ab7d25c6f54e3f8e9a36800f8b929be5913
2
+ SHA256:
3
+ metadata.gz: f26fccdb1893d53cbb280832a4fe527a98f17c9d62bb4350cc07629caea51251
4
+ data.tar.gz: c2b3d55a4c15c334617d3571d1e1ad0ac1a8436685f5e965dcf1854d55d59f64
5
5
  SHA512:
6
- metadata.gz: fbf295dd5c30ae4decfddad11da7f071a4b9840a648a1fd5a9ad190af01058e63e6db0d53c40fe2c38e90001c739f5081bbd48fa1542cb0c42b381211ab4930b
7
- data.tar.gz: a89f53e9a33aba413fe7e53b0e71b737acdd7954315de9283f7876ca3c5f41358597f00a58ba9f5c151f308d9a2b10ce18cdfa6ee8f40197e2d8693263bc2fcd
6
+ metadata.gz: 62078725168f732c21c720471ab26780dce72fd19869d0177715ff69caa49aee7e29eb815b0f44e91777c48d15a0473dd6976f5b38ee335af4aa0cc346e0d664
7
+ data.tar.gz: fadbdb441858930947ccf18895505fd5c5c44525acb99fe365f2212bbaeced1cf15e26426215a7ad3520e1caf792963704c25d5c16930141afd0ce031c72e548
data/README.md CHANGED
@@ -22,6 +22,14 @@ An overview of the DApp Store architecture is:
22
22
  1) Adds the application's public key as a signer so the application can access the MOBI and
23
23
  2) Signs a challenge transaction from the app with its secret key to authenticate that this user owns the account. This prevents a different person from pretending they own the account and spending the MOBI (more below under Authentication).
24
24
 
25
+ ## Sample Application
26
+
27
+ [Flappy Bird](https://github.com/mobius-network/flappy-bird-dapp) has been reimplemented using this new arhictecture and the above simple server code!
28
+
29
+ ## Documentation
30
+
31
+ [[RDoc.info](http://www.rubydoc.info/github/mobius-network/mobius-client-ruby/master)]
32
+
25
33
  ## Installation
26
34
 
27
35
  Add this line to your application's Gemfile:
@@ -50,41 +58,47 @@ You can also obtain free test network MOBI from https://mobius.network/friendbot
50
58
 
51
59
  ### Setting up test user accounts
52
60
 
53
- 1. Create empty Stellar account without a MOBI trustline.
61
+ 1. Create an empty Stellar account without a MOBI trustline.
54
62
  ```
55
63
  $ mobius-cli create account
56
64
  ```
57
- 2. Create stellar account with 1,000 test-net MOBI
65
+ 2. Create a stellar account with 1,000 test-net MOBI
58
66
  ```
59
67
  $ mobius-cli create dapp-account
60
68
  ```
61
- 3. Create stellar account with 1,000 test-net MOBI and the specified application public key added as a signer
69
+ 3. Create a stellar account with 1,000 test-net MOBI and the specified application public key added as a signer
62
70
  ```
63
71
  $ mobius-cli create dapp-account -a <Your application public key>
64
72
  ```
65
73
 
66
74
  ### Account Creation Wizard
67
75
 
68
- Below command will create and setup the 4 account types above for testing and generate a simple HTML test interface that simulates the DApp Store authentication functionality (obtaining a challenge request from an app, signing it, and then openining the specified app passing in a JWT encoded token the application will use to verify this request is from the user that owns the specified MOBI account).
76
+ The below command will create and setup the 4 account types above for testing and generate a simple HTML test interface that simulates the DApp Store authentication functionality (obtaining a challenge request from an app, signing it, and then opening the specified app passing in a JWT encoded token the application will use to verify this request is from the user that owns the specified MOBI account).
69
77
 
70
78
  ```
71
79
  $ mobius-cli create dev-wallet
72
80
  ```
73
81
 
82
+ ## Production Server Setup
83
+
84
+ Your production server must use HTTPS and set the below header on the `/auth` endpoint:
85
+
86
+ `Access-Control-Allow-Origin: *`
87
+
74
88
  ## Authentication
75
89
 
76
90
  ### Explanation
77
91
 
78
92
  When a user opens an app through the DApp Store it tells the app what Mobius account it should use for payment.
79
93
 
80
- The application needs to ensure that the user actually owns the secret key to the Mobius account and that this isn't a replay attack from a user who captured a previous request and is replyaing it.
94
+ The application needs to ensure that the user actually owns the secret key to the Mobius account and that this isn't a replay attack from a user who captured a previous request and is replaying it.
81
95
 
82
96
  This authentication is accomplished through the following process:
83
97
 
84
98
  * When the user opens an app in the DApp Store it requests a challenge from the application.
85
99
  * The challenge is a payment transaction of 1 XLM from and to the application account. It is never sent to the network - it is just used for authentication.
86
- * The application generates the challenge transaction on request, signs it with itss own private key, and sends it to user.
87
- * User receives the challenge transaction, verifies it is signed by the application's secret key by checking it the application's published public key that it receives through the DApp Store, and then signs the transaction which its own private key and sends it back to application along with its public key.
100
+ * The application generates the challenge transaction on request, signs it with its own private key, and sends it to user.
101
+ * The user receives the challenge transaction and verifies it is signed by the application's secret key by checking it against the application's published public key (that it receives through the DApp Store). Then the user signs the transaction with its own private key and sends it back to application along with its public key.
88
102
  * Application checks that challenge transaction is now signed by itself and the public key that was passed in. Time bounds are also checked to make sure this isn't a replay attack. If everything passes the server replies with a token the application can pass in to "login" with the specified public key and use it for payment (it would have previously given the app access to the public key by adding the app's public key as a signer).
89
103
 
90
104
  Note: the challenge transaction also has time bounds to restrict the time window when it can be used.
@@ -97,7 +111,7 @@ See demo at:
97
111
 
98
112
  ### Sample Server Implementation
99
113
 
100
- ```
114
+ ```ruby
101
115
  class AuthController < ApplicationController
102
116
  skip_before_action :verify_authenticity_token, :only => [:authenticate]
103
117
 
@@ -148,7 +162,7 @@ end
148
162
 
149
163
  ### Explanation
150
164
 
151
- After the user completes the authentication process they have a token T. They now pass it to the application to "login" which tells the application which Mobius account to withdraw MOBI from (the user public key) when a payment is needed. For a web application the token is generally passed in via a `token` request parameter. Upon opening the website/loading the application it checks that the token is valid (within time bounds etc) and the account in the token has added the app as a signer so it can withraw MOBI from it.
165
+ After the user completes the authentication process they have a token. They now pass it to the application to "login" which tells the application which Mobius account to withdraw MOBI from (the user public key) when a payment is needed. For a web application the token is generally passed in via a `token` request parameter. Upon opening the website/loading the application it checks that the token is valid (within time bounds etc) and the account in the token has added the app as a signer so it can withdraw MOBI from it.
152
166
 
153
167
 
154
168
  See demo at:
@@ -159,7 +173,7 @@ See demo at:
159
173
 
160
174
  ### Sample Server Implementation
161
175
 
162
- ```
176
+ ```ruby
163
177
  class AppController < ApplicationController
164
178
  skip_before_action :verify_authenticity_token, :only => [:pay]
165
179
 
@@ -182,9 +196,9 @@ class AppController < ApplicationController
182
196
  render plain: app.balance
183
197
  end
184
198
 
185
- # POST /pay
186
- def pay
187
- app.pay(ROUND_PRICE)
199
+ # POST /charge
200
+ def charge
201
+ app.charge(ROUND_PRICE)
188
202
  render plain: app.balance
189
203
  rescue Mobius::Client::Error::InsufficientFunds
190
204
  render :gone
@@ -211,13 +225,9 @@ class AppController < ApplicationController
211
225
  end
212
226
  ```
213
227
 
214
- ## Sample Application
215
-
216
- [Flappy Bird](https://github.com/mobius-network/flappy-bird-dapp) has been reimplemented using this new arhictecture and the above simple server code!
217
-
218
228
  ## CLI Test Implementation
219
229
 
220
- Normally, as mentioned the Mobius DApp Store will request a challenge, validate and sign it, pass it back to the application to obtain an access token, and then open the application and pass in the token.
230
+ Normally the Mobius DApp Store will request a challenge, validate and sign it, pass it back to the application to obtain an access token, and then open the application and pass in the token.
221
231
 
222
232
  For development purposes you can use the simple HTML test interface generated via `mobius-cli create dev-wallet` as mentioned above in the "Account Creation Wizard" section or you can use the these CLI commands.
223
233
 
@@ -237,10 +247,6 @@ end
237
247
 
238
248
  Check `lib/mobius/cli/auth.rb` for details.
239
249
 
240
- ## Documentation
241
-
242
- [[RDoc.info](http://www.rubydoc.info/github/mobius-network/mobius-client-ruby/master)]
243
-
244
250
  ## Development
245
251
 
246
252
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -257,4 +263,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
257
263
 
258
264
  ## Code of Conduct
259
265
 
260
- Everyone interacting in the Mobius::Client project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/mobius-client/blob/master/CODE_OF_CONDUCT.md).
266
+ Everyone interacting in the Mobius::Client project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/mobius-network/mobius-client-ruby/blob/master/CODE_OF_CONDUCT.md).
@@ -19,109 +19,97 @@ class Mobius::Client::App
19
19
  # @return [Float] User balance.
20
20
  def balance
21
21
  validate!
22
- balance_object["balance"].to_f
22
+ user_account.balance
23
23
  end
24
24
 
25
25
  # Returns application balance.
26
26
  # @return [Float] Application balance.
27
27
  def app_balance
28
- app_balance_object["balance"].to_f
28
+ app_account.balance
29
29
  end
30
30
 
31
31
  # Makes payment.
32
- # @param amount [Float] Payment amount.
32
+ # @param amount [Numeric, String] Payment amount.
33
33
  # @param target_address [String] Optional: third party receiver address.
34
- # rubocop:disable Metrics/AbcSize
34
+ # @deprecated use {#charge} instead
35
35
  def pay(amount, target_address: nil)
36
- current_balance = balance
37
- raise Mobius::Client::Error::InsufficientFunds if current_balance < amount.to_f
38
- envelope_base64 = payment_tx(amount.to_f, target_address).to_envelope(app_keypair).to_xdr(:base64)
39
- post_tx(envelope_base64).tap do
40
- [app_account, user_account].each(&:reload!)
36
+ warn "[DEPRECATED] method Mobius::Client::App#pay is deprecated and will be removed, use Mobius::Client::App#charge instead"
37
+ charge(amount, target_address)
38
+ end
39
+
40
+ # Charges user's wallet.
41
+ # @param amount [Numeric, String] Payment amount.
42
+ # @param target_address [String] Optional: third party receiver address.
43
+ def charge(amount, target_address: nil)
44
+ amount = cast_amount(amount)
45
+
46
+ raise Mobius::Client::Error::InsufficientFunds if balance < amount
47
+
48
+ submit_tx do |operations|
49
+ operations << payment_op(amount, dest: app_keypair, src: user_keypair)
50
+ operations << payment_op(amount, dest: target_address, src: app_keypair) if target_address
41
51
  end
42
52
  rescue Faraday::ClientError => err
43
53
  handle(err)
44
54
  end
45
- # rubocop:enable Metrics/AbcSize
46
55
 
47
- # Sends money from application account to third party.
56
+ # Sends money from user's account to third party.
48
57
  # @param amount [Float] Payment amount.
49
58
  # @param address [String] Target address.
50
- # rubocop:disable Metrics/AbcSize
51
59
  def transfer(amount, address)
52
- current_balance = app_balance
53
- raise Mobius::Client::Error::InsufficientFunds if current_balance < amount.to_f
54
- envelope_base64 = transfer_tx(amount.to_f, address).to_envelope(app_keypair).to_xdr(:base64)
55
- post_tx(envelope_base64).tap do
56
- [app_account, user_account].each(&:reload!)
57
- end
60
+ amount = cast_amount(amount)
61
+ raise Mobius::Client::Error::InsufficientFunds if app_balance < amount
62
+ submit_tx { |operations| operations << payment_op(amount, dest: address, src: user_keypair) }
58
63
  rescue Faraday::ClientError => err
59
64
  handle(err)
60
65
  end
61
- # rubocop:enable Metrics/AbcSize
62
66
 
63
- private
64
-
65
- def post_tx(txe)
66
- Mobius::Client.horizon_client.horizon.transactions._post(tx: txe)
67
- end
68
-
69
- def payment_tx(amount, target_address)
70
- Stellar::Transaction.for_account(
71
- account: user_keypair,
72
- sequence: user_account.next_sequence_value,
73
- fee: target_address.nil? ? FEE : FEE * 2
74
- ).tap do |t|
75
- t.operations << payment_op(amount.to_f)
76
- t.operations << third_party_payment_op(target_address, amount) if target_address
67
+ # Sends money from application account to user's account or target_address, if given
68
+ # @param amount [Float] Payment amount.
69
+ # @param target_address [String] Optional: third party receiver address.
70
+ def payout(amount, target_address: user_keypair.address)
71
+ amount = cast_amount(amount)
72
+ raise Mobius::Client::Error::InsufficientFunds if app_balance < amount
73
+ submit_tx do |operations|
74
+ operations << payment_op(amount, dest: target_address, src: app_keypair)
77
75
  end
76
+ rescue Faraday::ClientError => err
77
+ handle(err)
78
78
  end
79
79
 
80
- def payment_op(amount)
81
- Stellar::Operation.payment(
82
- destination: app_keypair,
83
- amount: Stellar::Amount.new(amount.to_f, Mobius::Client.stellar_asset).to_payment
84
- )
85
- end
80
+ private
86
81
 
87
- def third_party_payment_op(target_address, amount)
88
- Stellar::Operation.payment(
89
- source_account: app_keypair,
90
- destination: Mobius::Client.to_keypair(target_address),
91
- amount: Stellar::Amount.new(amount.to_f, Mobius::Client.stellar_asset).to_payment
92
- )
93
- end
82
+ def submit_tx
83
+ return unless block_given?
94
84
 
95
- def transfer_tx(amount, address)
96
- Stellar::Transaction.payment(
85
+ tx = Stellar::Transaction.for_account(
97
86
  account: user_keypair,
98
87
  sequence: user_account.next_sequence_value,
99
- destination: Mobius::Client.to_keypair(address),
100
- amount: Stellar::Amount.new(amount.to_f, Mobius::Client.stellar_asset).to_payment
101
88
  )
102
- end
103
89
 
104
- def validate!
105
- raise Mobius::Client::Error::AuthorisationMissing unless authorized?
106
- raise Mobius::Client::Error::TrustlineMissing if balance_object.nil?
107
- end
90
+ yield(tx.operations)
108
91
 
109
- def limit
110
- balance_object["limit"].to_f
92
+ tx.fee = FEE * tx.operations.size
93
+
94
+ txe = tx.to_envelope(app_keypair).to_xdr(:base64)
95
+ post_txe(txe).tap { [app_account, user_account].each(&:reload!) }
111
96
  end
112
97
 
113
- def balance_object
114
- find_balance(user_account.info.balances)
98
+ def post_txe(txe)
99
+ Mobius::Client.horizon_client.horizon.transactions._post(tx: txe)
115
100
  end
116
101
 
117
- def app_balance_object
118
- find_balance(app_account.info.balances)
102
+ def payment_op(amount, dest:, src:)
103
+ Stellar::Operation.payment(
104
+ source_account: Mobius::Client.to_keypair(src),
105
+ destination: Mobius::Client.to_keypair(dest),
106
+ amount: Stellar::Amount.new(amount, Mobius::Client.stellar_asset).to_payment
107
+ )
119
108
  end
120
109
 
121
- def find_balance(balances)
122
- balances.find do |s|
123
- s["asset_code"] == Mobius::Client.asset_code && s["asset_issuer"] == Mobius::Client.asset_issuer
124
- end
110
+ def validate!
111
+ raise Mobius::Client::Error::AuthorisationMissing unless authorized?
112
+ raise Mobius::Client::Error::TrustlineMissing unless user_account.trustline_exists?
125
113
  end
126
114
 
127
115
  def app_keypair
@@ -147,5 +135,11 @@ class Mobius::Client::App
147
135
  raise err
148
136
  end
149
137
 
138
+ def cast_amount(amount)
139
+ Float(amount).to_d
140
+ rescue ArgumentError
141
+ raise Mobius::Client::Error::InvalidAmount, "Invalid amount provided: `#{amount}`"
142
+ end
143
+
150
144
  FEE = 100
151
145
  end
@@ -5,14 +5,14 @@ class Mobius::Client::Blockchain::Account
5
5
  # @!method initialize(keypair)
6
6
  # @param keypair [Stellar::Keypair] account keypair
7
7
  # @!scope instance
8
- param :keypair
8
+ param :keypair, Mobius::Client.method(:to_keypair)
9
9
 
10
10
  # Returns true if trustline exists for given asset and limit is positive.
11
11
  # @param asset [Stellar::Asset] Stellar asset to check or :native
12
12
  # @return [Boolean] true if trustline exists
13
13
  def trustline_exists?(asset = Mobius::Client.stellar_asset)
14
14
  balance = find_balance(asset)
15
- (balance && !balance.dig("limit").to_f.zero?) || false
15
+ (balance && !balance.dig("limit").to_d.zero?) || false
16
16
  end
17
17
 
18
18
  # Returns balance for given asset
@@ -20,7 +20,7 @@ class Mobius::Client::Blockchain::Account
20
20
  # @return [Float] Balance value.
21
21
  def balance(asset = Mobius::Client.stellar_asset)
22
22
  balance = find_balance(asset)
23
- balance && balance.dig("balance").to_f
23
+ balance && balance.dig("balance").to_d
24
24
  end
25
25
 
26
26
  # Returns true if given keypair is added as cosigner to current account.
@@ -46,4 +46,8 @@ class Mobius::Client::Error < StandardError
46
46
  # Raised if unknown or empty value has passed to KeyPairFactory
47
47
  class UnknownKeyPairType < self
48
48
  end
49
+
50
+ # Raised, when NaN provided as an amount for payment operation
51
+ class InvalidAmount < self
52
+ end
49
53
  end
@@ -1,5 +1,5 @@
1
1
  module Mobius
2
2
  module Client
3
- VERSION = "0.2.1".freeze
3
+ VERSION = "0.3.0".freeze
4
4
  end
5
5
  end
data/lib/mobius/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "bigdecimal"
2
+ require "bigdecimal/util"
1
3
  require "constructor_shortcut"
2
4
  require "dry-initializer"
3
5
  require "stellar-sdk"
@@ -7,6 +9,11 @@ require "jwt"
7
9
 
8
10
  require "mobius/client/version"
9
11
 
12
+ begin
13
+ require "pry-byebug"
14
+ rescue LoadError
15
+ end
16
+
10
17
  module Mobius
11
18
  module Cli
12
19
  autoload :Base, "mobius/cli/base"
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "rspec", "~> 3.0"
33
33
  spec.add_development_dependency "rubocop", "~> 0.53"
34
34
  spec.add_development_dependency "rubocop-rspec", "~> 1.23"
35
+ spec.add_development_dependency "pry-byebug"
35
36
  spec.add_development_dependency "simplecov", ">= 0.16.1"
36
37
  spec.add_development_dependency "simplecov-console", ">= 0.4.2"
37
38
  spec.add_development_dependency "timecop", "~> 0.9", ">= 0.9.1"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobius-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Viktor Sokolov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-26 00:00:00.000000000 Z
11
+ date: 2018-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,6 +114,20 @@ dependencies:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
116
  version: '1.23'
117
+ - !ruby/object:Gem::Dependency
118
+ name: pry-byebug
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
117
131
  - !ruby/object:Gem::Dependency
118
132
  name: simplecov
119
133
  requirement: !ruby/object:Gem::Requirement
@@ -392,7 +406,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
392
406
  version: '0'
393
407
  requirements: []
394
408
  rubyforge_project:
395
- rubygems_version: 2.6.13
409
+ rubygems_version: 2.7.6
396
410
  signing_key:
397
411
  specification_version: 4
398
412
  summary: Mobius Ruby Client