luno 0.1.0 → 0.2.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.
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