luno 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: daa749234c20ac9ba06398b5c4bd8e5c3e14af593411877ded14fd31d42d0aaf
4
- data.tar.gz: 4134f4e339b3f39f0a593b46b94baf665479a5e5681de2a0b57e46dcc0ba38a4
3
+ metadata.gz: 4e664e47e7a6037bf7e4ff9af7e7e40146cc8d393b0566e77f7f401c51433fb4
4
+ data.tar.gz: e46c10799631a0fafad6419a176a89c44917d90e4d99b152c7cf91fbd2075778
5
5
  SHA512:
6
- metadata.gz: b90a4e741c23e3cb14a45ccc7234ca4672a9d192af015d45a3796651ee52cdbf2739980aafa36318d88c5fef7ce711d31de7a69ed2588b35a4fb3e06ed5662f2
7
- data.tar.gz: 3c07483225243bdaf7ef880f37802fea9b0bd24233bc5773be7cd9898218054b6b8151bb9228d4df168dab6ea6652484dc2a25f4c3455cc7de6308981a45504f
6
+ metadata.gz: d33e2d46da2c3827164b7b217cda126b44410ee2c4beefdcf67ddba3bb43ff7ff56f15b943e45729e9b94c047fdefa1cd4abbeae89048516656b98bda1c9fdae
7
+ data.tar.gz: e7da2ac7785e87dbc147ce645a9dbbecf04ee01aceb003d7b8fc1dde7cfaecbbff7fd40e9552e10ec3f4b83fe47bed14231baa3394f43246050a76d68321fb73
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- luno (0.1.0)
4
+ luno (0.2.0)
5
5
  active_attr (~> 0.15)
6
6
  httparty (~> 0.18)
7
7
  nokogiri (~> 1.10.9)
@@ -82,7 +82,7 @@ GEM
82
82
  nokogiri (>= 1.6)
83
83
  rails-html-sanitizer (1.3.0)
84
84
  loofah (~> 2.3)
85
- rake (10.5.0)
85
+ rake (13.0.1)
86
86
  ruby-progressbar (1.10.1)
87
87
  safe_yaml (1.0.5)
88
88
  thread_safe (0.3.6)
@@ -106,7 +106,7 @@ DEPENDENCIES
106
106
  minitest-reporters (~> 1.4.2)
107
107
  mocha (~> 1.11.2)
108
108
  pry (~> 0.13)
109
- rake (~> 10.0)
109
+ rake (~> 13.0)
110
110
  timecop (~> 0.9.1)
111
111
  webmock (~> 3.8.3)
112
112
 
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Luno
2
+ A client for the Luno API. See: https://www.luno.com/en/developers/api
2
3
 
3
- This is a client for the Luno API. See: https://www.luno.com/en/developers/api
4
+ This is an unofficial project and still a work in progress (WIP) ... more to come soon.
4
5
 
5
6
  ## Installation
6
7
 
@@ -20,7 +21,35 @@ Or install it yourself as:
20
21
 
21
22
  ## Usage
22
23
 
23
- TODO: Write usage instructions here
24
+ ```ruby
25
+ require 'luno'
26
+ client = Luno::Client.new(key: 'your key', secret: 'your secret')
27
+ ```
28
+
29
+ ### Endpoints
30
+ - Accounts
31
+ - Beneficiaries
32
+ - Markets
33
+ - Orders
34
+ - Quotes
35
+ - Receiving
36
+ - Sending
37
+ - Transactions
38
+ - Withdrawals
39
+
40
+ ### Beta Endpoints
41
+ - Lightning
42
+ - Streaming
43
+
44
+ ### Other Endpoints
45
+ - ping(limit: 4, paths: ['https://www.luno.com/', 'https://api.mybitx.com/api/1/'])
46
+ - countries
47
+ - currencies
48
+ - permissions
49
+ - changelog
50
+
51
+ ### Constants
52
+ Constants
24
53
 
25
54
  ## Development
26
55
 
@@ -28,6 +57,11 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
28
57
 
