coinbase 0.0.1 → 2.0.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.

Potentially problematic release.


This version of coinbase might be problematic. Click here for more details.

@@ -0,0 +1,290 @@
1
+ require 'httparty'
2
+ require 'multi_json'
3
+ require 'hashie'
4
+ require 'money'
5
+ require 'monetize'
6
+ require 'time'
7
+ require 'securerandom'
8
+
9
+ module Coinbase
10
+ class Client
11
+ include HTTParty
12
+
13
+ BASE_URI = 'https://coinbase.com/api/v1'
14
+
15
+ def initialize(api_key, api_secret, options={})
16
+ @api_key = api_key
17
+ @api_secret = api_secret
18
+
19
+ # defaults
20
+ options[:base_uri] ||= BASE_URI
21
+ @base_uri = options[:base_uri]
22
+ options[:format] ||= :json
23
+ options.each do |k,v|
24
+ self.class.send k, v
25
+ end
26
+ end
27
+
28
+ # Account
29
+
30
+ def balance options={}
31
+ h = get '/account/balance', options
32
+ h['amount'].to_money(h['currency'])
33
+ end
34
+
35
+ def accounts options={}
36
+ accts = get '/accounts', options
37
+ accts = convert_money_objects(accts)
38
+ accts
39
+ end
40
+
41
+ def receive_address options={}
42
+ get '/account/receive_address', options
43
+ end
44
+
45
+ def generate_receive_address options={}
46
+ post '/account/generate_receive_address', options
47
+ end
48
+
49
+ # Buttons
50
+
51
+ def create_button name, price, description=nil, custom=nil, options={}
52
+ options[:button] ||= {}
53
+ options[:button][:name] ||= name
54
+ price = price.to_money("BTC") unless price.is_a?(Money)
55
+ options[:button][:price_string] ||= price.to_s
56
+ options[:button][:price_currency_iso] ||= price.currency.iso_code
57
+ options[:button][:description] ||= description
58
+ options[:button][:custom] ||= custom
59
+ r = post '/buttons', options
60
+ if r.success?
61
+ r.embed_html = case options[:button_mode]
62
+ when 'page'
63
+ %[<a href="https://coinbase.com/checkouts/#{r.button.code}" target="_blank"><img alt="#{r.button.text}" src="https://coinbase.com/assets/buttons/#{r.button.style}.png"></a>]
64
+ when 'iframe'
65
+ %[<iframe src="https://coinbase.com/inline_payments/#{r.button.code}" style="width:500px;height:160px;border:none;box-shadow:0 1px 3px rgba(0,0,0,0.25);overflow:hidden;" scrolling="no" allowtransparency="true" frameborder="0"></iframe>]
66
+ else
67
+ %[<div class="coinbase-button" data-code="#{r.button.code}"></div><script src="https://coinbase.com/assets/button.js" type="text/javascript"></script>]
68
+ end
69
+ end
70
+ r
71
+ end
72
+
73
+ def create_order_for_button button_id
74
+ post "/buttons/#{button_id}/create_order"
75
+ end
76
+
77
+ # Transactions
78
+
79
+ def transactions page=1, options ={}
80
+ r = get '/transactions', {page: page}.merge(options)
81
+ r.transactions ||= []
82
+ convert_money_objects(r.transactions)
83
+ r
84
+ end
85
+
86
+ def transaction transaction_id
87
+ r = get "/transactions/#{transaction_id}"
88
+ convert_money_objects(r.transaction)
89
+ r
90
+ end
91
+
92
+ def send_money to, amount, notes=nil, options={}
93
+ options[:transaction] ||= {}
94
+ options[:transaction][:to] ||= to
95
+ amount = amount.to_money("BTC") unless amount.is_a?(Money)
96
+ options[:transaction][:amount_string] ||= amount.to_s
97
+ options[:transaction][:amount_currency_iso] ||= amount.currency.iso_code
98
+ options[:transaction][:notes] ||= notes
99
+ r = post '/transactions/send_money', options
100
+ if amt = r.transaction.amount
101
+ r.transaction.amount = amt.amount.to_money(amt.currency)
102
+ end
103
+ r
104
+ end
105
+
106
+ def request_money from, amount, notes=nil, options={}
107
+ options[:transaction] ||= {}
108
+ options[:transaction][:from] ||= from
109
+ amount = amount.to_money("BTC") unless amount.is_a?(Money)
110
+ options[:transaction][:amount_string] ||= amount.to_s
111
+ options[:transaction][:amount_currency_iso] ||= amount.currency.iso_code
112
+ options[:transaction][:notes] ||= notes
113
+ r = post '/transactions/request_money', options
114
+ if amt = r.transaction.amount
115
+ r.transaction.amount = amt.amount.to_money(amt.currency)
116
+ end
117
+ r
118
+ end
119
+
120
+ def resend_request transaction_id
121
+ put "/transactions/#{transaction_id}/resend_request"
122
+ end
123
+
124
+ def cancel_request transaction_id
125
+ delete "/transactions/#{transaction_id}/cancel_request"
126
+ end
127
+
128
+ def complete_request transaction_id
129
+ put "/transactions/#{transaction_id}/complete_request"
130
+ end
131
+
132
+ # Users
133
+
134
+ def create_user email, password=nil, client_id=nil, scopes=nil
135
+ password ||= SecureRandom.urlsafe_base64(12)
136
+ options = {user: {email: email, password: password}}
137
+ if client_id
138
+ options[:client_id] = client_id
139
+ raise Error.new("Invalid scopes parameter; must be an array") if !scopes.is_a?(Array)
140
+ options[:scopes] = scopes.join(' ')
141
+ end
142
+ post '/users', options
143
+ end
144
+
145
+ # Prices
146
+
147
+ def buy_price qty=1
148
+ r = get '/prices/buy', {qty: qty}
149
+ r['amount'].to_money(r['currency'])
150
+ end
151
+
152
+ def sell_price qty=1
153
+ r = get '/prices/sell', {qty: qty}
154
+ r['amount'].to_money(r['currency'])
155
+ end
156
+
157
+ def spot_price currency='USD'
158
+ r = get '/prices/spot_rate', {currency: currency}
159
+ r['amount'].to_money(r['currency'])
160
+ end
161
+
162
+ # Buys
163
+
164
+ def buy! qty
165
+ r = post '/buys', {qty: qty}
166
+ r = convert_money_objects(r)
167
+ r.transfer.payout_date = Time.parse(r.transfer.payout_date) rescue nil
168
+ r
169
+ end
170
+
171
+ # Sells
172
+
173
+ def sell! qty
174
+ r = post '/sells', {qty: qty}
175
+ r = convert_money_objects(r)
176
+ r.transfer.payout_date = Time.parse(r.transfer.payout_date) rescue nil
177
+ r
178
+ end
179
+
180
+ # Transfers
181
+
182
+ def transfers options={}
183
+ r = get '/transfers', options
184
+ r = convert_money_objects(r)
185
+ r.transfers.each do |t|
186
+ t.transfer.payout_date = Time.parse(t.transfer.payout_date) rescue nil
187
+ end
188
+ r
189
+ end
190
+
191
+ # Wrappers for the main HTTP verbs
192
+
193
+ def get(path, options={})
194
+ http_verb :get, path, options
195
+ end
196
+
197
+ def post(path, options={})
198
+ http_verb :post, path, options
199
+ end
200
+
201
+ def put(path, options={})
202
+ http_verb :put, path, options
203
+ end
204
+
205
+ def delete(path, options={})
206
+ http_verb :delete, path, options
207
+ end
208
+
209
+ def self.whitelisted_cert_store
210
+ @@cert_store ||= build_whitelisted_cert_store
211
+ end
212
+
213
+ def self.build_whitelisted_cert_store
214
+ path = File.expand_path(File.join(File.dirname(__FILE__), 'ca-coinbase.crt'))
215
+
216
+ certs = [ [] ]
217
+ File.readlines(path).each{|line|
218
+ next if ["\n","#"].include?(line[0])
219
+ certs.last << line
220
+ certs << [] if line == "-----END CERTIFICATE-----\n"
221
+ }
222
+
223
+ result = OpenSSL::X509::Store.new
224
+
225
+ certs.each{|lines|
226
+ next if lines.empty?
227
+ cert = OpenSSL::X509::Certificate.new(lines.join)
228
+ result.add_cert(cert)
229
+ }
230
+
231
+ result
232
+ end
233
+
234
+ def ssl_options
235
+ { verify: true, cert_store: self.class.whitelisted_cert_store }
236
+ end
237
+
238
+ def http_verb(verb, path, options={})
239
+
240
+ nonce = options[:nonce] || (Time.now.to_f * 1e6).to_i
241
+
242
+ if [:get, :delete].include? verb
243
+ request_options = {}
244
+ path = "#{path}?#{URI.encode_www_form(options)}" if !options.empty?
245
+ hmac_message = nonce.to_s + @base_uri + path
246
+ else
247
+ request_options = {body: options.to_json}
248
+ hmac_message = nonce.to_s + @base_uri + path + options.to_json
249
+ end
250
+
251
+ signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), @api_secret, hmac_message)
252
+
253
+ headers = {
254
+ 'ACCESS_KEY' => @api_key,
255
+ 'ACCESS_SIGNATURE' => signature,
256
+ 'ACCESS_NONCE' => nonce.to_s,
257
+ "Content-Type" => "application/json",
258
+ }
259
+
260
+ request_options[:headers] = headers
261
+
262
+ r = self.class.send(verb, path, request_options.merge(ssl_options))
263
+ hash = Hashie::Mash.new(JSON.parse(r.body))
264
+ raise Error.new(hash.error) if hash.error
265
+ raise Error.new(hash.errors.join(", ")) if hash.errors
266
+ hash
267
+ end
268
+
269
+ class Error < StandardError; end
270
+
271
+ private
272
+
273
+ def convert_money_objects obj
274
+ if obj.is_a?(Array)
275
+ obj.each_with_index do |o, i|
276
+ obj[i] = convert_money_objects(o)
277
+ end
278
+ elsif obj.is_a?(Hash)
279
+ if obj[:amount] && (obj[:currency] || obj[:currency_iso])
280
+ obj = obj[:amount].to_money((obj[:currency] || obj[:currency_iso]))
281
+ else
282
+ obj.each do |k,v|
283
+ obj[k] = convert_money_objects(v)
284
+ end
285
+ end
286
+ end
287
+ obj
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,77 @@
1
+ require 'oauth2'
2
+
3
+ module Coinbase
4
+ class OAuthClient < Client
5
+
6
+ AUTHORIZE_URL = 'https://coinbase.com/oauth/authorize'
7
+ TOKEN_URL = 'https://coinbase.com/oauth/token'
8
+
9
+ # Initializes a Coinbase Client using OAuth 2.0 credentials
10
+ #
11
+ # @param [String] client_id this application's Coinbase OAuth2 CLIENT_ID
12
+ # @param [String] client_secret this application's Coinbase OAuth2 CLIENT_SECRET
13
+ # @param [Hash] user_credentials OAuth 2.0 credentials to use
14
+ # @option user_credentials [String] access_token Must pass either this or token
15
+ # @option user_credentials [String] token Must pass either this or access_token
16
+ # @option user_credentials [String] refresh_token Optional
17
+ # @option user_credentials [Integer] expires_at Optional
18
+ # @option user_credentials [Integer] expires_in Optional
19
+ #
20
+ # Please note access tokens will be automatically refreshed when expired
21
+ # Use the credentials method when finished with the client to retrieve up-to-date credentials
22
+ def initialize(client_id, client_secret, user_credentials, options={})
23
+ client_opts = {
24
+ :site => options[:base_uri] || BASE_URI,
25
+ :authorize_url => options[:authorize_url] || AUTHORIZE_URL,
26
+ :token_url => options[:token_url] || TOKEN_URL,
27
+ :ssl => {
28
+ :verify => true,
29
+ :cert_store => ::Coinbase::Client.whitelisted_cert_store
30
+ }
31
+ }
32
+ @oauth_client = OAuth2::Client.new(client_id, client_secret, client_opts)
33
+ token_hash = user_credentials.dup
34
+ token_hash[:access_token] ||= token_hash[:token]
35
+ token_hash.delete :expires
36
+ raise "No access token provided" unless token_hash[:access_token]
37
+ @oauth_token = OAuth2::AccessToken.from_hash(@oauth_client, token_hash)
38
+ end
39
+
40
+ def http_verb(verb, path, options={})
41
+ path = remove_leading_slash(path)
42
+
43
+ if [:get, :delete].include? verb
44
+ request_options = {params: options}
45
+ else
46
+ request_options = {headers: {"Content-Type" => "application/json"}, body: options.to_json}
47
+ end
48
+ response = oauth_token.request(verb, path, request_options)
49
+
50
+ hash = Hashie::Mash.new(JSON.parse(response.body))
51
+ raise Error.new(hash.error) if hash.error
52
+ raise Error.new(hash.errors.join(", ")) if hash.errors
53
+ hash
54
+ end
55
+
56
+ def refresh!
57
+ raise "Access token not initialized." unless @oauth_token
58
+ @oauth_token = @oauth_token.refresh!
59
+ end
60
+
61
+ def oauth_token
62
+ raise "Access token not initialized." unless @oauth_token
63
+ refresh! if @oauth_token.expired?
64
+ @oauth_token
65
+ end
66
+
67
+ def credentials
68
+ @oauth_token.to_hash
69
+ end
70
+
71
+ private
72
+
73
+ def remove_leading_slash(path)
74
+ path.sub(/^\//, '')
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,3 @@
1
+ module Coinbase
2
+ VERSION = "2.0.0"
3
+ end
data/lib/coinbase.rb CHANGED
@@ -1,18 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'coinbase/address'
4
- require_relative 'coinbase/asset'
5
- require_relative 'coinbase/balance_map'
6
- require_relative 'coinbase/constants'
7
- require_relative 'coinbase/network'
8
- require_relative 'coinbase/transfer'
9
- require_relative 'coinbase/wallet'
10
- require 'dotenv'
11
-
12
- # The Coinbase SDK.
13
- module Coinbase
14
- # Initializes the Coinbase SDK.
15
- def self.init
16
- Dotenv.load
17
- end
18
- end
1
+ require "json"
2
+ require "money"
3
+ require "coinbase/version"
4
+ require "coinbase/client"
5
+ require "coinbase/oauth_client"