remitano 1.5.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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +13 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +127 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +115 -0
  9. data/Rakefile +51 -0
  10. data/bin/remitano +20 -0
  11. data/lib/remitano.rb +2 -0
  12. data/lib/remitano/client.rb +98 -0
  13. data/lib/remitano/client/action_confirmations.rb +29 -0
  14. data/lib/remitano/client/coin_accounts.rb +9 -0
  15. data/lib/remitano/client/coin_collection.rb +18 -0
  16. data/lib/remitano/client/coin_withdrawals.rb +24 -0
  17. data/lib/remitano/client/collection.rb +29 -0
  18. data/lib/remitano/client/fiat_accounts.rb +9 -0
  19. data/lib/remitano/client/fiat_collection.rb +18 -0
  20. data/lib/remitano/client/helper.rb +14 -0
  21. data/lib/remitano/client/merchant_charges.rb +24 -0
  22. data/lib/remitano/client/merchant_withdrawals.rb +38 -0
  23. data/lib/remitano/client/net.rb +100 -0
  24. data/lib/remitano/client/offers.rb +21 -0
  25. data/lib/remitano/client/orders.rb +26 -0
  26. data/lib/remitano/client/public/offers.rb +18 -0
  27. data/lib/remitano/client/public/price_ladders.rb +7 -0
  28. data/lib/remitano/client/public/rates.rb +12 -0
  29. data/lib/remitano/client/trades.rb +37 -0
  30. data/lib/remitano/version.rb +3 -0
  31. data/remitano.gemspec +40 -0
  32. data/spec/client/merchant_charges_spec.rb +66 -0
  33. data/spec/client/merchant_withdrawals_spec.rb +111 -0
  34. data/spec/coin_accounts_spec.rb +11 -0
  35. data/spec/fiat_accounts_spec.rb +11 -0
  36. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_charges/_create/invalid_params/raises_error.yml +51 -0
  37. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_charges/_create/valid_params/returns_created_charge.yml +53 -0
  38. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_charges/_get/object_exists/returns_charge_data.yml +48 -0
  39. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_charges/_get/object_not_found/raises_error.yml +46 -0
  40. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_withdrawals/_create/invalid_params/raises_error.yml +52 -0
  41. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_withdrawals/_create/valid_params/auto_confirms_withdrawal_with_htop_and_returns_created_withdrawal.yml +296 -0
  42. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_withdrawals/_get/object_exists/returns_withdrawal_data.yml +48 -0
  43. data/spec/fixtures/vcr_cassettes/Remitano_Client_merchant_withdrawals/_get/object_not_found/raises_error.yml +46 -0
  44. data/spec/fixtures/vcr_cassettes/remitano/coin_accounts/me.yml +52 -0
  45. data/spec/fixtures/vcr_cassettes/remitano/fiat_accounts/me.yml +52 -0
  46. data/spec/fixtures/vcr_cassettes/remitano/my_offers/sell.yml +47 -0
  47. data/spec/fixtures/vcr_cassettes/remitano/offers/update.yml +94 -0
  48. data/spec/fixtures/vcr_cassettes/remitano/orders/cancel.yml +54 -0
  49. data/spec/fixtures/vcr_cassettes/remitano/orders/create.yml +54 -0
  50. data/spec/fixtures/vcr_cassettes/remitano/orders/open.yml +54 -0
  51. data/spec/fixtures/vcr_cassettes/remitano/price_ladders/sell.yml +48 -0
  52. data/spec/fixtures/vcr_cassettes/remitano/rates.yml +44 -0
  53. data/spec/fixtures/vcr_cassettes/remitano/trades/active.yml +46 -0
  54. data/spec/fixtures/vcr_cassettes/remitano/trades/completed.yml +46 -0
  55. data/spec/fixtures/vcr_cassettes/remitano/trades/release.yml +144 -0
  56. data/spec/offers_spec.rb +18 -0
  57. data/spec/orders_spec.rb +29 -0
  58. data/spec/public/price_ladders_spec.rb +11 -0
  59. data/spec/public/rates_spec.rb +10 -0
  60. data/spec/spec_helper.rb +25 -0
  61. data/spec/support/crendentials.rb +12 -0
  62. data/spec/support/request_usec.rb +5 -0
  63. data/spec/support/vcr.rb +22 -0
  64. data/spec/trades_spec.rb +39 -0
  65. metadata +329 -0
