deribit-api 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e11b1e56992f333f743eb40b24a6c336b06faa7ed3fa981383477e4b7ae87e90
4
- data.tar.gz: aae71272675f88e4e793afbcb239662592beeae2f2f6e6fe8d5ce8eff5550f61
3
+ metadata.gz: d9384ba752c4c01d89a64e693199e7a22e57cf03d0de5f3f69cf47d3cd420079
4
+ data.tar.gz: 8c7497902c3cfcf5d799379f721460b73bb75137d2a82ce5d99245be03252e1f
5
5
  SHA512:
6
- metadata.gz: 423ba0584bd643834fb4ee11c7b57253565f37c544b207262604105b17bf3e406391db088745a84bead68ead8afa556f9f6d9a23eae15b7e2f97fcca94331767
7
- data.tar.gz: a726ef0e7cc7dddafe08a8d48d608ef0b6506aca6c773643556912232ff98c2b7582928e345559c5a3cfd6c5a3709d8d27b99042feb87df76ea082ccc3c60eba
6
+ metadata.gz: cc000a2fc6d98a8db24e1742c5f61ada7e67e6b5634ebbf6d72eb9566f92146471feff17126d320608fb1aa37d584f63f8dad9c8ecfd2cd847bc9b905182b952
7
+ data.tar.gz: c2763b97462ee107278bb699e7f79ea16587e49d1fde62a1d7d13b2b5173731d4d55b6b475788375ba2e0522d0cb0ae0b0254ccde0c67f49db1ec9a36858bd60
@@ -5,6 +5,10 @@
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.2] - 2019-04-17
9
+ ### Added
10
+ - private Websocket API
11
+
8
12
  ## [0.1.0] - 2019-04-02
9
13
  ### Added
10
14
  - public Websocket API
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deribit-api (0.1.0)
4
+ deribit-api (0.1.2)
5
5
  faraday
6
6
  faraday_middleware
7
7
  faye-websocket
data/README.md CHANGED
@@ -127,23 +127,26 @@ Trades || [X] | [X] ||
127
127
  Summary || [X] | [X] ||
128
128
  Announcements || [X] | [X] ||
129
129
  Settlements || [X] | [X] ||
130
- Account | YES | [X] ||
131
- Buy | YES | [X] ||
132
- Sell | YES | [X] ||
133
- Edit | YES | [X] ||
134
- Cancel | YES | [X] ||
135
- Cancel all | YES | [X] ||
136
- Orders | YES | [X] ||
137
- Positions | YES | [X] ||
138
- Orders history | YES | [X] ||
139
- Order | YES | [X] ||
140
- Trades history | YES | [X] ||
141
- New announcements | YES | [X] ||
142
- Cancel on disconnect | YES | [X] ||
143
- Get email lang | YES | [X] ||
144
- Set email lang | YES | [X] ||
145
- Set announcements read | YES | [X] ||
146
- Settlements history | YES | [X] ||
130
+ Account | YES | [X] | [X] ||
131
+ Buy | YES | [X] | [X] ||
132
+ Sell | YES | [X] | [X] ||
133
+ Edit | YES | [X] | [X] ||
134
+ Cancel | YES | [X] | [X] ||
135
+ Cancel all | YES | [X] | [X] ||
136
+ Orders | YES | [X] | [X] ||
137
+ Positions | YES | [X] | [X]||
138
+ Orders history | YES | [X] | [X] ||
139
+ Order | YES | [X] |[X]||
140
+ Trades history | YES | [X] | [X] ||
141
+ New announcements | YES | [X] | [X] ||
142
+ Logout | YES | N/A | [X] ||
143
+ Cancel on disconnect | YES | N/A | [X] ||
144
+ Get email lang | YES | [X] | [X] ||
145
+ Set email lang | YES | [X] | [X] ||
146
+ Set announcements read | YES | [X] | [X] ||
147
+ Settlements history | YES | [X] | [X] ||
148
+ Subscribe | | N/A | ||
149
+ Unsubscribe | | N/A | ||
147
150
 
148
151
  ## Development
149
152
 