29
58
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
30
59
 
60
+ ### Tests
61
+ To run tests execute:
62
+
63
+ $ rake test
64
+
31
65
  ## Contributing
32
66
 
33
67
  Bug reports and pull requests are welcome on GitHub at https://github.com/trex22/luno. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
data/lib/luno.rb CHANGED
@@ -2,6 +2,7 @@ require 'httparty'
2
2
  require 'nokogiri'
3
3
 
4
4
  require 'luno/version'
5
+ require 'luno/constants'
5
6
 
6
7
  # Endpoints
7
8
  require 'luno/accounts'
data/lib/luno/accounts.rb CHANGED
@@ -1,8 +1,32 @@
1
1
  module Luno
2
2
  module Accounts
3
+ # GET paths
3
4
  def list_accounts
4
5
  path = 'accounts'
5
6
  authorise_and_send(http_method: :get, path: path)
6
7
  end
8
+
9
+ def list_pending_account_transactions(account_id)
10
+ path = "accounts/#{account_id}/pending"
11
+ authorise_and_send(http_method: :get, path: path)
12
+ end
13
+
14
+ # Path params: min_row=1&max_row=1000
15
+ def list_account_transactions(account_id, min_row: -1000, max_row: 0)
16
+ path = "accounts/#{account_id}/transactions"
17
+ path_params = { min_row: min_row, max_row: max_row }
18
+ authorise_and_send(http_method: :get, path: path, params: path_params)
19
+ end
20
+
21
+ # List balances has been moved and retired as an endpoint
22
+
23
+ # POST paths
24
+ # TODO:
25
+ # Create account: /api/1/accounts body: { name: '', currency: '' }
26
+ # TODO: Check internally that inputs are valid
27
+
28
+ # PUT paths
29
+ # TODO:
30
+ # Update Account name: /api/1/accounts/{id}/name body: { name: '' }
7
31
  end
8
32
  end
@@ -1,5 +1,8 @@
1
1
  module Luno
2
2
  module Beneficiaries
3
-
3
+ def list_beneficiaries
4
+ path = 'beneficiaries'
5
+ authorise_and_send(http_method: :get, path: path)
6
+ end
4
7
  end
5
8
  end
data/lib/luno/client.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Luno
2
2
  class Client
3
+ include ::Luno::Constants
4
+
3
5
  # Endpoints
4
6
  include ::Luno::Accounts
5
7
  include ::Luno::Beneficiaries
@@ -38,12 +40,12 @@ module Luno
38
40
 
39
41
  private
40
42
 
41
- def unauthorised_and_send(http_method:, path:, payload: {})
43
+ def unauthorised_and_send(http_method:, path:, payload: {}, params: {})
42
44
  start_time = get_micro_second_time
43
45
 
44
46
  response = HTTParty.send(
45
47
  http_method.to_sym,
46
- construct_base_path(path),
48
+ construct_base_path(path, params),
47
49
  body: payload,
48
50
  headers: { 'Content-Type': 'application/json' },
49
51
  port: port,
@@ -51,17 +53,17 @@ module Luno
51
53
  )
52
54
 
53
55
  end_time = get_micro_second_time
54
- construct_response_obejct(response, start_time, end_time)
56
+ construct_response_object(response, path, start_time, end_time)
55
57
  end
56
58
 
57
- def authorise_and_send(http_method:, path:, payload: {})
59
+ def authorise_and_send(http_method:, path:, payload: {}, params: {})
58
60
  auth = {username: key, password: secret}
59
61
 
60
62
  start_time = get_micro_second_time
61
63
 
62
64
  response = HTTParty.send(
63
65
  http_method.to_sym,
64
- construct_base_path(path),
66
+ construct_base_path(path, params),
65
67
  body: payload,
66
68
  headers: { 'Content-Type': 'application/json' },
67
69
  port: port,
@@ -70,39 +72,63 @@ module Luno
70
72
  )
71
73
 
72
74
  end_time = get_micro_second_time
