stellar_base-rails 0.3.0 → 0.4.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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +19 -29
  3. data/app/concepts/stellar_base/bridge_callbacks/bridge_callback_policy.rb +14 -0
  4. data/app/concepts/stellar_base/bridge_callbacks/contracts/{process.rb → create.rb} +5 -5
  5. data/app/concepts/stellar_base/bridge_callbacks/operations/create.rb +31 -0
  6. data/app/concepts/stellar_base/withdrawal_requests/contracts/create.rb +38 -0
  7. data/app/concepts/stellar_base/withdrawal_requests/operations/create.rb +53 -0
  8. data/app/concepts/stellar_base/withdrawal_requests/withdrawal_request_policy.rb +14 -0
  9. data/app/controllers/stellar_base/bridge_callbacks_controller.rb +1 -1
  10. data/app/controllers/stellar_base/withdraw_controller.rb +35 -0
  11. data/app/models/stellar_base/bridge_callback.rb +1 -14
  12. data/app/models/stellar_base/withdrawal_request.rb +4 -0
  13. data/app/representers/application_representer.rb +3 -0
  14. data/app/representers/withdrawal_request_representer.rb +13 -0
  15. data/app/services/stellar_base/bridge_callbacks/process.rb +9 -7
  16. data/app/services/stellar_base/gen_random_string.rb +10 -0
  17. data/app/services/stellar_base/withdrawal_requests/call_on_withdraw.rb +30 -0
  18. data/app/services/stellar_base/withdrawal_requests/determine_fee.rb +21 -0
  19. data/app/services/stellar_base/withdrawal_requests/find_withdrawal_request.rb +40 -0
  20. data/app/services/stellar_base/withdrawal_requests/gen_memo.rb +19 -0
  21. data/app/services/stellar_base/withdrawal_requests/process.rb +27 -0
  22. data/app/twins/application_twin.rb +3 -0
  23. data/app/twins/withdrawal_request_twin.rb +13 -0
  24. data/config/routes.rb +2 -3
  25. data/db/migrate/20180816014433_create_stellar_base_bridge_callbacks.rb +21 -0
  26. data/db/migrate/20180816110314_create_stellar_base_withdrawal_requests.rb +25 -0
  27. data/db/migrate/20180816135847_unique_stellar_base_bridge_callbacks_operation_id.rb +11 -0
  28. data/lib/stellar_base.rb +33 -0
  29. data/lib/stellar_base/factories.rb +3 -0
  30. data/lib/stellar_base/factories/bridge_callbacks.rb +9 -0
  31. data/lib/stellar_base/factories/withdrawal_requests.rb +14 -0
  32. data/lib/stellar_base/version.rb +1 -1
  33. metadata +97 -5
  34. data/app/concepts/stellar_base/bridge_callbacks/operations/process.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a83410d8dc46aa9b3e3a7501ff339f620e4bb16073a5156b935a942249204fcd
4
- data.tar.gz: b76ff40be0ee4f471c37198856157f152ef041d14736e2fdf0eebfaf42f3a770
3
+ metadata.gz: 15b69658233c066ee56074dd0bcf6ceed2abb687d873322e7d732f36bfb9d96c
4
+ data.tar.gz: 29e95f9804ccd034b6a9d210792ad19800936fbfddc9ae7c0588dd62bce0231d
5
5
  SHA512:
6
- metadata.gz: 2db9224965d1e88f9f6f8b1deba1e50bcf6ac32c7226da4ba8cbaee737c6d9834b0d663861597cabb65eb9e601e13d6e695b7097d44c73df34ca2e6419f3e7f6
7
- data.tar.gz: 1bf1a4bd010321297c05638303b681756d1c16089d006e8acdc3e4a50fc438d45ef9a35cd5404d0b73c5f9105ef2a1af505d246a9ea243ae32d09d7401e98224
6
+ metadata.gz: 9340c436c18b047df93e5a6ca27321c4fe586ed0c60f449e3d55a2042cfd8ac9f19411d7fdb2e6954c4767d64dbd8c22f2c436f0475daa0d1513bcaf27018f57
7
+ data.tar.gz: 123e430f1e9f8fc2a938bcd928e09a34174f3325c7df4a9649d48de58e255bed5a4e3b2961118485ed220c08a6368761c3bddbcaab35cd3b612769080f991a0c
data/README.md CHANGED
@@ -11,6 +11,11 @@ Adding modules to your routes:
11
11
  mount StellarBase::Engine => "/stellar_base"