data/TODOs.org CHANGED
@@ -14,14 +14,21 @@
14
14
  :LOGBOOK:
15
15
  CLOCK: [2019-04-02 Tue 10:10]--[2019-04-02 Tue 13:12] => 3:02
16
16
  :END:
17
- ** private Websocket API
17
+ ** DONE private Websocket API
18
+ CLOSED: [2019-04-17 Wed 18:26] SCHEDULED: <2019-04-16 Tue>
19
+ :LOGBOOK:
20
+ CLOCK: [2019-04-17 Wed 17:55]--[2019-04-17 Wed 18:26] => 0:31
21
+ CLOCK: [2019-04-16 Tue 12:23]--[2019-04-16 Tue 18:16] => 5:53
22
+ :END:
18
23
  ** response middleware
19
24
  ** check key/secret present for private endpoints
20
25
  ** fix trade history
21
26
  ** research async websocket implementation
27
+ ** cleaup 'params' for both http and websocket
22
28
  ** TODO Deribit implementation
23
- SCHEDULED: <2019-04-09 Tue +1w>
29
+ SCHEDULED: <2019-04-23 Tue +1w>
24
30
  :PROPERTIES:
25
- :LAST_REPEAT: [2019-04-02 Tue 13:02]
31
+ :LAST_REPEAT: [2019-04-17 Wed 18:26]
26
32
  :END:
33
+ - State "DONE" from "TODO" [2019-04-17 Wed 18:26]
27
34
  - State "DONE" from "TODO" [2019-04-02 Tue 13:02]
@@ -12,4 +12,15 @@ require 'deribit/websocket'
12
12
  module Deribit
13
13
  # Base error class
14
14
  class Error < StandardError; end
15
+
16
+ # @see https://docs.deribit.com/rpc-authentication.html
17
+ def self.signature(key, nonce, params, query)
18
+ signature_string = params.map { |k, v| "#{k}=#{v}" }.sort.join '&'
19
+ signature_string += "&#{query}" if query
20
+
21
+ signature_digest = Digest::SHA256.digest signature_string
22
+ signature_hash = Base64.encode64 signature_digest
23
+
24
+ "#{key}.#{nonce}.#{signature_hash.chomp}"
25
+ end
15
26
  end
@@ -27,17 +27,10 @@ module Deribit
27
27
  _acsec: @secret,
28
28
  _action: env['url'].path
29
29
  }
30
- # add POST params
31
30
  params.merge! JSON.parse(env['body']) if env['body']
31
+ query = env['url'].query
32
32
 
33
- signature_string = params.map{ |key, value| "#{key}=#{value}" }.sort.join '&'
34
- # add GET query
35
- signature_string += "&#{env['url'].query}" if env['url'].query
36
-
37
- signature_digest = Digest::SHA256.digest signature_string
38
- signature_hash = Base64.encode64 signature_digest
39
-
40
- "#{@key}.#{nonce}.#{signature_hash.chomp}"
33
+ Deribit.signature @key, nonce, params, query
41
34
  end
42
35
  end
43
36
  end
@@ -6,6 +6,8 @@ module Deribit
6
6
  # URL for mainnet
7
7
  MAINNET_URL = 'www.deribit.com'
8
8
 
9
+ attr_reader :websocket
10
+
9
11
  # Create new instance
10
12
  # @param key [String] Deribit Access Key
11
13
  # @param secret [String] Deribit Secret Key
@@ -13,8 +15,8 @@ module Deribit
13
15
  # @param debug [Boolean] set to true for debug output
14
16
  # @return [Deribit::Client] the instance of client
15
17
  def initialize(key: nil, secret: nil, testnet: false, debug: false)
16
- url = 'https://' + (testnet ? TESTNET_URL : MAINNET_URL)
17
- @connection = Faraday::Connection.new(url: url) do |f|
18
+ host = testnet ? TESTNET_URL : MAINNET_URL
19
+ @connection = Faraday::Connection.new(url: 'https://' + host) do |f|
18
20
  f.request :json
19
21
  f.response :mashify
20
22
  f.response :json