73
- construct_response_obejct(response, start_time, end_time)
75
+ construct_response_object(response, path, start_time, end_time)
74
76
  end
75
77
 
76
- def construct_response_obejct(response, start_time, end_time)
77
- if response.ok?
78
- response.to_json.merge({
79
- metadata: construct_metadata(start_time, end_time)
80
- })
81
- else
82
- {
83
- body: response.body,
84
- headers: response.headers,
85
- metadata: construct_metadata(start_time, end_time)
86
- }
87
- end
78
+ def construct_response_object(response, path, start_time, end_time)
79
+ {
80
+ 'body' => parse_body(response, path),
81
+ 'headers' => response.headers,
82
+ 'metadata' => construct_metadata(response, start_time, end_time)
83
+ }
88
84
  end
89
85
 
90
- def construct_metadata(start_time, end_time)
86
+ def construct_metadata(response, start_time, end_time)
91
87
  total_time = end_time - start_time
92
88
 
93
89
  {
94
- start_time: start_time,
95
- end_time: end_time,
96
- total_time: total_time
90
+ 'start_time' => start_time,
91
+ 'end_time' => end_time,
92
+ 'total_time' => total_time
97
93
  }
98
94
  end
99
95
 
96
+ def body_is_present?(response)
97
+ !body_is_missing?(response)
98
+ end
99
+
100
+ def body_is_missing?(response)
101
+ response.body.nil? || response.body.empty?
102
+ end
103
+
104
+ def parse_body(response, path)
105
+ parsed_response = JSON.parse(response.body) # Purposely not using HTTParty
106
+
107
+ if parsed_response.dig(path.to_s)
108
+ parsed_response.dig(path.to_s)
109
+ else
110
+ parsed_response
111
+ end
112
+ rescue JSON::ParserError => _e
113
+ response.body
114
+ end
115
+
100
116
  def get_micro_second_time
101
117
  (Time.now.to_f * 1000000).to_i
102
118
  end
103
119
 
104
- def construct_base_path(path)
105
- "#{base_path}/#{path}"
120
+ def construct_base_path(path, params)
121
+ constructed_path = "#{base_path}/#{path}"
122
+
123
+ if params != {}
124
+ constructed_path
125
+ else
126
+ "#{constructed_path}?#{process_params(params)}"
127
+ end
128
+ end
129
+
130
+ def process_params(params)
131
+ params.keys.map { |key| "#{key}=#{params[key]}" }.join('&')
106
132
  end
107
133
  end
108
134
  end