12
12
  ```
13
13
 
14
+ ```sh
15
+ rails stellar_base:install:migrations
16
+ rails db:migrate
17
+ ```
18
+
14
19
  ### Configuration
15
20
  Create an initializer in your rails application:
16
21
 
@@ -30,41 +35,21 @@ end
30
35
 
31
36
 
32
37
  #### c.modules
33
- - Value(s): array of symbols
34
- - bridge_callbacks - when supplied this will mount the `/bridge_callbacks` endpoint
38
+ You can supply what endpoints you want to activate with the gem
39
+
40
+ - Value(s): array of symbols. See the [modules documentation](docs/modules.md) for more details.
35
41
  - Default: `%i(bridge_callbacks)`
36
- - You can supply what endpoints you want to activate with the gem
37
- - `bridge_callbacks` - this will mount a HTTP/S POST endpoint that acts as callback receiver for bridge server payments on the path. It will call your `.on_bridge_callback` class.
42
+
43
+ #### c.distribution_account
44
+ This is the same distribution account that is setup in bridge. Currently, it is used in the `/withdraw` endpoint -- to tell the user to send the assets there.
45
+
46
+ - Value: Stellar account address
38
47
 
39
48
  #### c.horizon_url
40
49
  - Value(s): String, url to horizon
41
50
  - Default: https://horizon.stellar.org
42
51
  - This is where the engine will check bridge callbacks if `c.check_bridge_callbacks_authenticity` is turned on
43
52
 
44
- #### c.on_bridge_callback
45
- - Value(s): Class
46
- - Default: None
47
- - Once the bridge_receive endpoint receives a callback, the class will be called with .call
48
- - The class will be passed with the bridge server callback payload contained in a `StellarBase::BridgeCallback` object.
49
- - The class will be expected to return a boolean, return true if the callback was processed properly
50
- - Warning: The bridge server will may post multiple callbacks with the same ID, make sure you handle these correctly. https://github.com/stellar/bridge-server/blob/master/readme_bridge.md#callbacksreceive
51
-
52
-
53
- #### c.check_bridge_callbacks_authenticity
54
- - Value(s): `true` or `false`
55
- - Default: `false`
56
- - This secures the `/bridge_callbacks` endpoint from fake transactions by checking the transaction ID and it's contents against the Stellar Blockchain. If it doesn't add up, `/bridge_callbacks` endpoint will respond with a 422
57
-
58
- #### c.check_bridge_callbacks_mac_payload
59
- - Value(s): `true` or `false`
60
- - Default: `false`
61
- - This secures the `/bridge_callbacks` endpoint from fake transactions by checking the `X_PAYLOAD_MAC` header for 1.) existence and 2.) if it matches the HMAC-SH256 encoded raw request body
62
-
63
- #### c.bridge_callbacks_mac_key
64
- - Value(s): Any Stellar Private Key, it should be the same as the mac_key configured in your bridge server
65
- - Default: None
66
- - This is used to verify the contents of `X_PAYLOAD_MAC` by encoding the raw request body with the decoded `bridge_callback_mac_key` as the key
67
-
68
53
  ## Installation
69
54
  Add this line to your application's Gemfile:
70
55
 
@@ -78,7 +63,12 @@ $ bundle
78
63
  ```
79
64
 
80
65
  ## Contributing
81
- Contribution directions go here.
66
+
67
+ ```ruby
68
+ cp spec/config.yml{.sample,}
69
+ ```
70
+
71
+ Edit the `spec/config.yml` file.
82
72
 
83
73
  ## License