@@ -22,6 +24,7 @@ module Deribit
22
24
  f.response :logger if debug
23
25
  f.adapter Faraday.default_adapter
24
26
  end
27
+ @websocket = Deribit::Websocket.new host, key: key, secret: secret
25
28
  end
26
29
 
27
30
  # Retrieves the current time (in ms).
@@ -225,9 +228,14 @@ module Deribit
225
228
  # Retrieves user account summary.
226
229
  # @param ext [Boolean] Requests additional fields
227
230
  # @return [Hashie::Mash] the account details
231
+ # @yield [Hashie::Mash] the account details
228
232
  # @see https://docs.deribit.com/rpc-endpoints.html#account
229
- def account(ext: false)
230
- get :account, auth: true
233
+ def account(ext: false, &blk)
234
+ if block_given?
235
+ websocket.subscribe :account, params: { auth: true }, &blk
236
+ else
237
+ get :account, auth: true
238
+ end
231
239
  end
232
240
 
233
241
  # Places a buy order for an instrument.
@@ -245,9 +253,15 @@ module Deribit
245
253
  # @option options [String] :execInst (index_price) Defines trigger type, required for "stop_limit" order type, possible values "index_price", "mark_price" (Only valid for stop orders)
246
254
  # @option options [String] :adv Advanced option order type, can be "implv", "usd". (Only valid for options)
247
255
  # @return [Hashie::Mash] the details of new order
256
+ # @yield [Hashie::Mash] the details of new order
248
257
  # @see https://docs.deribit.com/rpc-endpoints.html#buy
249
- def buy(instrument, quantity, options = {})
250
- post :buy, instrument: instrument, quantity: quantity, price: options[:price]
258
+ def buy(instrument, quantity, options = {}, &blk)
259
+ params = { instrument: instrument, quantity: quantity, price: options[:price] }
260
+ if block_given?
261
+ websocket.subscribe :buy, params: params.merge(auth: true), &blk
262
+ else
263
+ post :buy, params
264
+ end
251
265
  end
252
266
 
253
267
  # Places a sell order for an instrument.
@@ -255,9 +269,15 @@ module Deribit
255
269
  # @param quantity [Integer] The number of contracts to sell
256
270
  # @!macro deribit.options
257
271
  # @return [Hashie::Mash] the details of new order
272
+ # @yield [Hashie::Mash] the details of new order
258
273
  # @see https://docs.deribit.com/rpc-endpoints.html#sell
259
- def sell(instrument, quantity, options = {})
260
- post :sell, options.merge(instrument: instrument, quantity: quantity)
274
+ def sell(instrument, quantity, options = {}, &blk)
275
+ params = options.merge instrument: instrument, quantity: quantity, auth: true
276
+ if block_given?
277
+ websocket.subscribe :sell, params: params, &blk
278
+ else
279
+ post :sell, params
280
+ end
261
281
  end
262
282
 
263
283
  # Changes price and/or quantity of the own order.
@@ -269,26 +289,45 @@ module Deribit
269
289
  # @option options [String] :adv The new advanced order type (only valid for option orders)
270
290
  # @option options [Float] :stopPx The new stop price (only valid for stop limit orders)
271
291
  # @return [Hashie::Mash] the edited order
292
+ # @yield [Hashie::Mash] the edited order
272
293
  # @see https://docs.deribit.com/rpc-endpoints.html#edit
273
- def edit(order_id, quantity, price, options = {})
274
- post :edit, options.merge(orderId: order_id, quantity: quantity, price: price)
294
+ def edit(order_id, quantity, price, options = {}, &blk)
295
+ params = options.merge orderId: order_id, quantity: quantity, price: price, auth: true
296
+ if block_given?
297
+ websocket.subscribe :edit, params: params, &blk
298
+ else
299
+ post :edit, params
300
+ end
275
301
  end
276
302
 
277
303
  # Cancels an order, specified by order id.
278
304
  # @param order_id [String] The order id of the order to be cancelled
279
305
  # @return [Hashie::Mash] details of the cancelled order