@@ -0,0 +1,70 @@
1
+ module Luno
2
+ module Constants
3
+ CURRENCIES = {
4
+ XBT: 'Bitcoin',
5
+ BCH: 'Bitcoin Cash',
6
+ ETH: 'Ethereum',
7
+ EUR: 'Euro',
8
+ MYR: 'Malaysian Ringgit',
9
+ NGN: 'Nigerian Naira',
10
+ UGX: 'Ugandan Shilling',
11
+ ZAR: 'South African Rand',
12
+ ZMW: 'Zambian Kwacha'
13
+ }
14
+
15
+ CURRENCY_PAIRS = [
16
+ 'XBTEUR',
17
+ 'XBTZAR',
18
+ 'XBTUGX',
19
+ 'XBTZMW',
20
+ 'ETHXBT',
21
+ 'BCHXBT'
22
+ ]
23
+
24
+ WITHDRAWL_CURRENCIES = [
25
+ BTC: 'Bitcoin',
26
+ BCH: 'Bitcoin Cash',
27
+ ETH: 'Ethereum',
28
+ BTC_LN: 'Lightning'
29
+ ]
30
+
31
+ WITHDRAWL_CURRENCY_PAIR_METHODS = {
32
+ ZAR_EFT: 'EFT',
33
+ NAD_EFT: 'EFT',
34
+ KES_EFT: 'EFT',
35
+ KES_MPESA: 'M-Pesa',
36
+ MYR_IBG: 'Interbank GIRO / IBFT',
37
+ IDR_LLG: 'Bank transfer, Lalu Lintas Giro',
38
+ NGN_EFT: 'Bank transfer',
39
+ ZMW_EFT: 'Bank transfer',
40
+ SGD_GIRO: 'GIRO / FAST',
41
+ SGD_WIRE: 'International Wire',
42
+ EUR_SEPA: 'SEPA transfer',
43
+ UGX_EFT: 'Bank transfer',
44
+ }
45
+
46
+ PERMISSIONS = {
47
+ Perm_R_Balance: { id: 1, description: '(View balance)' },
48
+ Perm_R_Transactions: { id: 2, description: '(View transactions)' },
49
+ Perm_W_Send: { id: 4, description: '(Send to any address)' },
50
+ Perm_R_Addresses: { id: 8, description: '(View addresses)' },
51
+ Perm_W_Addresses: { id: 16, description: '(Create addresses)' },
52
+ Perm_R_Orders: { id: 32, description: '(View orders)' },
53
+ Perm_W_Orders: { id: 64, description: '(Create orders)' },
54
+ Perm_R_Withdrawals: { id: 128, description: '(View withdrawals)' },
55
+ Perm_W_Withdrawals: { id: 256, description: '(Create withdrawals)' },
56
+ Perm_R_Merchant: { id: 512, description: '(View merchant invoices)' },
57
+ Perm_W_Merchant: { id: 1024, description: '(Create merchant invoices)' },
58
+ Perm_W_ClientDebit: { id: 8192, description: '(Debit accounts)' },
59
+ Perm_W_ClientCredit: { id: 16384, description: '(Credit accounts)' },
60
+ Perm_R_Beneficiaries: { id: 32768, description: '(View beneficiaries)' },
61
+ Perm_W_Beneficiaries: { id: 65536, description: '(Create and delete beneficiaries)' },
62
+ }
63
+
64
+ MARKET_API_RATE_LIMIT = 1 # per second per ip
65
+ MARKET_API_BURST_RATE_LIMIT = 5 # per second per ip
66
+
67
+ API_RATE_LIMIT = 5 # per second per ip
68
+ API_BURST_RATE_LIMIT = 25 # per second per ip
69
+ end
70
+ end
@@ -1,5 +1,11 @@
1
1
  module Luno
2
2
  module Lightning
3
+ # GET paths
4
+
5
+
6
+ # POST paths
7
+
8
+ # PUT paths
3
9
 
4
10
  end
5
11
  end
@@ -3,6 +3,9 @@
3
3
 
4
4
  module Luno
5
5
  module OtherData
6
+ COUNTRY_ENDPOINT = 'https://www.luno.com/en/countries'
7
+ DOCUMENTATION_ENDPOINT = 'https://www.luno.com/en/developers/api'
8
+
6
9
  def ping(limit: 4, paths: ['https://www.luno.com/', 'https://api.mybitx.com/api/1/'])
7
10
  endpoint_metrics = paths.map do |path|
8
11
  responses = []
@@ -12,45 +15,58 @@ module Luno
12
15
  end
13
16
 
14
17
  avg_time = responses
15
- .map { |r| r.dig(:metadata)&.dig(:total_time) }
18
+ .map { |r| r.dig('metadata')&.dig('total_time') }
16
19
  .reduce(&:+) / limit
17
20
 
18
21
  {
19
- path: path,
20
- average_time: avg_time
22
+ 'path' => path,
23
+ 'average_time' => avg_time
21
24
  }
22
25
  end
23
26
 
