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 +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +36 -2
- data/lib/luno.rb +1 -0
- data/lib/luno/accounts.rb +24 -0
- data/lib/luno/beneficiaries.rb +4 -1
- data/lib/luno/client.rb +50 -24
- data/lib/luno/constants.rb +70 -0
- data/lib/luno/lightning.rb +6 -0
- data/lib/luno/other_data.rb +42 -12
- data/lib/luno/version.rb +1 -1
- data/luno.gemspec +2 -2
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e664e47e7a6037bf7e4ff9af7e7e40146cc8d393b0566e77f7f401c51433fb4
|
4
|
+
data.tar.gz: e46c10799631a0fafad6419a176a89c44917d90e4d99b152c7cf91fbd2075778
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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 (
|
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 (~>
|
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
|
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
|
-
|
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
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
|
data/lib/luno/beneficiaries.rb
CHANGED
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
|
-
|
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
|
-
|
75
|
+
construct_response_object(response, path, start_time, end_time)
|
74
76
|
end
|
75
77
|
|
76
|
-
def
|
77
|
-
|
78
|
-
response
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
95
|
-
end_time
|
96
|
-
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
|
data/lib/luno/lightning.rb
CHANGED
data/lib/luno/other_data.rb
CHANGED
@@ -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(
|
18
|
+
.map { |r| r.dig('metadata')&.dig('total_time') }
|
16
19
|
.reduce(&:+) / limit
|
17
20
|
|
18
21
|
{
|
19
|
-
path
|
20
|
-
average_time
|
22
|
+
'path' => path,
|
23
|
+
'average_time' => avg_time
|
21
24
|
}
|
22
25
|
end
|
23
26
|
|
24
27
|
{
|
25
|
-
metadata
|
26
|
-
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
|
-
|
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
|
-
|
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
|
-
|
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
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.
|
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", "~>
|
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.
|
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-
|
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: '
|
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: '
|
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.
|
182
|
-
|
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
|