306
+ # @yield [Hashie::Mash] details of the cancelled order
280
307
  # @see https://docs.deribit.com/rpc-endpoints.html#cancel
281
- def cancel(order_id)
282
- post :cancel, orderId: order_id
308
+ def cancel(order_id, &blk)
309
+ params = { orderId: order_id, auth: true }
310
+ if block_given?
311
+ websocket.subscribe :cancel, params: params, &blk
312
+ else
313
+ post :cancel, params
314
+ end
283
315
  end
284
316
 
285
317
  # Cancels all orders, optionally filtered by instrument or instrument type.
286
318
  # @param type [all futures options] Which type of orders to cancel. Valid values are "all", "futures", "options"
287
319
  # @param options [Hash] extra options
288
320
  # @option options [String] :instrument The name of the instrument for which to cancel all orders
321
+ # @return [Boolean] success or not
322
+ # @yield [Boolean] success or not
289
323
  # @see https://docs.deribit.com/rpc-endpoints.html#cancelall
290
- def cancelall(type = :all, options = {})
291
- post :cancelall, options.merge(type: type)
324
+ def cancelall(type = :all, options = {}, &blk)
325
+ params = options.merge type: type, auth: true
326
+ if block_given?
327
+ websocket.subscribe :cancelall, params: params, &blk
328
+ else
329
+ post :cancelall, params
330
+ end
292
331
  end
293
332
 
294
333
  # Retrieves open orders.
@@ -297,16 +336,27 @@ module Deribit
297
336
  # @option options [string] ;orderId order ID
298
337
  # @option options [String] :type Order types to return. Valid values include "limit", "stop_limit", "any"
299
338
  # @return [Array] the list of open orders
339
+ # @yield [Hashie::Mash] the order
300
340
  # @see https://docs.deribit.com/rpc-endpoints.html#getopenorders
301
- def orders(options = {})
302
- get :getopenorders, auth: true, params: options
341
+ def orders(options = {}, &blk)
342
+ if block_given?
343
+ websocket.subscribe :getopenorders, params: options.merge(auth: true), &blk
344
+ else
345
+ get :getopenorders, auth: true, params: options
346
+ end
303
347
  end
304
348
 
305
349
  # Retrieves current positions.
306
350
  # @return [Array] the list of positions
351
+ # @yield [Hashie::Mash] the position
307
352
  # @see https://docs.deribit.com/rpc-endpoints.html#positions
308
- def positions
309
- get :positions, auth: true
353
+ def positions(&blk)
354
+ params = { auth: true }
355
+ if block_given?
356
+ websocket.subscribe :positions, params: params, &blk
357
+ else
358
+ get :positions, params
359
+ end
310
360
  end
311
361
 
312
362
  # Retrieves history of orders that have been partially or fully filled.
@@ -315,57 +365,108 @@ module Deribit
315
365
  # @option options [String] :count The number of items to be returned.
316
366
  # @option options [string] :offset The offset for pagination
317
367
  # @return [Array] the list of history orders
368
+ # @yield [Hashie::Mash] the order
318
369
  # @see https://docs.deribit.com/rpc-endpoints.html#orderhistory
319
- def orders_history(options = {})
320
- get :orderhistory, auth: true, params: options
370
+ def orders_history(options = {}, &blk)
371
+ if block_given?
372
+ websocket.subscribe :orderhistory, params: options.merge(auth: true), &blk
373
+ else
374
+ get :orderhistory, auth: true, params: options
375
+ end
321
376
  end
322
377
 
323
378
  # Retrieve order details state by order id.
324
379
  # @param order_id [String] the ID of the order to be retrieved
325
- # @return [Array] the details of the order
380
+ # @return [Hashie::Mash] the details of the order
381
+ # @yield [Hashie::Mash] the details of the order
326
382
  # @see https://docs.deribit.com/rpc-endpoints.html#orderstate
327
- def order(order_id)
328
- get :orderstate, auth: true, params: { orderId: order_id }
383
+ def order(order_id, &blk)
384
+ params = { orderId: order_id, auth: true }
385
+ if block_given?
386
+ websocket.subscribe :orderstate, params: params, &blk
387
+ else
388
+ get :orderstate, auth: true, params: params
389
+ end
329
390
  end