24
27
  {
25
- metadata: {
26
- endpoint_metrics: endpoint_metrics
28
+ 'metadata' => {
29
+ 'endpoint_metrics' => endpoint_metrics
27
30
  }
28
31
  }
29
32
  end
30
33
 
34
+ # TODO
31
35
  def countries
32
- call_countries
36
+ response = call_countries
33
37
  end
34
38
 
35
39
  # From API Documentation
40
+ # [WIP]
36
41
  def currencies
37
42
  lines = []
38
43
 
39
- call_api_documentation
44
+ response = call_api_documentation
45
+
46
+ output = parse_html(response['body'])
40
47
  .at('div#tag\/Currency')
41
48
  .search('li')
42
49
  .map(&:text)
43
50
  .map { |text| text.split.join(" ") }
51
+
52
+ {
53
+ 'body' => output,
54
+ 'headers' => response['headers'],
55
+ 'metadata' => response['metadata']
56
+ }
44
57
  end
45
58
 
59
+ # TODO
46
60
  def permissions
47
- call_api_documentation
61
+ response = call_api_documentation
48
62
  end
49
63
 
50
64
  def changelog
51
65
  lines = []
52
66
 
53
- call_api_documentation
67
+ response = call_api_documentation
68
+
69
+ parse_html(response['body'])
54
70
  .at('div#tag\/Changelog')
55
71
  .search('li')
56
72
  .map(&:text)
@@ -73,17 +89,31 @@ module Luno
73
89
  output.merge!(key => text)
74
90
  end
75
91
 
76
- output
92
+ {
93
+ 'body' => output,
94
+ 'headers' => response['headers'],
95
+ 'metadata' => response['metadata']
96
+ }
77
97
  end
78
98
 
79
99
  private
80
100
 
81
101
  def call_countries
82
- parse_html(HTTParty.get('https://www.luno.com/en/countries').body)
102
+ start_time = get_micro_second_time
103
+
104
+ response = HTTParty.get(COUNTRY_ENDPOINT)
105
+
106
+ end_time = get_micro_second_time
107
+ construct_response_obejct(response, start_time, end_time)
83
108
  end
84
109
 
85
110
  def call_api_documentation
86
- parse_html(HTTParty.get('https://www.luno.com/en/developers/api').body)
111
+ start_time = get_micro_second_time
112
+
113
+ response = HTTParty.get(DOCUMENTATION_ENDPOINT)
114
+
115
+ end_time = get_micro_second_time
116
+ construct_response_obejct(response, start_time, end_time)
87
117
  end
88
118
 
89
119
  def parse_html(raw_html)
data/lib/luno/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Luno
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/luno.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.email = ["contact@jasonchalom.com"]
10
10
 
11
11
  spec.summary = "A client for using the Luno API in Ruby."
12
- spec.description = "A client for using the Luno API in Ruby. It relies on the swagger spec from their api documentation. https://www.luno.com/en/developers/api"
12
+ spec.description = "A client for using the Luno API in Ruby. Built form their api documentation. https://www.luno.com/en/developers/api. This is an unofficial project."
13
13
  spec.homepage = "https://github.com/TRex22/luno"
14
14
  spec.license = "MIT"
15
15
 
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  # Development dependancies
30
30
  spec.add_development_dependency "bundler", "~> 1.17"
31
- spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rake", "~> 13.0"
32
32
  spec.add_development_dependency "minitest", "~> 5.0"
33
33
  spec.add_development_dependency "minitest-focus", "~> 1.1.2"
34
34
  spec.add_development_dependency "minitest-reporters", "~> 1.4.2"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: luno
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - trex22
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-23 00:00:00.000000000 Z
11
+ date: 2020-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: '13.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: '13.0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: minitest
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -178,8 +178,8 @@ dependencies:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
180
  version: 3.8.3
181
- description: A client for using the Luno API in Ruby. It relies on the swagger spec
182
- from their api documentation. https://www.luno.com/en/developers/api
181
+ description: A client for using the Luno API in Ruby. Built form their api documentation.
182
+ https://www.luno.com/en/developers/api. This is an unofficial project.
183
183
  email:
184
184
  - contact@jasonchalom.com
185
185
  executables: []
@@ -201,6 +201,7 @@ files:
201
201
  - lib/luno/accounts.rb
202
202
  - lib/luno/beneficiaries.rb
203
203
  - lib/luno/client.rb
204
+ - lib/luno/constants.rb
204
205
  - lib/luno/lightning.rb
205
206
  - lib/luno/markets.rb
206
207
  - lib/luno/orders.rb