@@ -0,0 +1,29 @@
1
+ require_relative "collection"
2
+
3
+ module Remitano
4
+ class Client::ActionConfirmations < Client::Collection
5
+ attr_accessor :config
6
+
7
+ def initialize(config:)
8
+ @config = config
9
+ end
10
+
11
+ def confirm!(id)
12
+ config.net.post("/action_confirmations/#{id}/confirm", token: config.authenticator_token).execute
13
+ end
14
+
15
+ def confirm_by_hotp!(id, otp_counter)
16
+ otp = config.hotp(otp_counter)
17
+ config.net.post("/action_confirmations/#{id}/confirm", token: otp).execute
18
+ end
19
+
20
+ def confirm_if_neccessary!(response)
21
+ if response.is_action_confirmation && response.status != "confirmed"
22
+ puts "Submitting token"
23
+ confirm!(response.id)
24
+ else
25
+ response
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "coin_collection"
2
+
3
+ module Remitano
4
+ class Client::CoinAccounts < Client::CoinCollection
5
+ def me
6
+ config.net.get("/coin_accounts/me?coin_currency=#{coin}").execute
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "collection"
2
+
3
+ module Remitano
4
+ class Client::CoinCollection < Client::Collection
5
+ attr_reader :config, :coin
6
+
7
+ def initialize(coin, config:)
8
+ @coin = coin
9
+ super(config: config)
10
+ end
11
+
12
+ class << self
13
+ def of_coin(coin, config:)
14
+ new(coin, config: config)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "coin_collection"
2
+
3
+ module Remitano
4
+ class Client::CoinWithdrawals < Client::CoinCollection
5
+ def my_withdrawals
6
+ config.net.get("/coin_withdrawals?coin_currency=#{coin}").execute
7
+ end
8
+
9
+ def cancel(id)
10
+ config.net.post("/coin_withdrawals/#{id}/cancel").execute
11
+ end
12
+
13
+ def withdraw(coin_address:, coin_amount:, destination_tag: nil)
14
+ params = {
15
+ coin_address: coin_address,
16
+ coin_currency: coin,
17
+ coin_amount: coin_amount,
18
+ destination_tag: destination_tag,
19
+ }
20
+ response = config.net.post("/coin_withdrawals", coin_withdrawal: params).execute
21
+ config.action_confirmations.confirm_if_neccessary!(response)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ module Remitano
2
+ class Client::Collection
3
+ attr_accessor :path, :resource_name
4
+ attr_accessor :config
5
+
6
+ def initialize(config:)
7
+ @config = config
8
+ name = self.class.name.underscore.split("/").last
9
+ self.resource_name = name.singularize
10
+ self.path = "/#{name}"
11
+ end
12
+
13
+ def all
14
+ config.net.new(config: config).get(self.path).execute
15
+ end
16
+
17
+ def create(params = {})
18
+ config.net.new(config: config).post(self.path, { self.resource_name => params }).execute
19
+ end
20
+
21
+ def get(id)
22
+ config.net.new(config: config).get("#{self.path}/#{id}").execute
23
+ end
24
+
25
+ def update(id, params = {})
26
+ config.net.new(config: config).patch("#{self.path}/#{id}", { self.resource_name => params }).execute
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "fiat_collection"
2
+
3
+ module Remitano
4
+ class Client::FiatAccounts < Client::FiatCollection
5
+ def me
6
+ config.net.get("/fiat_accounts/me?currency=#{currency}").execute
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "collection"
2
+
3
+ module Remitano
4
+ class Client::FiatCollection < Client::Collection
5
+ attr_reader :config, :currency
6
+
7
+ def initialize(currency, config:)
8
+ @currency = currency
9
+ super(config: config)
10
+ end
11
+
12
+ class << self
13
+ def of_currency(currency, config:)
14
+ new(currency, config: config)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module Remitano
2
+ module Client::Helper
3
+ def self.parse_json(str)
4
+ json = JSON.parse(str)
5
+ if json.is_a? Array
6
+ json.map do |hash|
7
+ Hashie::Mash[hash]
8
+ end
9
+ else
10
+ Hashie::Mash[json]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Remitano
4
+ class Client::MerchantCharges
5
+ attr_reader :config
6
+
7
+ def initialize(config:)
8
+ @config = config
9
+ end
10
+
11
+ def get(id)
12
+ config.net.get("/merchant/merchant_deposit_requests/#{id}").execute
13
+ end
14
+
15
+ def create(coin_currency:, coin_amount:, cancelled_or_completed_callback_url:)
16
+ config.net.post(
17
+ "/merchant/merchant_deposit_requests",
18
+ coin_currency: coin_currency,
19
+ coin_amount: coin_amount,
20
+ cancelled_or_completed_callback_url: cancelled_or_completed_callback_url
21
+ ).execute
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Remitano
4
+ class Client::MerchantWithdrawals
5
+ attr_reader :config
6
+
7
+ def initialize(config:)
8
+ @config = config
9
+ end
10
+
11
+ def get(id)
12
+ config.net.get("/merchant/merchant_withdrawal_requests/#{id}").execute
13
+ end
14
+
15
+ def create(
16
+ merchant_withdrawal_ref:, coin_currency:, coin_amount:, receiver_pay_fee:, cancelled_or_completed_callback_url:,
17
+ coin_address: nil, destination_tag: nil, remitano_username: nil, remitano_phone_number: nil
18
+ )
19
+ withdrawal = config.net.post(
20
+ "/merchant/merchant_withdrawal_requests",
21
+ merchant_withdrawal_ref: merchant_withdrawal_ref,
22
+ coin_currency: coin_currency,
23
+ coin_amount: coin_amount,
24
+ receiver_pay_fee: receiver_pay_fee,
25
+ cancelled_or_completed_callback_url: cancelled_or_completed_callback_url,
26
+ coin_address: coin_address,
27
+ destination_tag: destination_tag,
28
+ remitano_username: remitano_username,
29
+ remitano_phone_number: remitano_phone_number
30
+ ).execute
31
+ if (action_confirmation_id = withdrawal["action_confirmation_id"]).present?
32
+ config.action_confirmations.confirm_by_hotp!(action_confirmation_id, withdrawal["otp_counter"])
33
+ end
34
+
35
+ withdrawal
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,100 @@
1
+ require 'api-auth'
2
+
3
+ module Remitano
4
+ class Client::Request
5
+ class RequestError < StandardError; end
6
+
7
+ def initialize(request)
8
+ @request = request
9
+ end
10
+
11
+ def execute
12
+ @request.execute do |res, req, result|
13
+ if result.code =~ /^2\d\d$/
14
+ return Remitano::Client::Helper.parse_json(res)
15
+ else
16
+ raise RequestError.new("Error #{result.code} #{res}")
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ class Client::Net
23
+ attr_reader :config
24
+
25
+ def initialize(config:)
26
+ @config = config
27
+ end
28
+
29
+ def self.to_uri(path)
30
+ return "#{server}/api/v1#{path}"
31
+ end
32
+
33
+ def self.server
34
+ @server ||= (ENV['REMITANO_SERVER'] || "https://api.remitano.com")
35
+ end
36
+
37
+ def self.public_get(path, params = {})
38
+ options = {
39
+ :url => self.to_uri(path),
40
+ :method => :get,
41
+ :timeout => 20,
42
+ :headers => {
43
+ :params => params,
44
+ :lang => "vi"
45
+ }
46
+ }
47
+ req = RestClient::Request.new(options)
48
+ req.headers['Content-Type'] = 'application/json'
49
+ Remitano::Client::Request.new(req)
50
+ end
51
+
52
+ def get(path, params={})
53
+ request = new_request(:get, path, params)
54
+ sign_request(request)
55
+ end
56
+
57
+ def post(path, params={})
58
+ request = new_request(:post, path, params)
59
+ sign_request(request)
60
+ end
61
+
62
+ def patch(path, params={})
63
+ request = new_request(:put, path, params)
64
+ sign_request(request)
65
+ end
66
+
67
+ def delete(path, params={})
68
+ request = new_request(:delete, path, params)
69
+ sign_request(request)
70
+ end
71
+
72
+ def new_request(method, path, params={})
73
+ p [:new_request, method, path] if config.verbose
74
+
75
+ options = {
76
+ :method => method,
77
+ :timeout => 20
78
+ }
79
+
80
+ usec = Time.now.usec
81
+ if method == :get
82
+ path += (path.include?("?") ? "&" : "?")
83
+ path += "usec=#{usec}"
84
+ else
85
+ params[:usec] = usec
86
+ options[:payload] = params.to_json
87
+ end
88
+
89
+ options[:url] = self.class.to_uri(path)
90
+
91
+ RestClient::Request.new(options)
92
+ end
93
+
94
+ def sign_request(req)
95
+ req.headers['Content-Type'] = 'application/json'
96
+ ApiAuth.sign!(req, config.key, config.secret)
97
+ Remitano::Client::Request.new(req)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "coin_collection"
2
+ module Remitano
3
+ class Client::Offers < Client::CoinCollection
4
+ def my_offers(side)
5
+ config.net.get("/offers/my_offers?offer_type=#{side}&coin_currency=#{coin}").execute.offers
6
+ end
7
+
8
+ def update(offer_id, params)
9
+ response = config.net.patch("/offers/#{offer_id}?coin_currency=#{coin}", params).execute
10
+ config.action_confirmations.confirm_if_neccessary!(response)
11
+ end
12
+
13
+ def enable(offer_id)
14
+ config.net.patch("/offers/#{offer_id}/enable?coin_currency=#{coin}").execute
15
+ end
16
+
17
+ def disable(offer_id)
18
+ config.net.patch("/offers/#{offer_id}/disable?coin_currency=#{coin}").execute
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ require_relative "coin_collection"
2
+
3
+ module Remitano
4
+ class Client::Orders
5
+ attr_reader :config
6
+
7
+ def initialize(config:)
8
+ @config = config
9
+ end
10
+
11
+ def open(pair, **params)
12
+ config.net.get("/orders/open?pair=#{pair}&#{params.to_query}").execute
13
+ end
14
+
15
+ def cancel(id)
16
+ config.net.post("/orders/#{id}/cancel").execute
17
+ end
18
+
19
+ def create(pair:, side:, price:, amount:)
20
+ config.net.post(
21
+ "/orders",
22
+ pair: pair, side: side, price: price, amount: amount
23
+ ).execute
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "../collection"
2
+ module Remitano
3
+ class Client::PublicOffers < Remitano::Client::Collection
4
+ def offers(params = {} )
5
+ Remitano::Client::Net.public_get("/offers", params).execute.offers
6
+ end
7
+
8
+ def buy_offers(params = {})
9
+ params[:offer_type] = "buy"
10
+ offers(params)
11
+ end
12
+
13
+ def sell_offers(params = {})
14
+ params[:offer_type] = "sell"
15
+ offers(params)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module Remitano
2
+ class Client::PriceLadders
3
+ def fetch(pair)
4
+ Remitano::Client::Net.public_get("/price_ladders/#{pair}").execute
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ require_relative "../collection"
2
+ module Remitano
3
+ class Client::Rates
4
+ def ads
5
+ Remitano::Client::Net.public_get("/rates/ads").execute
6
+ end
7
+
8
+ def exchange
9
+ Remitano::Client::Net.public_get("/rates/exchange").execute
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ require_relative "coin_collection"
2
+ module Remitano
3
+ class Client::Trades < Client::CoinCollection
4
+ def active(buy_or_sell, page: nil)
5
+ options = { trade_type: buy_or_sell, trade_status: "active", coin_currency: coin }
6
+ (options[:page] = page) if page
7
+ config.net.get("/trades?#{options.to_query}").execute
8
+ end
9
+
10
+ def completed(buy_or_sell, page: nil)
11
+ options = { trade_type: buy_or_sell, trade_status: "completed", coin_currency: coin }
12
+ (options[:page] = page) if page
13
+ config.net.get("/trades?#{options.to_query}").execute
14
+ end
15
+
16
+ def release(trade_ref)
17
+ response = config.net.post("/trades/#{trade_ref}/release").execute
18
+ config.action_confirmations.confirm_if_neccessary!(response)
19
+ end
20
+
21
+ def dispute(trade_ref)
22
+ config.net.post("/trades/#{trade_ref}/dispute").execute
23
+ end
24
+
25
+ def mark_as_paid(trade_ref)
26
+ config.net.post("/trades/#{trade_ref}/mark_as_paid").execute
27
+ end
28
+
29
+ def get(id)
30
+ config.net.get("/trades/#{id}").execute.trade
31
+ end
32
+
33
+ def cancel(id)
34
+ config.net.post("/trades/#{id}/cancel").execute
35
+ end
36
+ end
37
+ end