cwallet-ruby 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 +13 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/cwallet-ruby.gemspec +29 -0
- data/lib/cwallet/wallet.rb +21 -0
- data/lib/cwallet/wallet/.DS_Store +0 -0
- data/lib/cwallet/wallet/adapters/em_http.rb +78 -0
- data/lib/cwallet/wallet/adapters/net_http.rb +66 -0
- data/lib/cwallet/wallet/api_client.rb +734 -0
- data/lib/cwallet/wallet/api_errors.rb +120 -0
- data/lib/cwallet/wallet/api_response.rb +41 -0
- data/lib/cwallet/wallet/client.rb +101 -0
- data/lib/cwallet/wallet/cpub.pub +9 -0
- data/lib/cwallet/wallet/models/account.rb +193 -0
- data/lib/cwallet/wallet/models/address.rb +12 -0
- data/lib/cwallet/wallet/models/api_object.rb +46 -0
- data/lib/cwallet/wallet/models/transaction.rb +20 -0
- data/lib/cwallet/wallet/version.rb +5 -0
- metadata +125 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
module Cwallet
|
2
|
+
module Wallet
|
3
|
+
def self.format_error(resp)
|
4
|
+
error = resp.body && (resp.body['errors'] || resp.body['warnings']).first
|
5
|
+
return resp.body unless error
|
6
|
+
message = error['message']
|
7
|
+
message += " (#{error['url']})" if error["url"]
|
8
|
+
message
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.check_response_status(resp)
|
12
|
+
(resp.body['warnings'] || []).each do |warning|
|
13
|
+
message = "WARNING: #{warning['message']}"
|
14
|
+
message += " (#{warning['url']})" if warning["url"]
|
15
|
+
$stderr.puts message
|
16
|
+
end
|
17
|
+
|
18
|
+
# OAuth2 errors
|
19
|
+
if resp.status >= 400 && resp.body['error']
|
20
|
+
raise APIError, resp.body['error_description']
|
21
|
+
end
|
22
|
+
|
23
|
+
# Regular errors
|
24
|
+
if resp.body['errors']
|
25
|
+
case resp.status
|
26
|
+
when 400
|
27
|
+
case resp.body['errors'].first['id']
|
28
|
+
when 'param_required' then raise ParamRequiredError, format_error(resp)
|
29
|
+
when 'invalid_request' then raise InvalidRequestError, format_error(resp)
|
30
|
+
when 'personal_details_required' then raise PersonalDetailsRequiredError, format_error(resp)
|
31
|
+
end
|
32
|
+
raise BadRequestError, format_error(resp)
|
33
|
+
when 401
|
34
|
+
case resp.body['errors'].first['id']
|
35
|
+
when 'authentication_error' then raise AuthenticationError, format_error(resp)
|
36
|
+
when 'unverified_email' then raise UnverifiedEmailError, format_error(resp)
|
37
|
+
when 'invalid_token' then raise InvalidTokenError, format_error(resp)
|
38
|
+
when 'revoked_token' then raise RevokedTokenError, format_error(resp)
|
39
|
+
when 'expired_token' then raise ExpiredTokenError, format_error(resp)
|
40
|
+
end
|
41
|
+
raise AuthenticationError, format_error(resp)
|
42
|
+
when 402 then raise TwoFactorRequiredError, format_error(resp)
|
43
|
+
when 403 then raise InvalidScopeError, format_error(resp)
|
44
|
+
when 404 then raise NotFoundError, format_error(resp)
|
45
|
+
when 422 then raise ValidationError, format_error(resp)
|
46
|
+
when 429 then raise RateLimitError, format_error(resp)
|
47
|
+
when 500 then raise InternalServerError, format_error(resp)
|
48
|
+
when 503 then raise ServiceUnavailableError, format_error(resp)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if resp.status > 400
|
53
|
+
raise APIError, "[#{resp.status}] #{resp.body}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Rest API Errors
|
59
|
+
#
|
60
|
+
class APIError < RuntimeError
|
61
|
+
end
|
62
|
+
|
63
|
+
# Status 400
|
64
|
+
class BadRequestError < APIError
|
65
|
+
end
|
66
|
+
|
67
|
+
class ParamRequiredError < APIError
|
68
|
+
end
|
69
|
+
|
70
|
+
class InvalidRequestError < APIError
|
71
|
+
end
|
72
|
+
|
73
|
+
class PersonalDetailsRequiredError < APIError
|
74
|
+
end
|
75
|
+
|
76
|
+
# Status 401
|
77
|
+
class AuthenticationError < APIError
|
78
|
+
end
|
79
|
+
|
80
|
+
class UnverifiedEmailError < APIError
|
81
|
+
end
|
82
|
+
|
83
|
+
class InvalidTokenError < APIError
|
84
|
+
end
|
85
|
+
|
86
|
+
class RevokedTokenError < APIError
|
87
|
+
end
|
88
|
+
|
89
|
+
class ExpiredTokenError < APIError
|
90
|
+
end
|
91
|
+
|
92
|
+
# Status 402
|
93
|
+
class TwoFactorRequiredError < APIError
|
94
|
+
end
|
95
|
+
|
96
|
+
# Status 403
|
97
|
+
class InvalidScopeError < APIError
|
98
|
+
end
|
99
|
+
|
100
|
+
# Status 404
|
101
|
+
class NotFoundError < APIError
|
102
|
+
end
|
103
|
+
|
104
|
+
# Status 422
|
105
|
+
class ValidationError < APIError
|
106
|
+
end
|
107
|
+
|
108
|
+
# Status 429
|
109
|
+
class RateLimitError < APIError
|
110
|
+
end
|
111
|
+
|
112
|
+
# Status 500
|
113
|
+
class InternalServerError < APIError
|
114
|
+
end
|
115
|
+
|
116
|
+
# Status 503
|
117
|
+
class ServiceUnavailableError < APIError
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Cwallet
|
2
|
+
module Wallet
|
3
|
+
# Encapsulate data for an API response
|
4
|
+
class APIResponse
|
5
|
+
attr_reader :received_at
|
6
|
+
attr_accessor :client
|
7
|
+
attr_accessor :method
|
8
|
+
attr_accessor :params
|
9
|
+
|
10
|
+
def initialize(resp)
|
11
|
+
@received_at = Time.now
|
12
|
+
@response = resp
|
13
|
+
end
|
14
|
+
|
15
|
+
def raw
|
16
|
+
@response
|
17
|
+
end
|
18
|
+
|
19
|
+
def body
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
alias_method :data, :body
|
23
|
+
|
24
|
+
def body=(body)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
def headers
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
def status
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_more?
|
37
|
+
body.has_key?('pagination') && body['pagination']['next_uri'] != nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Cwallet
|
2
|
+
module Wallet
|
3
|
+
BASE_API_URL = 'https://stg-wallet.fiahub.com'.freeze
|
4
|
+
API_VERSION = '2018-10-10'.freeze
|
5
|
+
|
6
|
+
class Client < NetHTTPClient
|
7
|
+
def initialize(options={})
|
8
|
+
[ :api_key, :api_secret ].each do |opt|
|
9
|
+
raise unless options.has_key? opt
|
10
|
+
end
|
11
|
+
@api_key = options[:api_key]
|
12
|
+
@api_secret = options[:api_secret]
|
13
|
+
@api_uri = URI.parse(options[:api_url] || BASE_API_URL)
|
14
|
+
super(@api_uri, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def auth_headers(method, path, body)
|
18
|
+
ts = Time.now.to_i.to_s
|
19
|
+
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'),
|
20
|
+
@api_secret,
|
21
|
+
ts + method + path + body.to_s)
|
22
|
+
{ 'CB-ACCESS-KEY' => @api_key,
|
23
|
+
'CB-ACCESS-SIGN' => signature,
|
24
|
+
'CB-ACCESS-TIMESTAMP' => ts,
|
25
|
+
'CB-VERSION' => API_VERSION }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class OAuthClient < NetHTTPClient
|
30
|
+
attr_accessor :access_token, :refresh_token
|
31
|
+
|
32
|
+
def initialize(options={})
|
33
|
+
raise unless options.has_key? :access_token
|
34
|
+
@access_token = options[:access_token]
|
35
|
+
@refresh_token = options[:refresh_token]
|
36
|
+
@oauth_uri = URI.parse(options[:api_url] || BASE_API_URL)
|
37
|
+
super(@oauth_uri, options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def auth_headers(method, path, body)
|
41
|
+
{ 'Authorization' => "Bearer #{@access_token}",
|
42
|
+
'CB-VERSION' => API_VERSION }
|
43
|
+
end
|
44
|
+
|
45
|
+
def authorize!(redirect_url, params = {})
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
|
49
|
+
def revoke!(params = {})
|
50
|
+
params[:token] ||= @access_token
|
51
|
+
|
52
|
+
out = nil
|
53
|
+
post("/oauth/revoke", params) do |resp|
|
54
|
+
out = APIObject.new(self, resp.body)
|
55
|
+
yield(out, resp) if block_given?
|
56
|
+
end
|
57
|
+
out
|
58
|
+
end
|
59
|
+
|
60
|
+
def refresh!(params = {})
|
61
|
+
params[:grant_type] = 'refresh_token'
|
62
|
+
params[:refresh_token] ||= @refresh_token
|
63
|
+
|
64
|
+
raise "Missing Parameter: refresh_token" unless params.has_key?(:refresh_token)
|
65
|
+
|
66
|
+
out = nil
|
67
|
+
post("/oauth/token", params) do |resp|
|
68
|
+
out = APIObject.new(self, resp.body)
|
69
|
+
# Update tokens to current instance
|
70
|
+
# Developer should always persist them
|
71
|
+
@access_token = out.access_token
|
72
|
+
@refresh_token = out.refresh_token
|
73
|
+
yield(out, resp) if block_given?
|
74
|
+
end
|
75
|
+
out
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class AsyncClient < EMHTTPClient
|
80
|
+
def initialize(options={})
|
81
|
+
[ :api_key, :api_secret ].each do |opt|
|
82
|
+
raise unless options.has_key? opt
|
83
|
+
end
|
84
|
+
@api_key = options[:api_key]
|
85
|
+
@api_secret = options[:api_secret]
|
86
|
+
@api_uri = URI.parse(options[:api_url] || BASE_API_URL)
|
87
|
+
end
|
88
|
+
|
89
|
+
def auth_headers(method, path, body)
|
90
|
+
ts = Time.now.to_i.to_s
|
91
|
+
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'),
|
92
|
+
@api_secret,
|
93
|
+
ts + method + path + body.to_s)
|
94
|
+
{ 'CB-ACCESS-KEY' => @api_key,
|
95
|
+
'CB-ACCESS-SIGN' => signature,
|
96
|
+
'CB-ACCESS-TIMESTAMP' => ts,
|
97
|
+
'CB-VERSION' => API_VERSION }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi/BwkgBBZESQNFEAuuFN
|
3
|
+
M+entJ+ULJAcBi5RNyU36Si4VjsLIdIiVDGso7tOgPVb0aCzjJdIGeVAxxaUJJzS
|
4
|
+
Jgf6/a3T4F8ZEvf0OndoxcHe6M9hh4O+ImcWbTL9VRlflSQ3Ebu8ZDvWYjsQf7xR
|
5
|
+
1mmk6QAPh294coCCCFNgMOcQsg/gNETD65OddQbwU+GRPjcM4qI5HvcTPYP+uiVT
|
6
|
+
rCeJh7mzDdFgJ/CqtSghAxiriQeTZTJ3FyRmAQU35+Ih0T7/JWVLeY6a1bTTf3k/
|
7
|
+
Z58l0eAhlJs5JBPuaVY5JFB4CfeAecAvBXXn/4SJ25MnFcGP4UcdKZwk/m/UjDsa
|
8
|
+
EwIDAQAB
|
9
|
+
-----END PUBLIC KEY-----
|
@@ -0,0 +1,193 @@
|
|
1
|
+
module Cwallet
|
2
|
+
module Wallet
|
3
|
+
class Account < APIObject
|
4
|
+
def update!(params = {})
|
5
|
+
@client.update_account(self['id'], params) do |data, resp|
|
6
|
+
update(data)
|
7
|
+
yield(data, resp) if block_given?
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def make_primary!(params = {})
|
12
|
+
@client.set_primary_account(self['id'], params) do |data, resp|
|
13
|
+
update(data)
|
14
|
+
yield(data, resp) if block_given?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete!(params = {})
|
19
|
+
@client.delete_account(self['id'], params) do |data, resp|
|
20
|
+
yield(data, resp) if block_given?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Addresses
|
26
|
+
#
|
27
|
+
def addresses(params = {})
|
28
|
+
@client.addresses(self['id'], params) do |data, resp|
|
29
|
+
yield(data, resp) if block_given?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def address(address_id, params = {})
|
34
|
+
@client.address(self['id'], address_id, params) do |data, resp|
|
35
|
+
yield(data, resp) if block_given?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def address_transactions(address_id, params = {})
|
40
|
+
@client.address_transactions(self['id'], address_id, params) do |data, resp|
|
41
|
+
yield(data, resp) if block_given?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_address(params = {})
|
46
|
+
@client.create_address(self['id'], params) do |data, resp|
|
47
|
+
yield(data, resp) if block_given?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Transactions
|
53
|
+
#
|
54
|
+
def transactions(params = {})
|
55
|
+
@client.transactions(self['id'], params) do |data, resp|
|
56
|
+
yield(data, resp) if block_given?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def transaction(transaction_id, params = {})
|
61
|
+
@client.transaction(self['id'], transaction_id, params) do |data, resp|
|
62
|
+
yield(data, resp) if block_given?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def send(params = {})
|
67
|
+
@client.send(self['id'], params) do |data, resp|
|
68
|
+
yield(data, resp) if block_given?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def transfer(params = {})
|
73
|
+
@client.transfer(self['id'], params) do |data, resp|
|
74
|
+
yield(data, resp) if block_given?
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def request(params = {})
|
79
|
+
@client.request(self['id'], params) do |data, resp|
|
80
|
+
yield(data, resp) if block_given?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Buys
|
86
|
+
#
|
87
|
+
def list_buys(params = {})
|
88
|
+
@client.list_buys(self['id'], params) do |data, resp|
|
89
|
+
yield(data, resp) if block_given?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def list_buy(transaction_id, params = {})
|
94
|
+
@client.list_buy(self['id'], transaction_id, params) do |data, resp|
|
95
|
+
yield(data, resp) if block_given?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def buy(params = {})
|
100
|
+
@client.buy(self['id'], params) do |data, resp|
|
101
|
+
yield(data, resp) if block_given?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def commit_buy(transaction_id, params = {})
|
106
|
+
@client.commit_buy(self['id'], transaction_id, params) do |data, resp|
|
107
|
+
yield(data, resp) if block_given?
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Sells
|
113
|
+
#
|
114
|
+
def list_sells(params = {})
|
115
|
+
@client.list_sells(self['id'], params) do |data, resp|
|
116
|
+
yield(data, resp) if block_given?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def list_sell(transaction_id, params = {})
|
121
|
+
@client.list_sell(self['id'], transaction_id, params) do |data, resp|
|
122
|
+
yield(data, resp) if block_given?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def sell(params = {})
|
127
|
+
@client.sell(self['id'], params) do |data, resp|
|
128
|
+
yield(data, resp) if block_given?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def commit_sell(transaction_id, params = {})
|
133
|
+
@client.commit_sell(self['id'], transaction_id, params) do |data, resp|
|
134
|
+
yield(data, resp) if block_given?
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
#
|
139
|
+
# Deposit
|
140
|
+
#
|
141
|
+
def list_deposits(params = {})
|
142
|
+
@client.list_deposits(self['id'], params) do |data, resp|
|
143
|
+
yield(data, resp) if block_given?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def list_deposit(transaction_id, params = {})
|
148
|
+
@client.list_deposit(self['id'], transaction_id, params) do |data, resp|
|
149
|
+
yield(data, resp) if block_given?
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def deposit(params = {})
|
154
|
+
@client.deposit(self['id'], params) do |data, resp|
|
155
|
+
yield(data, resp) if block_given?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def commit_deposit(transaction_id, params = {})
|
160
|
+
@client.commit_deposit(self['id'], transaction_id, params) do |data, resp|
|
161
|
+
yield(data, resp) if block_given?
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
#
|
166
|
+
# Withdrawals
|
167
|
+
#
|
168
|
+
def list_withdrawals(params = {})
|
169
|
+
@client.list_withdrawals(self['id'], params) do |data, resp|
|
170
|
+
yield(data, resp) if block_given?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def list_withdrawal(transaction_id, params = {})
|
175
|
+
@client.list_withdrawal(self['id'], transaction_id, params) do |data, resp|
|
176
|
+
yield(data, resp) if block_given?
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def withdraw(params = {})
|
181
|
+
@client.withdraw(self['id'], params) do |data, resp|
|
182
|
+
yield(data, resp) if block_given?
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def commit_withdrawal(transaction_id, params = {})
|
187
|
+
@client.commit_withdrawal(self['id'], transaction_id, params) do |data, resp|
|
188
|
+
yield(data, resp) if block_given?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|