330
391
 
331
392
  # Retrieve the trade history of the account
332
393
  # @param instrument [String] Either the name of the instrument, or "all" for instruments, "futures" for all futures, or "options" for all options.
333
394
  # @!macro deribit.filters
334
395
  # @return [Array] the list of trades
396
+ # @yield [Hashie::Mash] the trade
335
397
  # @see https://docs.deribit.com/rpc-endpoints.html?q=#tradehistory
336
- def trades_history(instrument = :all, filters = {})
337
- get :tradehistory, auth: true, params: filters.merge(instrument: instrument)
398
+ def trades_history(instrument = :all, filters = {}, &blk)
399
+ params = filters.merge(instrument: instrument, auth: true)
400
+ if block_given?
401
+ websocket.subscribe :tradehistory, params: params, &blk
402
+ else
403
+ get :tradehistory, auth: true, params: params
404
+ end
338
405
  end
339
406
 
340
407
  # Retrieves announcements that have not been marked read by the current user.
341
408
  # @return [Array] the list of new announcements
342
- def new_announcements
343
- get :newannouncements, auth: true
409
+ # @yield [Hashie::Mash] the announcement
410
+ def new_announcements(&blk)
411
+ if block_given?
412
+ websocket.subscribe :newannouncements, params: { auth: true }, &blk
413
+ else
414
+ get :newannouncements, auth: true
415
+ end
416
+ end
417
+
418
+ # Logs out the websocket connection.
419
+ # @yield [Boolean] success or not
420
+ # @see https://docs.deribit.com/rpc-endpoints.html#logout
421
+ def logout(&blk)
422
+ raise 'This API endpoint cannot be used over HTTP.' unless block_given?
423
+
424
+ websocket.subscribe :logout, params: {}, &blk
344
425
  end
345
426
 
346
427
  # Enables or disables "COD" (cancel on disconnect) for the current connection.
347
428
  # @param state [String] Whether COD is to be enabled for this connection. "enabled" or "disabled"
348
- def cancelondisconnect(state)
349
- get :cancelondisconnect, auth: true, params: { state: state }
429
+ # @yield [Boolean] success or not
430
+ # @see https://docs.deribit.com/rpc-endpoints.html#cancelondisconnect
431
+ def cancelondisconnect(state, &blk)
432
+ raise 'This API endpoint cannot be used over HTTP.' unless block_given?
433
+
434
+ websocket.subscribe :cancelondisconnect, params: { state: state, auth: true }, &blk
350
435
  end
351
436
 
352
437
  # Retrieves the language to be used for emails.
353
438
  # @return [String] the language name (e.g. "en", "ko", "zh")
354
- def getemaillang
355
- get :getemaillang, auth: true
439
+ # @yield [String] the language name (e.g. "en", "ko", "zh")
440
+ def getemaillang(&blk)
441
+ if block_given?
442
+ websocket.subscribe :getemaillang, params: { auth: true }, &blk
443
+ else
444
+ get :getemaillang, auth: true
445
+ end
356
446
  end
357
447
 
358
448
  # Changes the language to be used for emails.
359
449
  # @param lang [String] the abbreviated language name. Valid values include "en", "ko", "zh"
360
- def setemaillang(lang)
361
- post :setemaillang, lang: lang
450
+ # @return [Boolean] success or not
451
+ # @yield [Boolean] success or not
452
+ def setemaillang(lang, &blk)
453
+ if block_given?
454
+ websocket.subscribe :setemaillang, params: { lang: lang, auth: true }, &blk
455
+ else
456
+ post :setemaillang, lang: lang
457
+ end
362
458
  end
363
459
 
364
460
  # Marks an announcement as read, so it will not be shown in newannouncements
365
461
  # @param announcement_id [String] the ID of the announcement
366
462
  # @return [String] ok