84
74
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,14 @@
1
+ module StellarBase
2
+ module BridgeCallbacks
3
+ class BridgeCallbackPolicy
4
+
5
+ def initialize(_, _)
6
+ end
7
+
8
+ def create?
9
+ StellarBase.included_module?(:withdraw)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -1,9 +1,9 @@
1
1
  module StellarBase
2
2
  module BridgeCallbacks
3
3
  module Contracts
4
- class Process < ApplicationContract
4
+ class Create < ApplicationContract
5
5
 
6
- property :id
6
+ property :operation_id
7
7
  property :from
8
8
  property :route
9
9
  property :amount
@@ -14,7 +14,7 @@ module StellarBase
14
14
  property :data
15
15
  property :transaction_id
16
16
 
17
- validates :id, presence: true
17
+ validates :operation_id, presence: true
18
18
  validates :transaction_id, presence: true
19
19
  validates :from, presence: true
20
20
  validates :amount, presence: true
@@ -27,10 +27,10 @@ module StellarBase
27
27
  end
28
28
 
29
29
  result = BridgeCallbacks::Check.({
30
- operation_id: id,
30
+ operation_id: operation_id,
31
31
  transaction_id: transaction_id,
32
32
  params: {
33
- id: id,
33
+ id: operation_id,
34
34
  from: from,
35
35
  route: route,
36
36
  amount: amount,
@@ -0,0 +1,31 @@
1
+ module StellarBase
2
+ module BridgeCallbacks
3
+ module Operations
4
+ class Create < ApplicationOperation
5
+ step Policy::Pundit(BridgeCallbackPolicy, :create?)
6
+ step :assign_operation_id!
7
+ step :find_model!
8
+ step Model(BridgeCallback, :new)
9
+ step Contract::Build(constant: Contracts::Create)
10
+ step Contract::Validate(key: :bridge_callback)
11
+ step Contract::Persist()
12
+ step :process!
13
+
14
+ def find_model!(options, params:, **)
15
+ operation_id = params[:bridge_callback][:operation_id]
16
+ bridge_callback = BridgeCallback.find_by(operation_id: operation_id)
17
+ options["model"] = bridge_callback
18
+ bridge_callback.present? ? Railway.pass_fast! : true
19
+ end
20
+
21
+ def assign_operation_id!(options, params:, **)
22
+ params[:bridge_callback][:operation_id] = params[:bridge_callback][:id]
23
+ end
24
+
25
+ def process!(options, **)
26
+ BridgeCallbacks::Process.(options["model"])
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ module Contracts
4
+ class Create < ApplicationContract
5
+
6
+ property :asset_type
7
+ property :asset_code
8
+ property :dest
9
+ property :dest_extra
10
+ property :issuer
11
+ property :account_id
12
+ property :memo_type
13
+ property :memo
14
+ property :eta
15
+ property :min_amount
16
+ property :max_amount
17
+ property :fee_fixed
18
+ property :fee_percent
19
+ property :fee_network
20
+
21
+ validates(
22
+ *%i[
23
+ asset_type
24
+ asset_code
25
+ dest
26
+ issuer
27
+ account_id
28
+ fee_network
29
+ fee_fixed
30
+ fee_percent
31
+ ],
32
+ presence: true
33
+ )
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,53 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ module Operations
4
+ class Create < ApplicationOperation
5
+
6
+ DEFAULT_ETA = (10 * 60).freeze
7
+
8
+ step self::Policy::Pundit(WithdrawalRequestPolicy, :create?)
9
+ step Model(WithdrawalRequest, :new)
10
+ step :find_withdrawal_asset_details!
11
+ success :set_defaults!
12
+ step Contract::Build(constant: Contracts::Create)
13
+ step Contract::Validate(key: :withdrawal_request)
14
+ step Contract::Persist()
15
+
16
+ private
17
+
18
+ def find_withdrawal_asset_details!(options, params:, **)
19
+ withdrawable_assets = StellarBase.configuration.withdrawable_assets
20
+ details = withdrawable_assets.find do |e|
21
+ e[:asset_code] == params[:withdrawal_request][:asset_code]
22
+ end
23
+
24
+ return Railway.fail_fast! if details.nil?
25
+
26
+ options["withdrawal_asset_details"] = details
27
+ return true
28
+ end
29
+
30
+ def set_defaults!(options, withdrawal_asset_details:, params:, **)
31
+ fee_network = DetermineFee.network(
32
+ withdrawal_asset_details[:network],
33
+ params[:withdrawal_request][:fee_network],
34
+ )
35
+ params[:withdrawal_request].merge!({
36
+ asset_type: params[:withdrawal_request][:type],
37
+ issuer: withdrawal_asset_details[:issuer],
38
+ account_id: StellarBase.configuration.distribution_account,
39
+ memo_type: "text",
40
+ memo: GenMemo.(),
41
+ eta: DEFAULT_ETA,
42
+ min_amount: 0.0,
43
+ max_amount: nil,
44
+ fee_fixed: DetermineFee.(withdrawal_asset_details[:fee_fixed]),
45
+ fee_percent: DetermineFee.(withdrawal_asset_details[:fee_percent]),
46
+ fee_network: fee_network,
47
+ })
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,14 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ class WithdrawalRequestPolicy
4
+
5
+ def initialize(_, _)
6
+ end
7
+
8
+ def create?
9
+ StellarBase.included_module?(:withdraw)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -4,7 +4,7 @@ module StellarBase
4
4
  before_action :verify_mac_payload, if: :check_mac_payload?
5
5
 
6
6
  def create
7
- op = BridgeCallbacks::Operations::Process.(bridge_callback: callback_params)
7
+ op = BridgeCallbacks::Operations::Create.(bridge_callback: callback_params)
8
8
 
9
9
  respond_to do |f|
10
10
  f.json do
@@ -0,0 +1,35 @@
1
+ module StellarBase
2
+ class WithdrawController < ApplicationController
3
+
4
+ WITHDRAWAL_REQUEST_PARAMS = %i[
5
+ type
6
+ asset_code
7
+ dest
8
+ dest_extra
9
+ fee_network
10
+ ]
11
+
12
+ def create
13
+ op = WithdrawalRequests::Operations::Create.(withdrawal_request: withdrawal_request_params)
14
+
15
+ respond_to do |f|
16
+ f.json do
17
+ if op.success?
18
+ twin = WithdrawalRequestTwin.new(op["model"])
19
+ representer = WithdrawalRequestRepresenter.new(twin)
20
+ render json: representer
21
+ else
22
+ head :unprocessable_entity
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def withdrawal_request_params
31
+ params.permit(*WITHDRAWAL_REQUEST_PARAMS)
32
+ end
33
+
34
+ end
35
+ end
@@ -1,17 +1,4 @@
1
1
  module StellarBase
2
- class BridgeCallback
3
- include Virtus.model
4
- # Attributes and params from
5
- # https://github.com/stellar/bridge-server/blob/master/readme_bridge.md#callbacksreceive
6
- attribute :id, String
7
- attribute :from, String
8
- attribute :route, String
9
- attribute :amount, Float
10
- attribute :asset_code, String
11
- attribute :asset_issuer, String
12
- attribute :memo_type, String
13
- attribute :memo, String
14
- attribute :data, String
15
- attribute :transaction_id, String
2
+ class BridgeCallback < ApplicationRecord
16
3
  end
17
4
  end
@@ -0,0 +1,4 @@
1
+ module StellarBase
2
+ class WithdrawalRequest < ApplicationRecord
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRepresenter < Representable::Decorator
2
+ include Representable::JSON
3
+ end
@@ -0,0 +1,13 @@
1
+ class WithdrawalRequestRepresenter < ApplicationRepresenter
2
+
3
+ property :account_id
4
+ property :memo_type
5
+ property :memo
6
+ property :min_amount
7
+ property :max_amount
8
+ property :fee_fixed
9
+ property :fee_percent
10
+ property :fee_network
11
+ property :extra_info
12
+
13
+ end
@@ -3,7 +3,15 @@ module StellarBase
3
3
  class Process
4
4
  def self.call(callback)
5
5
  callback_class.(callback)
6
- rescue NameError => e
6
+ end
7
+
8
+ private
9
+
10
+ def self.callback_class
11
+ on_bridge_callback = StellarBase.configuration.on_bridge_callback
12
+ return on_bridge_callback if on_bridge_callback.respond_to?(:call)
13
+ on_bridge_callback.constantize
14
+ rescue NameError
7
15
  error_message = [
8
16
  "StellarBase.on_bridge_callback isn't configured or the",
9
17
  "configured callback class doesn't exist:",
@@ -12,12 +20,6 @@ module StellarBase
12
20
 
13
21
  raise NameError, error_message
14
22
  end
15
-
16
- private
17
-
18
- def self.callback_class
19
- StellarBase.configuration.on_bridge_callback.constantize
20
- end
21
23
  end
22
24
  end
23
25
  end
@@ -0,0 +1,10 @@
1
+ module StellarBase
2
+ class GenRandomString
3
+
4
+ def self.call(length:)
5
+ o = [(0..9), ('A'..'Z')].map(&:to_a).flatten
6
+ string = (0...length).map { o[rand(o.length)] }.join
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ class CallOnWithdraw
4
+
5
+ extend LightService::Action
6
+ expects :withdrawal_request, :bridge_callback, :on_withdraw
7
+
8
+ ON_WITHDRAW_ERROR = "`on_withdraw` must be a string of an object " \
9
+ "that responds to `.call` or the object itself"
10
+
11
+ executed do |c|
12
+ callback = callback_from(c.on_withdraw)
13
+ callback.(c.withdrawal_request, c.bridge_callback)
14
+ end
15
+
16
+ def self.callback_from(on_withdraw)
17
+ if on_withdraw.respond_to?(:constantize)
18
+ on_withdraw = on_withdraw.constantize
19
+ end
20
+
21
+ if !on_withdraw.respond_to?(:call)
22
+ fail ArgumentError, ON_WITHDRAW_ERROR
23
+ end
24
+
25
+ on_withdraw
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ class DetermineFee
4
+
5
+ DEFAULT = 0.0
6
+ # NOTE: Hard-code default network fees for now.
7
+ DEFAULT_NETWORK = {
8
+ bitcoin: 0.0001,
9
+ }.with_indifferent_access.freeze
10
+
11
+ def self.call(v)
12
+ v || DEFAULT
13
+ end
14
+
15
+ def self.network(network, v)
16
+ v || DEFAULT_NETWORK.fetch(network)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ class FindWithdrawalRequest
4
+
5
+ extend LightService::Action
6
+ expects :bridge_callback
7
+ promises :withdrawal_request
8
+
9
+ MATCH_WITHDRAWAL_REQUEST_TO_BRIDGE_CALLBACK_MAP = {
10
+ asset_code: :asset_code,
11
+ issuer: :asset_issuer,
12
+ memo_type: :memo_type,
13
+ memo: :memo,
14
+ }.freeze
15
+
16
+ executed do |c|
17
+ bridge_callback = c.bridge_callback
18
+ c.withdrawal_request = withdrawal_request = WithdrawalRequest.
19
+ find_by(memo: bridge_callback.memo)
20
+
21
+ if withdrawal_request.nil?
22
+ c.skip_remaining!
23
+ next c
24
+ end
25
+
26
+ map = MATCH_WITHDRAWAL_REQUEST_TO_BRIDGE_CALLBACK_MAP
27
+ mismatch = map.any? do |withdrawal_request_attr, bridge_callback_attr|
28
+ withdrawal_request.send(withdrawal_request_attr) !=
29
+ bridge_callback.send(bridge_callback_attr)
30
+ end
31
+
32
+ if mismatch
33
+ c.skip_remaining!
34
+ next c
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ class GenMemo
4
+
5
+ LENGTH = 8
6
+
7
+ def self.call
8
+ loop do
9
+ memo = GenRandomString.(length: LENGTH)
10
+ if !WithdrawalRequest.exists?(memo: memo)
11
+ return memo
12
+ break
13
+ end
14
+ end
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module StellarBase
2
+ module WithdrawalRequests
3
+ class Process
4
+
5
+ extend LightService::Organizer
6
+
7
+ def self.call(
8
+ bridge_callback,
9
+ on_withdraw: StellarBase.configuration.on_withdraw
10
+ )
11
+ with(
12
+ bridge_callback: bridge_callback,
13
+ on_withdraw: on_withdraw,
14
+ ).reduce(actions)
15
+ end
16
+
17
+ def self.actions
18
+ [
19
+ FindWithdrawalRequest,
20
+ CallOnWithdraw,
21
+ ]
22
+ end
23
+ private_class_method :actions
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationTwin < Disposable::Twin
2
+ feature Expose
3
+ end
@@ -0,0 +1,13 @@
1
+ class WithdrawalRequestTwin < ApplicationTwin
2
+
3
+ property :account_id
4
+ property :memo_type
5
+ property :memo
6
+ property :min_amount
7
+ property :max_amount
8
+ property :fee_fixed
9
+ property :fee_percent
10
+ property :fee_network
11
+ property :extra_info
12
+
13
+ end
data/config/routes.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  StellarBase::Engine.routes.draw do
2
- if StellarBase.included_module?(:bridge_callbacks)
3
- resources :bridge_callbacks, only: [:create], defaults: { format: "json" }
4
- end
2
+ resources :bridge_callbacks, only: [:create], defaults: { format: "json" }
3
+ get "/withdraw" => "withdraw#create", as: :withdraw
5
4
  end
6
5
 
@@ -0,0 +1,21 @@
1
+ class CreateStellarBaseBridgeCallbacks < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :stellar_base_bridge_callbacks do |t|
4
+ t.string :operation_id, null: false
5
+ t.string :from, null: false
6
+ t.string :route
7
+ t.decimal :amount, null: false
8
+ t.string :asset_code
9
+ t.string :asset_issuer
10
+ t.string :memo_type
11
+ t.string :memo
12
+ t.string :data
13
+ t.string :transaction_id
14
+ t.index %i[asset_code asset_issuer], name: :index_stellar_base_bridge_callbacks_on_asset
15
+ t.index :memo
16
+ t.index :operation_id
17
+ t.index :transaction_id
18
+ t.timestamps
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ class CreateStellarBaseWithdrawalRequests < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :stellar_base_withdrawal_requests do |t|
4
+ t.string :asset_type, null: false
5
+ t.string :asset_code, null: false
6
+ t.string :dest, null: false
7
+ t.string :issuer, null: false
8
+ t.string :dest_extra
9
+ t.string :account_id
10
+ t.string :memo_type
11
+ t.string :memo
12
+ t.integer :eta
13
+ t.decimal :min_amount, null: false, default: 0.0
14
+ t.decimal :max_amount
15
+ t.decimal :fee_fixed, null: false, default: 0.0
16
+ t.decimal :fee_percent, null: false, default: 0.0
17
+ t.decimal :fee_network, null: false, default: 0.0
18
+ t.string :extra_info
19
+ t.index([:asset_type, :asset_code], {
20
+ name: :index_stellar_base_withdrawal_requests_on_asset,
21
+ })
22
+ t.timestamps
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,11 @@
1
+ class UniqueStellarBaseBridgeCallbacksOperationId < ActiveRecord::Migration[5.1]
2
+ def up
3
+ remove_index :stellar_base_bridge_callbacks, :operation_id
4
+ add_index :stellar_base_bridge_callbacks, :operation_id, unique: true
5
+ end
6
+
7
+ def down
8
+ remove_index :stellar_base_bridge_callbacks, :operation_id
9
+ add_index :stellar_base_bridge_callbacks, :operation_id
10
+ end
11
+ end
data/lib/stellar_base.rb CHANGED
@@ -5,8 +5,10 @@ require "virtus"
5
5
  require "httparty"
6
6
  require "trailblazer-rails"
7
7
  require "disposable"
8
+ require "multi_json"
8
9
  require "reform"
9
10
  require "reform/form/coercion"
11
+ require "representable"
10
12
 
11
13
  require "stellar_base/engine"
12
14
 
@@ -17,15 +19,46 @@ module StellarBase
17
19
  has :horizon_url, default: "https://horizon.stellar.org"
18
20
  has :modules, default: [:bridge_callbacks]
19
21
 
22
+ has :distribution_account, classes: [NilClass, String]
23
+
20
24
  has :on_bridge_callback
21
25
  has :check_bridge_callbacks_authenticity, default: false
22
26
  has :check_bridge_callbacks_mac_payload, default: false
23
27
  has :bridge_callbacks_mac_key, default: false
28
+
29
+ has :withdrawable_assets, classes: [NilClass, Array, String, Pathname]
30
+ has :on_withdraw
31
+ end
32
+
33
+ after_configuration_change do
34
+ self.convert_config_withdraw!
24
35
  end
25
36
 
26
37
  def self.included_module?(module_name)
27
38
  self.configuration.modules&.include?(module_name)
28
39
  end
40
+
41
+ def self.convert_config_withdraw!
42
+ withdrawable_assets = self.configuration.withdrawable_assets
43
+ return if withdrawable_assets.is_a?(Array) || withdrawable_assets.nil?
44
+
45
+ array_of_hashes = try_from_yaml_file_path(withdrawable_assets) ||
46
+ try_from_json(withdrawable_assets)
47
+
48
+ self.configuration.withdrawable_assets =
49
+ array_of_hashes.map(&:with_indifferent_access)
50
+ end
51
+
52
+ def self.try_from_json(str)
53
+ JSON.parse(str)
54
+ rescue JSON::ParserError
55
+ end
56
+
57
+ def self.try_from_yaml_file_path(str)
58
+ YAML.load_file(str.to_s)
59
+ rescue Errno::ENOENT
60
+ end
61
+
29
62
  end
30
63
 
31
64
  require "stellar_base/horizon_client"
@@ -0,0 +1,3 @@
1
+ Dir[File.join(File.dirname(__FILE__), "factories/*.rb")].each do |f|
2
+ require f
3
+ end
@@ -0,0 +1,9 @@
1
+ FactoryBot.define do
2
+
3
+ factory :stellar_base_bridge_callback, class: "StellarBase::BridgeCallback" do
4
+ sequence(:operation_id) { |n| n.to_s }
5
+ from "from"
6
+ amount 100.0
7
+ end
8
+
9
+ end
@@ -0,0 +1,14 @@
1
+ FactoryBot.define do
2
+
3
+ factory(:stellar_base_withdrawal_request, {
4
+ class: "StellarBase::WithdrawalRequest",
5
+ }) do
6
+ asset_type "crypto"
7
+ asset_code "BTC"
8
+ issuer "issuer"
9
+ memo_type "text"
10
+ dest "destination"
11
+ sequence(:memo) {|n| "XYZ#{n}" }
12
+ end
13
+
14
+ end
@@ -1,3 +1,3 @@
1
1
  module StellarBase
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stellar_base-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ace Subido
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-08 00:00:00.000000000 Z
11
+ date: 2018-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: virtus
@@ -136,6 +136,48 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: disposable
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: representable
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: multi_json
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
139
181
  - !ruby/object:Gem::Dependency
140
182
  name: sqlite3
141
183
  requirement: !ruby/object:Gem::Requirement
@@ -192,6 +234,34 @@ dependencies:
192
234
  - - ">="
193
235
  - !ruby/object:Gem::Version
194
236
  version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: factory_bot_rails
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: stellar-sdk
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ version: '0'
195
265
  description: API Endpoints for the Stellar Protocol
196
266
  email:
197
267
  - ace.subido@gmail.com
@@ -207,15 +277,23 @@ files:
207
277
  - app/assets/stylesheets/stellar_base/application.css
208
278
  - app/concepts/stellar_base/application_contract.rb
209
279
  - app/concepts/stellar_base/application_operation.rb
210
- - app/concepts/stellar_base/bridge_callbacks/contracts/process.rb
211
- - app/concepts/stellar_base/bridge_callbacks/operations/process.rb
280
+ - app/concepts/stellar_base/bridge_callbacks/bridge_callback_policy.rb
281
+ - app/concepts/stellar_base/bridge_callbacks/contracts/create.rb
282
+ - app/concepts/stellar_base/bridge_callbacks/operations/create.rb
283
+ - app/concepts/stellar_base/withdrawal_requests/contracts/create.rb
284
+ - app/concepts/stellar_base/withdrawal_requests/operations/create.rb
285
+ - app/concepts/stellar_base/withdrawal_requests/withdrawal_request_policy.rb
212
286
  - app/controllers/stellar_base/application_controller.rb
213
287
  - app/controllers/stellar_base/bridge_callbacks_controller.rb
288
+ - app/controllers/stellar_base/withdraw_controller.rb
214
289
  - app/helpers/stellar_base/application_helper.rb
215
290
  - app/jobs/stellar_base/application_job.rb
216
291
  - app/mailers/stellar_base/application_mailer.rb
217
292
  - app/models/stellar_base/application_record.rb
218
293
  - app/models/stellar_base/bridge_callback.rb
294
+ - app/models/stellar_base/withdrawal_request.rb
295
+ - app/representers/application_representer.rb
296
+ - app/representers/withdrawal_request_representer.rb
219
297
  - app/services/stellar_base/bridge_callbacks/check.rb
220
298
  - app/services/stellar_base/bridge_callbacks/compare.rb
221
299
  - app/services/stellar_base/bridge_callbacks/get_operation.rb
@@ -228,11 +306,25 @@ files:
228
306
  - app/services/stellar_base/bridge_callbacks/mac_payloads/encode_params.rb
229
307
  - app/services/stellar_base/bridge_callbacks/process.rb
230
308
  - app/services/stellar_base/bridge_callbacks/verify_mac_payload.rb
309
+ - app/services/stellar_base/gen_random_string.rb
310
+ - app/services/stellar_base/withdrawal_requests/call_on_withdraw.rb
311
+ - app/services/stellar_base/withdrawal_requests/determine_fee.rb
312
+ - app/services/stellar_base/withdrawal_requests/find_withdrawal_request.rb
313
+ - app/services/stellar_base/withdrawal_requests/gen_memo.rb
314
+ - app/services/stellar_base/withdrawal_requests/process.rb
315
+ - app/twins/application_twin.rb
316
+ - app/twins/withdrawal_request_twin.rb
231
317
  - app/views/layouts/stellar_base/application.html.erb
232
318
  - config/routes.rb
319
+ - db/migrate/20180816014433_create_stellar_base_bridge_callbacks.rb
320
+ - db/migrate/20180816110314_create_stellar_base_withdrawal_requests.rb
321
+ - db/migrate/20180816135847_unique_stellar_base_bridge_callbacks_operation_id.rb
233
322
  - lib/stellar_base-rails.rb
234
323
  - lib/stellar_base.rb
235
324
  - lib/stellar_base/engine.rb
325
+ - lib/stellar_base/factories.rb
326
+ - lib/stellar_base/factories/bridge_callbacks.rb
327
+ - lib/stellar_base/factories/withdrawal_requests.rb
236
328
  - lib/stellar_base/horizon_client.rb
237
329
  - lib/stellar_base/version.rb
238
330
  - lib/tasks/stellar_base_tasks.rake
@@ -256,7 +348,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
256
348
  version: '0'
257
349
  requirements: []
258
350
  rubyforge_project:
259
- rubygems_version: 2.7.3
351
+ rubygems_version: 2.7.7
260
352
  signing_key:
261
353
  specification_version: 4
262
354
  summary: Mountable Stellar API Endpoints for Rails
@@ -1,21 +0,0 @@
1
- module StellarBase
2
- module BridgeCallbacks
3
- module Operations
4
- class Process < ApplicationOperation
5
- step :model!
6
- step Contract::Build(constant: Contracts::Process)
7
- step Contract::Validate(key: :bridge_callback)
8
- step Contract::Persist(method: :sync)
9
- step :process!
10
-
11
- def model!(options, **)
12
- options["model"] = BridgeCallback.new
13
- end
14
-
15
- def process!(options, **)
16
- BridgeCallbacks::Process.(options["model"])
17
- end
18
- end
19
- end
20
- end
21
- end