bitnob 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +30 -0
- data/.gitignore +57 -0
- data/.rspec +3 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +74 -0
- data/LICENSE +29 -0
- data/README.md +171 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bitnob.gemspec +40 -0
- data/lib/bitnob/errors.rb +30 -0
- data/lib/bitnob/modules/base_endpoints.rb +10 -0
- data/lib/bitnob/objects/base/base.rb +97 -0
- data/lib/bitnob/objects/customer.rb +57 -0
- data/lib/bitnob/objects/lightning.rb +86 -0
- data/lib/bitnob/objects/onchain.rb +48 -0
- data/lib/bitnob/objects/utils.rb +14 -0
- data/lib/bitnob/objects/wallets.rb +21 -0
- data/lib/bitnob/version.rb +5 -0
- data/lib/bitnob.rb +10 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d76d6992c04df571dbc84bde929721e5565adabcab0a2e06fc069cba1a2812a3
|
4
|
+
data.tar.gz: 5ad51857790fa9e67720a744b23a534c0374c871b64d4b649d53b716b4cd2bb5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 674820661f193897db89659d2e209fc079a99d16f86f851d9d0c753f8c43c589c7ebe8cb479e4eb5f3c183f9e2d124fc707755f1d8540001ae8ff4990108e0cf
|
7
|
+
data.tar.gz: e6d26d72ddc9e3ce69e35fd7b8b98c55d565329b053075d3adf8ff906a3582da5c6bc9fefda43750c84c13e25ee3e94c7655c8c2b4abf3d06aa402fd32b88dbb
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: SDK CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ main ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ main ]
|
8
|
+
|
9
|
+
env:
|
10
|
+
BITNOB_API_KEY: ${{ secrets.BITNOB_API_KEY}}
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
test:
|
14
|
+
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
|
17
|
+
strategy:
|
18
|
+
matrix:
|
19
|
+
ruby-version: [2.5.5]
|
20
|
+
|
21
|
+
steps:
|
22
|
+
- uses: actions/checkout@v2
|
23
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
24
|
+
uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
|
25
|
+
with:
|
26
|
+
ruby-version: ${{ matrix.ruby-version }}
|
27
|
+
- name: Install dependencies
|
28
|
+
run: bundle install
|
29
|
+
- name: Run tests
|
30
|
+
run: bundle exec rspec
|
data/.gitignore
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
.env
|
13
|
+
|
14
|
+
# Used by dotenv library to load environment variables.
|
15
|
+
# .env
|
16
|
+
|
17
|
+
# Ignore Byebug command history file.
|
18
|
+
.byebug_history
|
19
|
+
|
20
|
+
## Specific to RubyMotion:
|
21
|
+
.dat*
|
22
|
+
.repl_history
|
23
|
+
build/
|
24
|
+
*.bridgesupport
|
25
|
+
build-iPhoneOS/
|
26
|
+
build-iPhoneSimulator/
|
27
|
+
|
28
|
+
## Specific to RubyMotion (use of CocoaPods):
|
29
|
+
#
|
30
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
31
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
32
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
33
|
+
#
|
34
|
+
# vendor/Pods/
|
35
|
+
|
36
|
+
## Documentation cache and generated files:
|
37
|
+
/.yardoc/
|
38
|
+
/_yardoc/
|
39
|
+
/doc/
|
40
|
+
/rdoc/
|
41
|
+
|
42
|
+
## Environment normalization:
|
43
|
+
/.bundle/
|
44
|
+
/vendor/bundle
|
45
|
+
/lib/bundler/man/
|
46
|
+
|
47
|
+
# for a library or gem, you might want to ignore these files since the code is
|
48
|
+
# intended to run in multiple environments; otherwise, check them in:
|
49
|
+
# Gemfile.lock
|
50
|
+
# .ruby-version
|
51
|
+
# .ruby-gemset
|
52
|
+
|
53
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
54
|
+
.rvmrc
|
55
|
+
|
56
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
57
|
+
# .rubocop-https?--*
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-performance
|
3
|
+
- rubocop-rspec
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
TargetRubyVersion: 2.5
|
7
|
+
NewCops: enable
|
8
|
+
|
9
|
+
Style/Documentation:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Lint/MissingSuper:
|
13
|
+
Exclude:
|
14
|
+
- 'lib/**/**/*'
|
15
|
+
|
16
|
+
Metrics/MethodLength:
|
17
|
+
Max: 1000
|
18
|
+
|
19
|
+
Metrics/ClassLength:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Metrics/AbcSize:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Metrics/CyclomaticComplexity:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Metrics/PerceivedComplexity:
|
29
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bitnob (0.0.3)
|
5
|
+
dotenv (~> 2.7)
|
6
|
+
httparty (~> 0.19.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
ast (2.4.2)
|
12
|
+
diff-lcs (1.4.4)
|
13
|
+
dotenv (2.7.6)
|
14
|
+
httparty (0.19.0)
|
15
|
+
mime-types (~> 3.0)
|
16
|
+
multi_xml (>= 0.5.2)
|
17
|
+
mime-types (3.3.1)
|
18
|
+
mime-types-data (~> 3.2015)
|
19
|
+
mime-types-data (3.2021.0901)
|
20
|
+
multi_xml (0.6.0)
|
21
|
+
parallel (1.20.1)
|
22
|
+
parser (3.0.2.0)
|
23
|
+
ast (~> 2.4.1)
|
24
|
+
rainbow (3.0.0)
|
25
|
+
rake (13.0.6)
|
26
|
+
regexp_parser (2.1.1)
|
27
|
+
rexml (3.2.5)
|
28
|
+
rspec (3.10.0)
|
29
|
+
rspec-core (~> 3.10.0)
|
30
|
+
rspec-expectations (~> 3.10.0)
|
31
|
+
rspec-mocks (~> 3.10.0)
|
32
|
+
rspec-core (3.10.1)
|
33
|
+
rspec-support (~> 3.10.0)
|
34
|
+
rspec-expectations (3.10.1)
|
35
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
+
rspec-support (~> 3.10.0)
|
37
|
+
rspec-mocks (3.10.2)
|
38
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
39
|
+
rspec-support (~> 3.10.0)
|
40
|
+
rspec-support (3.10.2)
|
41
|
+
rubocop (1.20.0)
|
42
|
+
parallel (~> 1.10)
|
43
|
+
parser (>= 3.0.0.0)
|
44
|
+
rainbow (>= 2.2.2, < 4.0)
|
45
|
+
regexp_parser (>= 1.8, < 3.0)
|
46
|
+
rexml
|
47
|
+
rubocop-ast (>= 1.9.1, < 2.0)
|
48
|
+
ruby-progressbar (~> 1.7)
|
49
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
50
|
+
rubocop-ast (1.11.0)
|
51
|
+
parser (>= 3.0.1.1)
|
52
|
+
rubocop-performance (1.11.5)
|
53
|
+
rubocop (>= 1.7.0, < 2.0)
|
54
|
+
rubocop-ast (>= 0.4.0)
|
55
|
+
rubocop-rspec (2.4.0)
|
56
|
+
rubocop (~> 1.0)
|
57
|
+
rubocop-ast (>= 1.1.0)
|
58
|
+
ruby-progressbar (1.11.0)
|
59
|
+
unicode-display_width (2.0.0)
|
60
|
+
|
61
|
+
PLATFORMS
|
62
|
+
x86_64-linux
|
63
|
+
|
64
|
+
DEPENDENCIES
|
65
|
+
bitnob!
|
66
|
+
bundler (~> 2.2.27)
|
67
|
+
rake (~> 13.0.1)
|
68
|
+
rspec (~> 3.0)
|
69
|
+
rubocop (~> 1.20.0)
|
70
|
+
rubocop-performance (~> 1.11.5)
|
71
|
+
rubocop-rspec (~> 2.4.0)
|
72
|
+
|
73
|
+
BUNDLED WITH
|
74
|
+
2.2.27
|
data/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2021, Bitnob
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
17
|
+
contributors may be used to endorse or promote products derived from
|
18
|
+
this software without specific prior written permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
# Bitnob
|
2
|
+
---
|
3
|
+
This is a Ruby gem for easy integration of Bitnob For Business API for various applications written in Ruby language from Bitnob.
|
4
|
+
|
5
|
+
[![SDK CI](https://github.com/bitnob/bitnob_ruby_SDK/actions/workflows/main.yml/badge.svg)](https://github.com/bitnob/bitnob_ruby_SDK/actions/workflows/main.yml)
|
6
|
+
|
7
|
+
## Getting started
|
8
|
+
|
9
|
+
### Requirements
|
10
|
+
This gem requires Ruby 2.6+ and Rails 5.2+
|
11
|
+
|
12
|
+
### Installation
|
13
|
+
- Add the following to your gem file:
|
14
|
+
```ruby
|
15
|
+
gem 'bitnob', '~> 0.0.2'
|
16
|
+
```
|
17
|
+
Then run:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
bundle install
|
21
|
+
```
|
22
|
+
|
23
|
+
### Usage
|
24
|
+
- To use this SDK, you need to create a new Bitnob class with your API secret key gotten from your dashboard settings. We recommend you store such keys in an environment variable name `BITNOB_API_KEY`. Instantiating such object would look like this
|
25
|
+
|
26
|
+
|
27
|
+
By default the package assumes that you are currently working using a sandbox credential in development, however to go live, your `secret key` nust be a production-grade secret key and you need to specify `true` when instantiating your bitnob class like this:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'bitnob'
|
31
|
+
|
32
|
+
wallet = Wallet.new(true) # production
|
33
|
+
get_wallets = wallet.fetch_wallets
|
34
|
+
p get_wallets.body
|
35
|
+
|
36
|
+
# Sandbox environment
|
37
|
+
|
38
|
+
wallet = Wallet.new
|
39
|
+
|
40
|
+
get_transaction = wallet.fetch_all_transactions
|
41
|
+
p get_transaction.body
|
42
|
+
```
|
43
|
+
|
44
|
+
`NOTE`: It is best practice to always set your API keys to your environment variable for security purpose. Please be warned not use this package without setting your API keys in your environment variables in production.
|
45
|
+
|
46
|
+
### Bitnob Functions
|
47
|
+
- Before making use of any bitnob functions, it is expected you instantiate a new Function class and pass production as true to whatever function you wish to perform. Below is a demonstration:
|
48
|
+
|
49
|
+
- `Customer.new(true)`
|
50
|
+
- `Lightning.new(true)`
|
51
|
+
- `Onchain.new(true)`
|
52
|
+
- `Wallets.new(true)`
|
53
|
+
|
54
|
+
|
55
|
+
#### Customers
|
56
|
+
|
57
|
+
- To manage customers on your Bitnob for business in your ruby application, simply follow the instruction at the beginning of this sub-heading and instantiate a new `Customer` class.
|
58
|
+
- The following functions are available:
|
59
|
+
- create_customer
|
60
|
+
- get_customer_by_email
|
61
|
+
- get_customer
|
62
|
+
- update_customer
|
63
|
+
|
64
|
+
### Lightning
|
65
|
+
- To create Lightning Transactions, simply follow the instruction at the beginning of this sub-heading and instantiate a new `Lightning` class.
|
66
|
+
- The following functions are available:
|
67
|
+
- create_invoice
|
68
|
+
- pay_invoice
|
69
|
+
- initiate_payment
|
70
|
+
- decode_payment request
|
71
|
+
- get_invoice
|
72
|
+
|
73
|
+
|
74
|
+
###### Full Transaction Workflow
|
75
|
+
```ruby
|
76
|
+
require 'bitnob'
|
77
|
+
|
78
|
+
ln = Lightning.new(true)
|
79
|
+
|
80
|
+
payload = {
|
81
|
+
customerEmail: "parah@bitnob.com",
|
82
|
+
description: "Dorime for Nonso and Tumise",
|
83
|
+
tokens: 300,
|
84
|
+
expires_at: "24h",
|
85
|
+
}
|
86
|
+
|
87
|
+
# Create a lightning invoice
|
88
|
+
|
89
|
+
new_ln_invoice = ln.create_invoice(payload)
|
90
|
+
|
91
|
+
```
|
92
|
+
### Onchain
|
93
|
+
- To create Onchain Transactions, simply follow the instruction at the beginning of this sub-heading and instantiate a new `Onchain` class.
|
94
|
+
- The following functions are available:
|
95
|
+
- send_bitcoin
|
96
|
+
- generate_address
|
97
|
+
- list_addresses
|
98
|
+
|
99
|
+
|
100
|
+
#### Full Transaction Workflow
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
|
104
|
+
require 'bitnob'
|
105
|
+
|
106
|
+
on_chain = Onchain.new(true)
|
107
|
+
|
108
|
+
payload = {
|
109
|
+
customerEmail: "parah@bitnob.com",
|
110
|
+
satoshis: 30000,
|
111
|
+
address: "btcjshlidlsidskdslisidsdosilsdmxksjsjldksossjoioidjifkji.zjijsi",
|
112
|
+
description: "Go buy your momma a house!",
|
113
|
+
priorityLevel: "regular"
|
114
|
+
}
|
115
|
+
|
116
|
+
# Send bitcoin using onchain
|
117
|
+
|
118
|
+
new_onchain = on_chain.send_bitcoin(payload)
|
119
|
+
|
120
|
+
```
|
121
|
+
|
122
|
+
### Wallets
|
123
|
+
- To get wallets information, simply follow the instruction at the beginning of this sub-heading and instantiate a new `Wallets` class.
|
124
|
+
- The following functions are available:
|
125
|
+
- fetch_wallets
|
126
|
+
- fetch_all_transactions
|
127
|
+
- fetch_transaction
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
### Webhook Authentication
|
132
|
+
|
133
|
+
- You simply check to see if your webhook requests returns the appropriate body by simply doing this
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
|
137
|
+
require 'bitnob'
|
138
|
+
|
139
|
+
check_webhook = webhook_authentication(requests) # return true or false
|
140
|
+
```
|
141
|
+
|
142
|
+
### Important Note
|
143
|
+
|
144
|
+
- it is important that response from each function returns both the response headers, body and status code. To work with only the reponse body simply call the `BODY` object after each function call :
|
145
|
+
|
146
|
+
```ruby
|
147
|
+
require 'bitnob'
|
148
|
+
|
149
|
+
wallet = Wallet.new(true) # production
|
150
|
+
get_wallets = wallet.fetch_wallets
|
151
|
+
p get_wallets.body # fetches response body
|
152
|
+
p get_wallets.headers # fetches response headers
|
153
|
+
|
154
|
+
|
155
|
+
```
|
156
|
+
|
157
|
+
## Development
|
158
|
+
|
159
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run rake spec to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
160
|
+
|
161
|
+
To install this gem onto your local machine, run `bundle 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.
|
162
|
+
|
163
|
+
|
164
|
+
## Contributing
|
165
|
+
|
166
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/bitnob/bitnob_ruby_SDK](https://github.com/bitnob/bitnob_ruby_SDK). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct. Simply create a new branch and raise a Pull Request, we would review and merge.
|
167
|
+
|
168
|
+
## License
|
169
|
+
|
170
|
+
The gem is available as open source under the terms of the [BSD License](https://opensource.org/licenses/BSD-3-Clause)
|
171
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'bitnob'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require 'irb'
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/bitnob.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'bitnob/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'bitnob'
|
9
|
+
spec.version = Bitnob::VERSION
|
10
|
+
spec.authors = ['Bitnob', 'Nonso Amadi']
|
11
|
+
spec.email = ['nonso@bitnob.com']
|
12
|
+
|
13
|
+
spec.summary = 'Bitnob gem for Ruby/Rails'
|
14
|
+
spec.description = 'Client Library Gem for Bitnob API. Allows integration of Bitnob in your Ruby Applications'
|
15
|
+
spec.homepage = 'https://github.com/bitnob/bitnob_ruby_SDK'
|
16
|
+
spec.license = '0BSD'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = 'exe'
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
spec.extra_rdoc_files = ['README.md']
|
23
|
+
|
24
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
25
|
+
spec.metadata['source_code_uri'] = spec.homepage
|
26
|
+
spec.metadata['changelog_uri'] = spec.homepage
|
27
|
+
|
28
|
+
# Dev dependencies
|
29
|
+
spec.add_development_dependency 'bundler', '~> 2.2.27'
|
30
|
+
spec.add_development_dependency 'rake', '~> 13.0.1'
|
31
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
32
|
+
spec.add_development_dependency 'rubocop', '~> 1.20.0'
|
33
|
+
spec.add_development_dependency 'rubocop-performance', '~> 1.11.5'
|
34
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0'
|
35
|
+
|
36
|
+
# Dependencies
|
37
|
+
spec.required_ruby_version = '>= 2.5.0'
|
38
|
+
spec.add_dependency 'dotenv', '~> 2.7'
|
39
|
+
spec.add_dependency 'httparty', '~> 0.19.0'
|
40
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class BitnobServerError < StandardError
|
4
|
+
attr_reader :response
|
5
|
+
|
6
|
+
def initialize(response: nil)
|
7
|
+
@response = response
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class BitnobBadKeyError < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class PermissionError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
class BadRequestError < StandardError
|
18
|
+
end
|
19
|
+
|
20
|
+
class TooManyRequests < StandardError
|
21
|
+
end
|
22
|
+
|
23
|
+
class NotFoundError < StandardError
|
24
|
+
end
|
25
|
+
|
26
|
+
class IncompleteParameterError < StandardError
|
27
|
+
end
|
28
|
+
|
29
|
+
class UnAuthorizedError < StandardError
|
30
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BaseEndpoints
|
4
|
+
BITNOB_LIVE_URL = 'https://api.bitnob.co/api/v1'
|
5
|
+
BITNOB_SANDBOX_URL = 'https://sandboxapi.bitnob.co/api/v1'
|
6
|
+
CUSTOMER = '/customers'
|
7
|
+
LN = '/wallets/ln'
|
8
|
+
ONCHAIN = '/wallets'
|
9
|
+
ADDRESS = '/address'
|
10
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require_relative '../../modules/base_endpoints'
|
5
|
+
require 'json'
|
6
|
+
require_relative '../../errors'
|
7
|
+
|
8
|
+
class Base
|
9
|
+
attr_accessor :secret_key, :production, :url
|
10
|
+
|
11
|
+
def initialize(production = false)
|
12
|
+
# - bitnob api key
|
13
|
+
@secret_key = ENV['BITNOB_API_KEY']
|
14
|
+
bitnob_sandbox_url = BaseEndpoints::BITNOB_SANDBOX_URL
|
15
|
+
bitnob_live_url = BaseEndpoints::BITNOB_LIVE_URL
|
16
|
+
|
17
|
+
# set bitnob url to sandbox or live if we are in production or development
|
18
|
+
@url = if production == false
|
19
|
+
bitnob_sandbox_url
|
20
|
+
else
|
21
|
+
bitnob_live_url
|
22
|
+
end
|
23
|
+
|
24
|
+
def base_url
|
25
|
+
@url
|
26
|
+
end
|
27
|
+
|
28
|
+
if @secret_key.nil?
|
29
|
+
raise BitnobBadKeyError,
|
30
|
+
"No secret key supplied and couldn't find any in environment variables. Make sure to set secret key as an environment variable BITNOB_SECRET_KEY"
|
31
|
+
end
|
32
|
+
|
33
|
+
raise BitnobBadKeyError, "Invalid secret key #{@secret_key}" unless @secret_key[0..2] == 'sk.'
|
34
|
+
end
|
35
|
+
|
36
|
+
# make a get request
|
37
|
+
def get_request(endpoint)
|
38
|
+
response = HTTParty.get(endpoint, headers: { 'Authorization' => "Bearer #{@secret_key}" })
|
39
|
+
begin
|
40
|
+
unless response.code == 200 || response.code == 201
|
41
|
+
raise BitnobServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
|
42
|
+
end
|
43
|
+
|
44
|
+
raise BitnobServerError.new(response), "Server Message: #{response.message}" unless response.code != 0
|
45
|
+
|
46
|
+
response
|
47
|
+
rescue JSON::ParserError => e
|
48
|
+
raise BitnobServerError.new(response),
|
49
|
+
"Invalid result data. Could not parse JSON response body \n #{e.message}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# method to make a post request
|
54
|
+
def post_request(endpoint, data)
|
55
|
+
response = HTTParty.post(endpoint, {
|
56
|
+
body: data,
|
57
|
+
headers: {
|
58
|
+
'Content-Type' => 'application/json',
|
59
|
+
'Authorization' => "Bearer #{@secret_key}"
|
60
|
+
}
|
61
|
+
})
|
62
|
+
|
63
|
+
unless response.code == 200 || response.code == 201
|
64
|
+
raise BitnobServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
|
65
|
+
end
|
66
|
+
|
67
|
+
response
|
68
|
+
end
|
69
|
+
|
70
|
+
# method to make a put request
|
71
|
+
def put_request(endpoint, data)
|
72
|
+
response = HTTParty.put(endpoint, {
|
73
|
+
body: data,
|
74
|
+
headers: {
|
75
|
+
'Content-Type' => 'application/json',
|
76
|
+
'Authorization' => "Bearer #{@secret_key}"
|
77
|
+
}
|
78
|
+
})
|
79
|
+
|
80
|
+
unless response.code == 200 || response.code == 201
|
81
|
+
raise BitnobServerError.new(response), "HTTP Code #{response.code}: #{response.body}"
|
82
|
+
end
|
83
|
+
|
84
|
+
response
|
85
|
+
end
|
86
|
+
|
87
|
+
# - Verify that passed parameter contains required parameters
|
88
|
+
def check_parameters(required_params, passed_params)
|
89
|
+
# This is used to check if the passed authorization parameters matches the required parameters
|
90
|
+
required_params.each do |k, _v|
|
91
|
+
unless passed_params.key?(k)
|
92
|
+
raise IncompleteParameterError,
|
93
|
+
"Parameters Incomplete, Missing Parameter: #{k}, Please pass in the complete parameter."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base/base'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class Customer < Base
|
7
|
+
# -<tt>Required Parameters</tt>
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# data: {
|
11
|
+
# firstName: string(required),
|
12
|
+
# lastName: string(optional),
|
13
|
+
# email: string(required),
|
14
|
+
# countryCode: number(+234)(optional),
|
15
|
+
# phone: number(optional)
|
16
|
+
# }
|
17
|
+
def create_customer(data)
|
18
|
+
required_parameters = %w[firstName lastName email countryCode phone]
|
19
|
+
check_passed_parameters(required_parameters, data)
|
20
|
+
payload = data.to_json
|
21
|
+
|
22
|
+
post_request("#{base_url}#{BaseEndpoints::CUSTOMER}", payload)
|
23
|
+
end
|
24
|
+
|
25
|
+
# <tt>Required Parameter</tt>
|
26
|
+
#
|
27
|
+
# email: string
|
28
|
+
def get_customer_by_email(email)
|
29
|
+
body = { 'email' => email }
|
30
|
+
payload = body.to_json
|
31
|
+
|
32
|
+
post_request("#{base_url}#{BaseEndpoints::CUSTOMER}/fetch_customer", payload)
|
33
|
+
end
|
34
|
+
|
35
|
+
# <tt>Required Parameter</tt>
|
36
|
+
#
|
37
|
+
# customer_id: string
|
38
|
+
def get_customer(customer_id)
|
39
|
+
get_request("#{base_url}#{BaseEndpoints::CUSTOMER}/#{customer_id}")
|
40
|
+
end
|
41
|
+
|
42
|
+
# -<tt>Required Parameters</tt>
|
43
|
+
#
|
44
|
+
#
|
45
|
+
# data: {
|
46
|
+
# firstName: string(required),
|
47
|
+
# lastName: string(optional),
|
48
|
+
# email: string(required),
|
49
|
+
# countryCode: number(+234)(optional),
|
50
|
+
# phone: number(optional)
|
51
|
+
# }
|
52
|
+
def update_customer(customer_id, data)
|
53
|
+
payload = data.to_json
|
54
|
+
|
55
|
+
put_request("#{base_url}#{BaseEndpoints::CUSTOMER}/#{customer_id}", payload)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base/base'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# - Making Payments Via Lightning
|
7
|
+
class Lightning < Base
|
8
|
+
# Create Lightning invoice
|
9
|
+
#
|
10
|
+
# - Required Function Parameters:
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# data: {
|
14
|
+
# description: string,
|
15
|
+
# customerEmail: string,
|
16
|
+
# tokens: number,
|
17
|
+
# expires_at: string
|
18
|
+
# }
|
19
|
+
def create_invoice(data)
|
20
|
+
required_parameters = %w[description customerEmail tokens expires_at]
|
21
|
+
|
22
|
+
check_passed_parameters(required_parameters, data)
|
23
|
+
payload = data.to_json
|
24
|
+
|
25
|
+
post_request("#{base_url}#{BaseEndpoints::LN}/createinvoice", payload)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Pay Lightning invoice
|
29
|
+
#
|
30
|
+
# - Required Function Parameters:
|
31
|
+
#
|
32
|
+
#
|
33
|
+
# data: {
|
34
|
+
# description: string,
|
35
|
+
# customerEmail: string,
|
36
|
+
# request: string,
|
37
|
+
# }
|
38
|
+
|
39
|
+
def pay_invoice(data)
|
40
|
+
required_parameters = %w[request customerEmail description]
|
41
|
+
|
42
|
+
check_passed_parameters(required_parameters, data)
|
43
|
+
payload = data.to_json
|
44
|
+
|
45
|
+
post_request("#{base_url}#{BaseEndpoints::LN}/pay", payload)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Initiate payment is advised to be run before paying an invoice to calculate fees and check if an invoice has expired.
|
49
|
+
#
|
50
|
+
# - Required Function Parameters:
|
51
|
+
#
|
52
|
+
# request: string
|
53
|
+
|
54
|
+
def initiate_payment(request)
|
55
|
+
body = { request: request }
|
56
|
+
payload = body.to_json
|
57
|
+
|
58
|
+
post_request("#{base_url}#{BaseEndpoints::LN}/initiatepayment", payload)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Decode a BOLT 11 compliant payment request
|
62
|
+
#
|
63
|
+
# - Required Function Parameters:
|
64
|
+
#
|
65
|
+
# request: string
|
66
|
+
|
67
|
+
def decode_payment_request(request)
|
68
|
+
body = { request: request }
|
69
|
+
payload = body.to_json
|
70
|
+
|
71
|
+
post_request("#{base_url}#{BaseEndpoints::LN}/decodepaymentrequest", payload)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Getting Lightning invoice data
|
75
|
+
#
|
76
|
+
# - Required Function Parameters:
|
77
|
+
#
|
78
|
+
# invoice_id: string
|
79
|
+
|
80
|
+
def get_invoice(invoice_id)
|
81
|
+
body = { id: invoice_id }
|
82
|
+
payload = body.to_json
|
83
|
+
|
84
|
+
post_request("#{base_url}#{BaseEndpoints::LN}/getinvoice", payload)
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base/base'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# Handles all transactions via Onchain
|
7
|
+
class Onchain < Base
|
8
|
+
# Onchain sending of bitcoin
|
9
|
+
#
|
10
|
+
# - Required Function Parameters:
|
11
|
+
#
|
12
|
+
#
|
13
|
+
# data: {
|
14
|
+
# satoshis: number,
|
15
|
+
# customerEmail: string,
|
16
|
+
# address: string,
|
17
|
+
# priorityLevel: string
|
18
|
+
# }
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# - Priority level is used to detect how long a transaction would take. Its default is regular
|
22
|
+
def send_bitcoin(data)
|
23
|
+
required_parameters = %w[satoshis customerEmail address]
|
24
|
+
|
25
|
+
checked_passed_parameters(required_parameters, data)
|
26
|
+
payload = data.to_json
|
27
|
+
post_request("#{base_url}#{BaseEndpoints::ONCHAIN}/send_bitcoin", payload)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generates a temporary address for onchain transaction
|
31
|
+
#
|
32
|
+
# - Required Function Parameters: <tt>customer_email</tt>
|
33
|
+
def generate_address(customer_email)
|
34
|
+
body = { customerEmail: customer_email }
|
35
|
+
payload = body.to_json
|
36
|
+
post_request("#{base_url}#{BaseEndpoints::ADDRESS}/generate", payload)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns a JSON data containing list of addresses
|
40
|
+
#
|
41
|
+
# - Required Function Parameters: <tt>page_number</tt> <tt>limit</tt>
|
42
|
+
#
|
43
|
+
#
|
44
|
+
# default: <tt>page_number => 1, limit => 10</tt>
|
45
|
+
def list_addresses(page_number: 1, limit: 10)
|
46
|
+
get_request("#{base_url}#{BaseEndpoints::ADDRESS}order=ASC&page=#{page_number}&take=#{limit}")
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
require 'digest'
|
5
|
+
|
6
|
+
# - Authenticates Webhook Requests
|
7
|
+
def webhook_authentication(request)
|
8
|
+
webhook_secret = ENV['BITNOB_WEBHOOK_SECRET']
|
9
|
+
signature = request.headers['x-bitnob-signature']
|
10
|
+
digest = OpenSSL::Digest.new('Digest', 'sha512')
|
11
|
+
|
12
|
+
hash = OpenSSL::HMAC.hexdigest(digest, webhook_secret, request.body)
|
13
|
+
signature == hash
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'base/base'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class Wallets < Base
|
7
|
+
def fetch_wallets
|
8
|
+
get_request("#{base_url}#{BaseEndpoints::ONCHAIN}")
|
9
|
+
end
|
10
|
+
|
11
|
+
# page_number: number, limit: number
|
12
|
+
# default_value: page_number: 1, limit: 10
|
13
|
+
def fetch_all_transactions(page_number: 1, limit: 10)
|
14
|
+
get_request("#{base_url}#{BaseEndpoints::ONCHAIN}?order=ASC&page=#{page_number}&take=#{limit}")
|
15
|
+
end
|
16
|
+
|
17
|
+
# transaction_id: string
|
18
|
+
def fetch_transaction(transaction_id)
|
19
|
+
get_request("#{base_url}#{BaseEndpoints::ONCHAIN}/#{transaction_id}")
|
20
|
+
end
|
21
|
+
end
|
data/lib/bitnob.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'bitnob/objects/customer'
|
4
|
+
require_relative 'bitnob/objects/utils'
|
5
|
+
require_relative 'bitnob/objects/lightning'
|
6
|
+
require_relative 'bitnob/objects/onchain'
|
7
|
+
require_relative 'bitnob/objects/wallets'
|
8
|
+
require_relative 'bitnob/version'
|
9
|
+
require_relative 'bitnob/modules/base_endpoints'
|
10
|
+
require_relative 'bitnob/errors'
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bitnob
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bitnob
|
8
|
+
- Nonso Amadi
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2021-09-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 2.2.27
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 2.2.27
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 13.0.1
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 13.0.1
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '3.0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '3.0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rubocop
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.20.0
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.20.0
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rubocop-performance
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.11.5
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.11.5
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: rubocop-rspec
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 2.4.0
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 2.4.0
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: dotenv
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '2.7'
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '2.7'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: httparty
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 0.19.0
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.19.0
|
126
|
+
description: Client Library Gem for Bitnob API. Allows integration of Bitnob in your
|
127
|
+
Ruby Applications
|
128
|
+
email:
|
129
|
+
- nonso@bitnob.com
|
130
|
+
executables: []
|
131
|
+
extensions: []
|
132
|
+
extra_rdoc_files:
|
133
|
+
- README.md
|
134
|
+
files:
|
135
|
+
- ".github/workflows/main.yml"
|
136
|
+
- ".gitignore"
|
137
|
+
- ".rspec"
|
138
|
+
- ".rubocop.yml"
|
139
|
+
- CHANGELOG.md
|
140
|
+
- Gemfile
|
141
|
+
- Gemfile.lock
|
142
|
+
- LICENSE
|
143
|
+
- README.md
|
144
|
+
- Rakefile
|
145
|
+
- bin/console
|
146
|
+
- bin/setup
|
147
|
+
- bitnob.gemspec
|
148
|
+
- lib/bitnob.rb
|
149
|
+
- lib/bitnob/errors.rb
|
150
|
+
- lib/bitnob/modules/base_endpoints.rb
|
151
|
+
- lib/bitnob/objects/base/base.rb
|
152
|
+
- lib/bitnob/objects/customer.rb
|
153
|
+
- lib/bitnob/objects/lightning.rb
|
154
|
+
- lib/bitnob/objects/onchain.rb
|
155
|
+
- lib/bitnob/objects/utils.rb
|
156
|
+
- lib/bitnob/objects/wallets.rb
|
157
|
+
- lib/bitnob/version.rb
|
158
|
+
homepage: https://github.com/bitnob/bitnob_ruby_SDK
|
159
|
+
licenses:
|
160
|
+
- 0BSD
|
161
|
+
metadata:
|
162
|
+
homepage_uri: https://github.com/bitnob/bitnob_ruby_SDK
|
163
|
+
source_code_uri: https://github.com/bitnob/bitnob_ruby_SDK
|
164
|
+
changelog_uri: https://github.com/bitnob/bitnob_ruby_SDK
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 2.5.0
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubygems_version: 3.1.2
|
181
|
+
signing_key:
|
182
|
+
specification_version: 4
|
183
|
+
summary: Bitnob gem for Ruby/Rails
|
184
|
+
test_files: []
|