367
- def setannouncementasread(announcement_id)
368
- post :setannouncementasread, announcementid: announcement_id
463
+ # @yield [String] ok
464
+ def setannouncementasread(announcement_id, &blk)
465
+ if block_given?
466
+ websocket.subscribe :setannouncementasread, params: { announcementid: announcement_id, auth: true }, &blk
467
+ else
468
+ post :setannouncementasread, announcementid: announcement_id
469
+ end
369
470
  end
370
471
 
371
472
  # Retrieves settlement, delivery and bankruptcy events that have affected your account.
@@ -376,13 +477,14 @@ module Deribit
376
477
  # @option filters [Integer] :startTstamp The latest timestamp to return result for
377
478
  # @option filters [String] :continuation Continuation token for pagination. Each response contains a token to be used for continuation
378
479
  # @return [Hashie::Mash] the settlements
480
+ # @yield [Hashie::Mash] the settlement
379
481
  # @see https://docs.deribit.com/rpc-endpoints.html#settlementhistory
380
- def settlements_history(filters = {})
381
- get :settlementhistory, auth: true, params: filters
382
- end
383
-
384
- def websocket
385
- Deribit::Websocket.new TESTNET_URL
482
+ def settlements_history(filters = {}, &blk)
483
+ if block_given?
484
+ websocket.subscribe :settlementhistory, params: filters.merge(auth: true), &blk
485
+ else
486
+ get :settlementhistory, auth: true, params: filters
487
+ end
386
488
  end
387
489
 
388
490
  private
@@ -400,7 +502,8 @@ module Deribit
400
502
  response = @connection.post path(action, true), params
401
503
  raise response.message unless response.success?
402
504
  raise response.body.message unless response.body.success
403
- response.body.result
505
+
506
+ response.body.result || response.body.success?
404
507
  end
405
508
 
406
509
  def path(action, auth = false)
@@ -1,3 +1,3 @@
1
1
  module Deribit
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.2'
3
3
  end
@@ -1,16 +1,16 @@
1
1
  module Deribit
2
2
  class Websocket
3
- attr_reader :host, :api_key, :api_secret
3
+ attr_reader :host, :key, :secret
4
4
 
5
5
  # Create new websocket instance
6
6
  # @param host [String] the underlying host to connect to
7
- # @param api_key [String] the api key
8
- # @param api_secret [String] the api secret
7
+ # @param key [String] the api key
8
+ # @param secret [String] the api secret
9
9
  # @return [Deribit::Websocket] new websocket instance
10
- def initialize(host, api_key: nil, api_secret: nil)
10
+ def initialize(host, key: nil, secret: nil)
11
11
  @host = host
12
- @api_key = api_key
13
- @api_secret = api_secret
12
+ @key = key
13
+ @secret = secret
14
14
  @callbacks = {}
15
15
  end
16
16
 
@@ -24,10 +24,18 @@ module Deribit
24
24
  EM.run do
25
25
  connect
26
26
 
27
- id = rand(9999)
27
+ # request id
28
+ id = Time.now.to_i
28
29
  @callbacks[id] = callback
29
30
 
30
- payload = { id: id, action: "/api/v1/public/#{topic}", arguments: params }
31
+ # request action
32
+ auth = params.delete :auth
33
+ uri = auth ? 'private' : 'public'
34
+ action = "/api/v1/#{uri}/#{topic}"
35
+
36
+ payload = { id: id, action: action, arguments: params }
37
+ payload[:sig] = signature id, action, params if auth
38
+
31
39
  @faye.send payload.to_json.to_s
32
40
  end
33
41
  end
@@ -39,6 +47,19 @@ module Deribit
39
47
 
40
48
  private
41
49
 
50
+ def signature(nonce, action, params)
51
+ payload = {
52
+ _: nonce,
53
+ _ackey: @key,
54
+ _acsec: @secret,
55
+ _action: action
56
+ }
57
+ payload.merge! params
58
+ # query = env['url'].query
59
+
60
+ Deribit.signature @key, nonce, payload, nil
61
+ end
62
+
42
63
  def websocket_url
43
64
  "wss://#{host}/ws/api/v1/"
44
65
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deribit-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iulian Costan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-02 00:00:00.000000000 Z
11
+ date: 2019-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday