coinfresh 0.0.1
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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/coinfresh.gemspec +27 -0
- data/lib/coinfresh.rb +59 -0
- data/lib/coinfresh/api/base.rb +18 -0
- data/lib/coinfresh/api/cash_flow.rb +20 -0
- data/lib/coinfresh/api/currency.rb +19 -0
- data/lib/coinfresh/api/market.rb +25 -0
- data/lib/coinfresh/api/order.rb +43 -0
- data/lib/coinfresh/api/wallet.rb +21 -0
- data/lib/coinfresh/api/withdraw.rb +21 -0
- data/lib/coinfresh/api_operation/create.rb +12 -0
- data/lib/coinfresh/api_operation/destroy.rb +11 -0
- data/lib/coinfresh/api_operation/find.rb +16 -0
- data/lib/coinfresh/api_operation/list.rb +13 -0
- data/lib/coinfresh/api_operation/new.rb +11 -0
- data/lib/coinfresh/api_operation/update.rb +12 -0
- data/lib/coinfresh/client.rb +39 -0
- data/lib/coinfresh/http.rb +106 -0
- data/lib/coinfresh/model/base.rb +175 -0
- data/lib/coinfresh/model/cash_flow.rb +17 -0
- data/lib/coinfresh/model/currency.rb +18 -0
- data/lib/coinfresh/model/market.rb +18 -0
- data/lib/coinfresh/model/order.rb +22 -0
- data/lib/coinfresh/model/trade.rb +18 -0
- data/lib/coinfresh/model/wallet.rb +22 -0
- data/lib/coinfresh/model/withdraw.rb +21 -0
- data/lib/coinfresh/version.rb +3 -0
- data/spec/api/cash_flow_spec.rb +23 -0
- data/spec/api/currency_spec.rb +24 -0
- data/spec/api/market_spec.rb +52 -0
- data/spec/api/order_spec.rb +55 -0
- data/spec/api/wallet_spec.rb +40 -0
- data/spec/api/withdraw_spec.rb +43 -0
- data/spec/cassettes/Coinfresh_Api_CashFlow/_list/gets_all_the_cashflows_for_currency.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Currency/_list/gets_all_the_currencies.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Market/_find/gets_a_market_with_the_given_id.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Market/_list/gets_all_the_markets.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Market/_trades/gets_all_trades_for_a_market.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Order/_cancel/cancels_an_order.yml +65 -0
- data/spec/cassettes/Coinfresh_Api_Order/_create/creates_an_order.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Order/_list/gets_all_the_orders.yml +67 -0
- data/spec/cassettes/Coinfresh_Api_Order/_my/gets_all_the_orders.yml +67 -0
- data/spec/cassettes/Coinfresh_Api_Wallet/_create/creates_a_wallet_with_the_given_id.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Wallet/_list/gets_all_the_wallets.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Withdraw/_create/creates_a_wallet_with_the_given_id.yml +64 -0
- data/spec/cassettes/Coinfresh_Api_Withdraw/_list/gets_all_the_wallets.yml +64 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/common_let_helpers.rb +62 -0
- data/spec/support/json_api_helpers.rb +5 -0
- metadata +190 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'api-auth'
|
2
|
+
|
3
|
+
module Coinfresh
|
4
|
+
|
5
|
+
module Http
|
6
|
+
class Unauthorized < Exception; end
|
7
|
+
class ResourceNotFound < Exception; end
|
8
|
+
class BadRequest < Exception; end
|
9
|
+
|
10
|
+
def base_uri(path, params = {})
|
11
|
+
uri = URI.parse(self.class.base_scope_url)
|
12
|
+
uri.path = path
|
13
|
+
uri.query = URI.encode_www_form(params) if params.any?
|
14
|
+
uri
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(path, params ={}, parse=true)
|
18
|
+
uri = base_uri("#{api_prefix}/#{path}", params)
|
19
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
20
|
+
make_api_request(req, uri, parse)
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(path, body = "", parse=true)
|
24
|
+
uri = base_uri("#{api_prefix}/#{path}")
|
25
|
+
req = Net::HTTP::Put.new(uri.request_uri)
|
26
|
+
req.body = body
|
27
|
+
req.add_field("Content-Type", "application/json")
|
28
|
+
make_api_request(req, uri, parse)
|
29
|
+
end
|
30
|
+
|
31
|
+
def multipart_post(path, params, parse = true)
|
32
|
+
uri = base_uri("#{api_prefix}/#{path}")
|
33
|
+
req = Net::HTTP::Post::Multipart.new(uri.request_uri, params)
|
34
|
+
make_api_request(req, uri, parse)
|
35
|
+
end
|
36
|
+
|
37
|
+
def post(path, body ="", parse = true)
|
38
|
+
uri = base_uri("#{api_prefix}/#{path}")
|
39
|
+
req = Net::HTTP::Post.new(uri.request_uri)
|
40
|
+
req.body = body
|
41
|
+
req.add_field("Content-Type", "application/json")
|
42
|
+
make_api_request(req, uri, parse)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(path, parse=true)
|
46
|
+
uri = base_uri("#{api_prefix}/#{path}")
|
47
|
+
req = Net::HTTP::Delete.new(uri.request_uri)
|
48
|
+
make_api_request(req, uri, parse)
|
49
|
+
end
|
50
|
+
|
51
|
+
def make_api_request(req, uri, parse = true)
|
52
|
+
if self.access_token && self.secret_key
|
53
|
+
req = ApiAuth.sign!(req, self.access_token, self.secret_key)
|
54
|
+
end
|
55
|
+
make_request(req, uri, parse)
|
56
|
+
end
|
57
|
+
|
58
|
+
def make_request(req, uri, parse = true)
|
59
|
+
req.add_field("Accept", "text/json")
|
60
|
+
n = Net::HTTP.new(uri.host, uri.port)
|
61
|
+
if uri.scheme == "https"
|
62
|
+
n.use_ssl = true
|
63
|
+
end
|
64
|
+
res = n.start do |http|
|
65
|
+
http.request(req)
|
66
|
+
end
|
67
|
+
parse_response(res, parse)
|
68
|
+
end
|
69
|
+
|
70
|
+
def parse_response(res, parse)
|
71
|
+
if res.body !~ /^\s*$/ && !res.body.nil?
|
72
|
+
body = parse ? JSON.parse(res.body) : res.body
|
73
|
+
end
|
74
|
+
|
75
|
+
case res
|
76
|
+
when Net::HTTPNotFound
|
77
|
+
raise Coinfresh::Http::ResourceNotFound.new(body["message"])
|
78
|
+
when Net::HTTPSuccess
|
79
|
+
body
|
80
|
+
when Net::HTTPUnauthorized
|
81
|
+
raise Coinfresh::Http::Unauthorized.new(body["message"])
|
82
|
+
when Net::HTTPBadRequest
|
83
|
+
message = ""
|
84
|
+
if body["error"]
|
85
|
+
message = [body["error"].to_s, body["message"].to_s].join(" ")
|
86
|
+
end
|
87
|
+
|
88
|
+
if body["errors"]
|
89
|
+
message = body["errors"]
|
90
|
+
end
|
91
|
+
|
92
|
+
raise Coinfresh::Http::BadRequest.new(message)
|
93
|
+
when Net::HTTPSeeOther
|
94
|
+
res["Location"]
|
95
|
+
else
|
96
|
+
raise "Unknown #{res.class} response. #{body["message"]}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def api_prefix; "/api/v1"; end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class ResourceNotSaved < Exception; end
|
4
|
+
class AttributeReadOnly < Exception; end
|
5
|
+
|
6
|
+
class Base
|
7
|
+
|
8
|
+
attr_accessor :client
|
9
|
+
|
10
|
+
def self.inspect
|
11
|
+
attr_list = attributes.inject([]) do |a, (attr, opts)|
|
12
|
+
a << "#{attr}: #{opts[:type]}"
|
13
|
+
end * ", "
|
14
|
+
"#{super}(#{attr_list})"
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
attr_list = self.class.attributes.inject([]) do |a, (attr, opts)|
|
19
|
+
if has_attribute?(attr)
|
20
|
+
a << "#{attr}: #{self[attr].inspect}"
|
21
|
+
else
|
22
|
+
a
|
23
|
+
end
|
24
|
+
end * ", "
|
25
|
+
"#<#{self.class} #{attr_list}>"
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(values = {}, client = nil)
|
29
|
+
self.client = client
|
30
|
+
values.each_pair do |k, v|
|
31
|
+
self.send("#{k}=", v) if respond_to?("#{k}=") && !v.nil?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_params
|
36
|
+
self.class.attributes.inject({}) do |h, (attr, opts)|
|
37
|
+
has_attribute?(attr) ? h.merge(attr => paramify(self[attr])) : h
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
class << self
|
43
|
+
|
44
|
+
attr_accessor :attributes
|
45
|
+
def set_attributes(attrs)
|
46
|
+
self.attributes = attrs
|
47
|
+
attrs.each_pair do |name, options|
|
48
|
+
attr_reader name
|
49
|
+
define_method "#{name}=" do |value|
|
50
|
+
if options[:readonly] && !instance_variable_get("@#{name}").nil?
|
51
|
+
raise AttributeReadOnly
|
52
|
+
end
|
53
|
+
write_attribute("#{name}", convert_attribute(value, options))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def inherited(subclass)
|
59
|
+
if !self.attributes.nil?
|
60
|
+
subclass.attributes = self.attributes
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_association(name, klass, options = {})
|
65
|
+
attr_accessor "#{name}_id"
|
66
|
+
attr_reader name
|
67
|
+
self.attributes["#{name}_id".intern] = {type: :foreign_key}
|
68
|
+
define_method "#{name}=" do |attributes|
|
69
|
+
write_attribute("#{name}_id", attributes["id"])
|
70
|
+
if options[:polymorphic]
|
71
|
+
obj = polymorphic_object(attributes, options[:accepted_types])
|
72
|
+
else
|
73
|
+
obj = klass.new(attributes, client)
|
74
|
+
end
|
75
|
+
write_attribute("#{name}", obj)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_many_association(name, klass, options = {})
|
80
|
+
attr_reader name
|
81
|
+
self.attributes[name.intern] = {type: :has_many_association}
|
82
|
+
define_method "#{name}=" do |arr|
|
83
|
+
many = arr.collect do |attributes|
|
84
|
+
if options[:polymorphic]
|
85
|
+
polymorphic_object(attributes, options[:accepted_types])
|
86
|
+
else
|
87
|
+
klass.new(attributes, client)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
write_attribute(name, many)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
def ==(o)
|
97
|
+
self.class == o.class && !self.id.nil? && self.id != "" && self.id == o.id
|
98
|
+
end
|
99
|
+
alias_method :eql?, :==
|
100
|
+
|
101
|
+
def [](val)
|
102
|
+
self.send(val)
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def save
|
107
|
+
if self.id.nil?
|
108
|
+
#puts "saving #{self}, #{self.to_params}}"
|
109
|
+
item = api.create(self.to_params)
|
110
|
+
puts "item: #{item.id}"
|
111
|
+
item
|
112
|
+
else
|
113
|
+
api.update(self.id, self.to_params)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def reload
|
118
|
+
raise ResourceNotSaved if self.id.nil?
|
119
|
+
api.find(self.id)
|
120
|
+
end
|
121
|
+
|
122
|
+
def destroy
|
123
|
+
raise ResourceNotSaved if self.id.nil?
|
124
|
+
api.destroy(self.id)
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
def write_attribute(name, value)
|
129
|
+
instance_variable_set("@#{name}", value)
|
130
|
+
end
|
131
|
+
|
132
|
+
def api
|
133
|
+
raise NotImplementedError
|
134
|
+
end
|
135
|
+
|
136
|
+
def has_attribute?(attr)
|
137
|
+
instance_variable_defined?("@#{attr}")
|
138
|
+
end
|
139
|
+
|
140
|
+
def paramify(val)
|
141
|
+
if val.kind_of? Coinfresh::Model::Base
|
142
|
+
val.to_params
|
143
|
+
elsif val.kind_of? Array
|
144
|
+
val.collect{|v| paramify(v) }
|
145
|
+
else
|
146
|
+
val
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def convert_attribute(val, options)
|
151
|
+
case options[:type]
|
152
|
+
when :int
|
153
|
+
val.to_i
|
154
|
+
when :string
|
155
|
+
val.to_s
|
156
|
+
when :date
|
157
|
+
val.kind_of?(Date) ? val : Date.parse(val)
|
158
|
+
when :decimal
|
159
|
+
val.to_f
|
160
|
+
when :boolean
|
161
|
+
val == "true"
|
162
|
+
when :datetime
|
163
|
+
val.kind_of?(DateTime) ? val : DateTime.parse(val)
|
164
|
+
when :datetime
|
165
|
+
val.kind_of?(Time) ? val : Time.parse(val)
|
166
|
+
when :foreign_key
|
167
|
+
(val == "" || val.nil?) ? nil : val.to_i
|
168
|
+
else
|
169
|
+
val
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class CashFlow < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
created_at: {type: :datetime, readonly: true},
|
6
|
+
cash_type: {type: :string, readonly: true},
|
7
|
+
amount: {type: :decimal, readonly: true}
|
8
|
+
)
|
9
|
+
|
10
|
+
private
|
11
|
+
def api
|
12
|
+
client.cash_flows
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class Currency < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
name: {type: :string, readonly: true},
|
6
|
+
ticker: {type: :string, readonly: true},
|
7
|
+
withdraw_transaction_fee: {type: :decimal, readonly: true},
|
8
|
+
deposit_confirmations: {type: :int, readonly: true}
|
9
|
+
)
|
10
|
+
|
11
|
+
private
|
12
|
+
def api
|
13
|
+
client.currencies
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class Market < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
name: {type: :string, readonly: true},
|
6
|
+
last_price: {type: :decimal, readonly: true}
|
7
|
+
)
|
8
|
+
|
9
|
+
has_association :base_currency, Coinfresh::Model::Currency
|
10
|
+
has_association :currency, Coinfresh::Model::Currency
|
11
|
+
|
12
|
+
private
|
13
|
+
def api
|
14
|
+
client.markets
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class Order < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
created_at: {type: :datetime, readonly: true},
|
6
|
+
updated_at: {type: :datetime, readonly: true},
|
7
|
+
filled_amount: {type: :decimal, readonly: true},
|
8
|
+
status: {type: :string},
|
9
|
+
order_type: {type: :string},
|
10
|
+
amount: {type: :decimal},
|
11
|
+
price: {type: :decimal},
|
12
|
+
market_id: {type: :integer}
|
13
|
+
)
|
14
|
+
|
15
|
+
private
|
16
|
+
def api
|
17
|
+
client.orders
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class Trade < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
created_at: {type: :datetime, readonly: true},
|
6
|
+
amount: {type: :decimal, readonly: true},
|
7
|
+
price: {type: :decimal, readonly: true},
|
8
|
+
buy_order_id: {type: :int, readonly: true},
|
9
|
+
sell_order_id: {type: :int, readonly: true}
|
10
|
+
)
|
11
|
+
|
12
|
+
private
|
13
|
+
def api
|
14
|
+
client.markets
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class Wallet < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
balance: {type: :decimal, readonly: true},
|
6
|
+
deposit_address: {type: :string, readonly: true},
|
7
|
+
in_escrow: {type: :decimal, readonly: true},
|
8
|
+
total_withdraw: {type: :decimal, readonly: true},
|
9
|
+
total_deposit: {type: :decimal, readonly: true},
|
10
|
+
unconfirmed_deposit: {type: :decimal, readonly: true},
|
11
|
+
)
|
12
|
+
|
13
|
+
has_association :currency, Coinfresh::Model::Currency
|
14
|
+
|
15
|
+
private
|
16
|
+
def api
|
17
|
+
client.wallets
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Coinfresh
|
2
|
+
module Model
|
3
|
+
class Withdraw < Base
|
4
|
+
set_attributes(id: {type: :int, readonly: true},
|
5
|
+
created_at: {type: :datetime, readonly: true},
|
6
|
+
address: {type: :string, readonly: true},
|
7
|
+
amount: {type: :decimal, readonly: true},
|
8
|
+
txid: {type: :string, readonly: true},
|
9
|
+
status: {type: :string, readonly: true},
|
10
|
+
)
|
11
|
+
|
12
|
+
has_association :wallet, Coinfresh::Model::Wallet
|
13
|
+
|
14
|
+
private
|
15
|
+
def api
|
16
|
+
client.withdraws
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Coinfresh
|
4
|
+
module Api
|
5
|
+
describe CashFlow, :vcr do
|
6
|
+
|
7
|
+
describe "#list" do
|
8
|
+
it "gets all the cashflows for currency" do
|
9
|
+
cash_flows = client.cash_flows.list(limit: 2, currency: 'BTC')
|
10
|
+
expect(cash_flows.count).to be > 0
|
11
|
+
cash_flow = cash_flows.first
|
12
|
+
expect(cash_flow.id).not_to be_nil
|
13
|
+
expect(cash_flow.created_at).not_to be_nil
|
14
|
+
expect(cash_flow.amount).not_to be_nil
|
15
|
+
expect(cash_flow.cash_type).not_to be_nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|