nanook 0.6.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 +7 -0
- data/.circleci/config.yml +56 -0
- data/.gitignore +8 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +21 -0
- data/README.md +304 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/img/qr.png +0 -0
- data/lib/nanook.rb +46 -0
- data/lib/nanook/account.rb +74 -0
- data/lib/nanook/block.rb +97 -0
- data/lib/nanook/error.rb +4 -0
- data/lib/nanook/key.rb +38 -0
- data/lib/nanook/node.rb +51 -0
- data/lib/nanook/rpc.rb +72 -0
- data/lib/nanook/util.rb +9 -0
- data/lib/nanook/version.rb +3 -0
- data/lib/nanook/wallet.rb +92 -0
- data/lib/nanook/wallet_account.rb +104 -0
- data/lib/nanook/work_peer.rb +27 -0
- data/nanook.gemspec +30 -0
- metadata +139 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 96226472bd51f8f70ef9462fa26ddf6b6f16da85
|
4
|
+
data.tar.gz: 014690cf0466ed78b0aa95a92ad9dd2f15a7581b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5571c48e4ce49a3e75487d7632d51ed4b7b5edc5ccb3aed14e3c7e18f92cd18c582606e2152ea4eb21bca238a077068a48b12db1036a43043d924c29e112fff2
|
7
|
+
data.tar.gz: cf515b77fe27f4cb882a36a04b8c109943388cdcd33db3c34a018f586a7c41f8c0a8dc406a048048dcfad21edde62bbae6e468d0131efa96202990f45eb170f1
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Ruby CircleCI 2.0 configuration file
|
2
|
+
#
|
3
|
+
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
|
+
#
|
5
|
+
version: 2
|
6
|
+
jobs:
|
7
|
+
build:
|
8
|
+
docker:
|
9
|
+
# specify the version you desire here
|
10
|
+
- image: circleci/ruby:2.4.1-node-browsers
|
11
|
+
|
12
|
+
# Specify service dependencies here if necessary
|
13
|
+
# CircleCI maintains a library of pre-built images
|
14
|
+
# documented at https://circleci.com/docs/2.0/circleci-images/
|
15
|
+
# - image: circleci/postgres:9.4
|
16
|
+
|
17
|
+
working_directory: ~/repo
|
18
|
+
|
19
|
+
steps:
|
20
|
+
- checkout
|
21
|
+
|
22
|
+
# Download and cache dependencies
|
23
|
+
- restore_cache:
|
24
|
+
keys:
|
25
|
+
- v1-dependencies-{{ checksum "Gemfile.lock" }}
|
26
|
+
# fallback to using the latest cache if no exact match is found
|
27
|
+
- v1-dependencies-
|
28
|
+
|
29
|
+
- run:
|
30
|
+
name: install dependencies
|
31
|
+
command: |
|
32
|
+
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
33
|
+
|
34
|
+
- save_cache:
|
35
|
+
paths:
|
36
|
+
- ./vendor/bundle
|
37
|
+
key: v1-dependencies-{{ checksum "Gemfile.lock" }}
|
38
|
+
|
39
|
+
# Database setup
|
40
|
+
# - run: bundle exec rake db:create
|
41
|
+
# - run: bundle exec rake db:schema:load
|
42
|
+
|
43
|
+
# run tests!
|
44
|
+
- run:
|
45
|
+
name: run tests
|
46
|
+
command: |
|
47
|
+
mkdir /tmp/test-results
|
48
|
+
|
49
|
+
bundle exec rspec spec --format progress --out /tmp/test-results/rspec.xml
|
50
|
+
|
51
|
+
# collect reports
|
52
|
+
- store_test_results:
|
53
|
+
path: /tmp/test-results
|
54
|
+
- store_artifacts:
|
55
|
+
path: /tmp/test-results
|
56
|
+
destination: test-results
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nanook (0.6.0)
|
5
|
+
symbolized
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.5.2)
|
11
|
+
public_suffix (>= 2.0.2, < 4.0)
|
12
|
+
crack (0.4.3)
|
13
|
+
safe_yaml (~> 1.0.0)
|
14
|
+
diff-lcs (1.3)
|
15
|
+
hashdiff (0.3.7)
|
16
|
+
public_suffix (3.0.2)
|
17
|
+
rake (10.5.0)
|
18
|
+
rspec (3.7.0)
|
19
|
+
rspec-core (~> 3.7.0)
|
20
|
+
rspec-expectations (~> 3.7.0)
|
21
|
+
rspec-mocks (~> 3.7.0)
|
22
|
+
rspec-core (3.7.1)
|
23
|
+
rspec-support (~> 3.7.0)
|
24
|
+
rspec-expectations (3.7.0)
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
+
rspec-support (~> 3.7.0)
|
27
|
+
rspec-mocks (3.7.0)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.7.0)
|
30
|
+
rspec-support (3.7.1)
|
31
|
+
safe_yaml (1.0.4)
|
32
|
+
symbolized (0.0.1)
|
33
|
+
webmock (3.3.0)
|
34
|
+
addressable (>= 2.3.6)
|
35
|
+
crack (>= 0.3.2)
|
36
|
+
hashdiff
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
bundler (~> 1.16)
|
43
|
+
nanook!
|
44
|
+
rake (~> 10.0)
|
45
|
+
rspec (~> 3.2)
|
46
|
+
webmock (~> 3.3)
|
47
|
+
|
48
|
+
BUNDLED WITH
|
49
|
+
1.16.0
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Luke Duncalfe
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,304 @@
|
|
1
|
+
# Nanook
|
2
|
+
|
3
|
+
This is a Ruby library for managing a [nano currency](https://nano.org/) node, including making and receiving payments, using the [nano RPC protocol](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol). Nano is a fee-less, fast, environmentally-friendly cryptocurrency. It's awesome. See [https://nano.org/](https://nano.org/).
|
4
|
+
|
5
|
+
[](https://badge.fury.io/rb/nanook)
|
6
|
+
[](https://circleci.com/gh/lukes/nanook/tree/master)
|
7
|
+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'nanook'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install nanook
|
24
|
+
|
25
|
+
# Getting Started
|
26
|
+
|
27
|
+
## Initializing
|
28
|
+
|
29
|
+
Nanook will by default connect to `http://localhost:7076`. If you're using Nanook from the nano node itself this will generally work fine.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
nanook = Nanook.new
|
33
|
+
```
|
34
|
+
|
35
|
+
To connect to another host instead:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
nanook = Nanook.new("http://example.com:7076")
|
39
|
+
```
|
40
|
+
|
41
|
+
## Basics
|
42
|
+
|
43
|
+
### Working with wallets and accounts
|
44
|
+
|
45
|
+
Create a wallet:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
Nanook.new.wallet.create
|
49
|
+
```
|
50
|
+
|
51
|
+
Create an account within a wallet:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
Nanook.new.wallet(wallet_id).account.create
|
55
|
+
```
|
56
|
+
|
57
|
+
List accounts within a wallet:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
Nanook.new.wallet(wallet_id).accounts
|
61
|
+
```
|
62
|
+
|
63
|
+
### Sending a payment
|
64
|
+
|
65
|
+
You can send a payment from an account in a wallet:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
account = Nanook.new.wallet(wallet_id).account(account_id)
|
69
|
+
account.pay(to: recipient_account_id, amount: 0.2, id: unique_id)
|
70
|
+
```
|
71
|
+
|
72
|
+
Or, a wallet:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
wallet = Nanook.new.wallet(wallet_id)
|
76
|
+
wallet.pay(from: your_account_id, to: recipient_account_id, amount: 0.2, id: unique_id)
|
77
|
+
```
|
78
|
+
|
79
|
+
The `id` can be any string and needs to be unique per payment. It serves an important purpose; it allows you to make this call multiple times with the same `id` and be reassured that you will only ever send that nano payment once. From the [Nano RPC](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol#account-create):
|
80
|
+
|
81
|
+
> You can (and should) specify a unique id for each spend to provide idempotency. That means that if you [make the payment call] two times with the same id, the second request won't send any additional Nano.
|
82
|
+
|
83
|
+
The unit of the `amount` is NANO (which is currently technically 1Mnano — see [What are Nano's Units](https://nano.org/en/faq#what-are-nano-units-)).
|
84
|
+
|
85
|
+
Note, there may be a delay in receiving a response due to Proof of Work being done. From the [Nano RPC](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol#account-create):
|
86
|
+
|
87
|
+
> Proof of Work is precomputed for one transaction in the background. If it has been a while since your last transaction it will send instantly, the next one will need to wait for Proof of Work to be generated.
|
88
|
+
|
89
|
+
### Receiving a payment
|
90
|
+
|
91
|
+
The simplest way to receive a payment is:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
account = Nanook.new.wallet(wallet_id).account(account_id)
|
95
|
+
account.receive
|
96
|
+
|
97
|
+
# or:
|
98
|
+
|
99
|
+
wallet = Nanook.new.wallet(wallet_id)
|
100
|
+
wallet.receive(into: account_id)
|
101
|
+
```
|
102
|
+
|
103
|
+
The `receive` method when called as above will receive the latest pending payment for an account in a wallet. It will either return a RPC response containing the block if a payment was received, or `false` if there were no pending payments to receive.
|
104
|
+
|
105
|
+
You can also receive a specific pending block if you know it (you may have discovered it through calling `account.pending` for example):
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
account = Nanook.new.wallet(wallet_id).account(account_id)
|
109
|
+
account.receive(block_id)
|
110
|
+
|
111
|
+
# or:
|
112
|
+
|
113
|
+
wallet = Nanook.new.wallet(wallet_id)
|
114
|
+
wallet.receive(block_id, into: account_id)
|
115
|
+
```
|
116
|
+
|
117
|
+
## All commands
|
118
|
+
|
119
|
+
### Wallets
|
120
|
+
|
121
|
+
#### Create wallet:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
Nanook.new.wallet.create
|
125
|
+
```
|
126
|
+
|
127
|
+
#### Working with a single wallet:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
wallet = Nanook.new.wallet(wallet_id)
|
131
|
+
|
132
|
+
wallet.export
|
133
|
+
wallet.locked?
|
134
|
+
wallet.unlock(password)
|
135
|
+
wallet.change_password(password)
|
136
|
+
|
137
|
+
wallet.balance
|
138
|
+
wallet.balance(account_break_down: true)
|
139
|
+
wallet.pay(from: your_account_id, to: recipient_account_id, amount: 0.2, id: unique_id)
|
140
|
+
wallet.receive(into: account_id)
|
141
|
+
wallet.receive(pending_block_id, into: account_id)
|
142
|
+
|
143
|
+
wallet.account.create
|
144
|
+
wallet.accounts
|
145
|
+
wallet.contains?(account_id)
|
146
|
+
|
147
|
+
wallet.destroy
|
148
|
+
```
|
149
|
+
### Accounts
|
150
|
+
|
151
|
+
#### Create account:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
Nanook.new.wallet(wallet_id).account.create
|
155
|
+
```
|
156
|
+
|
157
|
+
#### Working with a single account:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
account = Nanook.new.wallet(wallet_id).account(account_id)
|
161
|
+
|
162
|
+
account.exists?
|
163
|
+
account.info
|
164
|
+
account.ledger
|
165
|
+
account.ledger(limit: 10)
|
166
|
+
account.history
|
167
|
+
account.history(limit: 1)
|
168
|
+
account.public_key
|
169
|
+
account.delegators
|
170
|
+
account.representative
|
171
|
+
account.weight
|
172
|
+
|
173
|
+
account.balance
|
174
|
+
account.pay(to: recipient_account_id, amount: 0.2, id: unique_id)
|
175
|
+
account.pending
|
176
|
+
account.pending(limit: 1)
|
177
|
+
account.receive
|
178
|
+
account.receive(pending_block_id)
|
179
|
+
|
180
|
+
account.destroy
|
181
|
+
```
|
182
|
+
|
183
|
+
#### Working with any account (not necessarily in your wallet):
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
account = Nanook.new.account(account_id)
|
187
|
+
|
188
|
+
account.exists?
|
189
|
+
account.info
|
190
|
+
account.ledger
|
191
|
+
account.ledger(limit: 10)
|
192
|
+
account.history
|
193
|
+
account.history(limit: 1)
|
194
|
+
account.public_key
|
195
|
+
account.delegators
|
196
|
+
account.representative
|
197
|
+
account.weight
|
198
|
+
|
199
|
+
account.balance
|
200
|
+
account.pending
|
201
|
+
account.pending(limit: 1)
|
202
|
+
```
|
203
|
+
|
204
|
+
### Blocks
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
block = Nanook.new.block(block_id)
|
208
|
+
|
209
|
+
block.info # Verified blocks in the ledger
|
210
|
+
block.info(allow_unchecked: true) # Verified blocks AND unchecked synchronizing blocks
|
211
|
+
block.account
|
212
|
+
block.chain
|
213
|
+
block.chain(limit: 10)
|
214
|
+
block.history
|
215
|
+
block.history(limit: 10)
|
216
|
+
block.republish
|
217
|
+
block.republish(sources: 2)
|
218
|
+
block.republish(destinations: 2)
|
219
|
+
block.pending?
|
220
|
+
block.process
|
221
|
+
block.successors
|
222
|
+
block.successors(limit: 10)
|
223
|
+
|
224
|
+
block.generate_work
|
225
|
+
block.cancel_work
|
226
|
+
block.is_valid_work?(work_id)
|
227
|
+
```
|
228
|
+
|
229
|
+
### Managing your nano node
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
node = Nanook.new.node
|
233
|
+
|
234
|
+
node.block_count
|
235
|
+
node.block_count_type
|
236
|
+
node.bootstrap_any
|
237
|
+
node.bootstrap(address: "::ffff:138.201.94.249", port: 7075)
|
238
|
+
node.frontier_count
|
239
|
+
node.peers
|
240
|
+
node.representatives
|
241
|
+
node.stop
|
242
|
+
node.version
|
243
|
+
```
|
244
|
+
|
245
|
+
### Work peers
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
work_peers = Nanook.new.work_peers
|
249
|
+
|
250
|
+
work_peers.add(address: "::ffff:172.17.0.1:7076", port: 7076)
|
251
|
+
work_peers.clear
|
252
|
+
work_peers.list
|
253
|
+
```
|
254
|
+
|
255
|
+
### Keys
|
256
|
+
|
257
|
+
#### Create private public key pair:
|
258
|
+
|
259
|
+
```ruby
|
260
|
+
Nanook.new.key.generate
|
261
|
+
Nanook.new.key.generate(seed: seed, index: 0)
|
262
|
+
```
|
263
|
+
|
264
|
+
#### Working with a single key
|
265
|
+
|
266
|
+
```ruby
|
267
|
+
key = Nanook.new.key(private_key)
|
268
|
+
|
269
|
+
key.info
|
270
|
+
```
|
271
|
+
|
272
|
+
## Nanook Metal
|
273
|
+
|
274
|
+
You can do any call listed in the [Nano RPC](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol) directly through the `rpc` method. The first argument should match the `action` of the RPC call, and then all remaining parameters are passed in as arguments.
|
275
|
+
|
276
|
+
E.g., the [accounts_create command](https://github.com/nanocurrency/raiblocks/wiki/RPC-protocol#accounts-create) can be called like this:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
Nano.new.rpc(:accounts_create, wallet: wallet_id, count: 2)
|
280
|
+
```
|
281
|
+
|
282
|
+
## Contributing
|
283
|
+
|
284
|
+
Bug reports and pull requests are welcome. Pull requests with passing tests are even better.
|
285
|
+
|
286
|
+
To run the test suite:
|
287
|
+
|
288
|
+
bundle exec rspec spec
|
289
|
+
|
290
|
+
## License
|
291
|
+
|
292
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
293
|
+
|
294
|
+
|
295
|
+
## Buy me a nano coffee
|
296
|
+
|
297
|
+
This library is totally free to use, but feel free to send some nano [my way](https://www.nanode.co/account/xrb_3c3ek3k8135f6e8qtfy8eruk9q3yzmpebes7btzncccdest8ymzhjmnr196j) if you'd like to!
|
298
|
+
|
299
|
+
xrb_3c3ek3k8135f6e8qtfy8eruk9q3yzmpebes7btzncccdest8ymzhjmnr196j
|
300
|
+
|
301
|
+

|
302
|
+
|
303
|
+
|
304
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "nanook"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/img/qr.png
ADDED
Binary file
|
data/lib/nanook.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
require 'nanook/account'
|
5
|
+
require 'nanook/block'
|
6
|
+
require 'nanook/error'
|
7
|
+
require 'nanook/key'
|
8
|
+
require 'nanook/node'
|
9
|
+
require 'nanook/rpc'
|
10
|
+
require 'nanook/util'
|
11
|
+
require 'nanook/version'
|
12
|
+
require 'nanook/wallet_account'
|
13
|
+
require 'nanook/wallet'
|
14
|
+
require 'nanook/work_peer'
|
15
|
+
|
16
|
+
class Nanook
|
17
|
+
|
18
|
+
def initialize(uri=Nanook::Rpc::DEFAULT_URI, timeout:Nanook::Rpc::DEFAULT_URI)
|
19
|
+
@rpc = Nanook::Rpc.new(uri, timeout: timeout)
|
20
|
+
end
|
21
|
+
|
22
|
+
def account(account=nil)
|
23
|
+
Nanook::Account.new(account, @rpc)
|
24
|
+
end
|
25
|
+
|
26
|
+
def block(block=nil)
|
27
|
+
Nanook::Block.new(block, @rpc)
|
28
|
+
end
|
29
|
+
|
30
|
+
def key(key=nil)
|
31
|
+
Nanook::Key.new(key, @rpc)
|
32
|
+
end
|
33
|
+
|
34
|
+
def node
|
35
|
+
Nanook::Node.new(@rpc)
|
36
|
+
end
|
37
|
+
|
38
|
+
def wallet(wallet=nil)
|
39
|
+
Nanook::Wallet.new(wallet, @rpc)
|
40
|
+
end
|
41
|
+
|
42
|
+
def work_peers
|
43
|
+
Nanook::WorkPeer.new(@rpc)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class Nanook
|
2
|
+
class Account
|
3
|
+
|
4
|
+
def initialize(account, rpc)
|
5
|
+
@account = account
|
6
|
+
@rpc = rpc
|
7
|
+
end
|
8
|
+
|
9
|
+
def delegators
|
10
|
+
account_required!
|
11
|
+
rpc(:delegators)
|
12
|
+
end
|
13
|
+
|
14
|
+
def exists?
|
15
|
+
account_required!
|
16
|
+
response = rpc(:validate_account_number)
|
17
|
+
!response.empty? && response[:valid] == 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def history(limit: 1000)
|
21
|
+
account_required!
|
22
|
+
rpc(:account_history, count: limit)
|
23
|
+
end
|
24
|
+
|
25
|
+
def public_key
|
26
|
+
account_required!
|
27
|
+
rpc(:account_key)
|
28
|
+
end
|
29
|
+
|
30
|
+
def representative
|
31
|
+
account_required!
|
32
|
+
rpc(:account_representative)
|
33
|
+
end
|
34
|
+
|
35
|
+
def balance
|
36
|
+
account_required!
|
37
|
+
rpc(:account_balance)
|
38
|
+
end
|
39
|
+
|
40
|
+
def info
|
41
|
+
account_required!
|
42
|
+
rpc(:account_info)
|
43
|
+
end
|
44
|
+
|
45
|
+
def ledger(limit: 1)
|
46
|
+
account_required!
|
47
|
+
rpc(:ledger, count: limit)
|
48
|
+
end
|
49
|
+
|
50
|
+
def pending(limit: 1000)
|
51
|
+
account_required!
|
52
|
+
rpc(:pending, count: limit)
|
53
|
+
end
|
54
|
+
|
55
|
+
def weight
|
56
|
+
account_required!
|
57
|
+
rpc(:account_weight)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def rpc(action, params={})
|
63
|
+
p = @account.nil? ? {} : { account: @account }
|
64
|
+
@rpc.call(action, p.merge(params))
|
65
|
+
end
|
66
|
+
|
67
|
+
def account_required!
|
68
|
+
if @account.nil?
|
69
|
+
raise ArgumentError.new("Account must be present")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
data/lib/nanook/block.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
class Nanook
|
2
|
+
class Block
|
3
|
+
|
4
|
+
def initialize(block, rpc)
|
5
|
+
@block = block
|
6
|
+
@rpc = rpc
|
7
|
+
block_required! # All methods expect a block
|
8
|
+
end
|
9
|
+
|
10
|
+
def account
|
11
|
+
rpc(:block_account, :hash)
|
12
|
+
end
|
13
|
+
|
14
|
+
def cancel_work
|
15
|
+
rpc(:work_cancel, :hash)
|
16
|
+
end
|
17
|
+
|
18
|
+
def chain(limit: 1000)
|
19
|
+
rpc(:chain, :block, count: limit)
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate_work
|
23
|
+
rpc(:work_generate, :hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
def history(limit: 1000)
|
27
|
+
rpc(:history, :hash, count: limit)
|
28
|
+
end
|
29
|
+
|
30
|
+
def info(allow_unchecked: false)
|
31
|
+
if allow_unchecked
|
32
|
+
# TODO not actually sure what this response looks like when it's not an unchecked block, assuming its blank
|
33
|
+
response = rpc(:unchecked_get, :hash)
|
34
|
+
return response unless response[:error] == "Block not found"
|
35
|
+
# Continue on falling backto checked block
|
36
|
+
end
|
37
|
+
|
38
|
+
response = rpc(:block, :hash)
|
39
|
+
|
40
|
+
# The contents is a stringified JSON
|
41
|
+
if response[:contents]
|
42
|
+
response[:contents] = JSON.parse(response[:contents])
|
43
|
+
end
|
44
|
+
|
45
|
+
response
|
46
|
+
end
|
47
|
+
|
48
|
+
def is_valid_work?(work)
|
49
|
+
response = rpc(:work_validate, :hash, work: work)
|
50
|
+
!response.empty? && response[:valid] == 1
|
51
|
+
end
|
52
|
+
|
53
|
+
def republish(destinations:nil, sources:nil)
|
54
|
+
if !destinations.nil? && !sources.nil?
|
55
|
+
raise ArgumentError.new("You must provide either destinations or sources but not both")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Add in optional arguments
|
59
|
+
params = {}
|
60
|
+
params[:destinations] = destinations unless destinations.nil?
|
61
|
+
params[:sources] = sources unless sources.nil?
|
62
|
+
params[:count] = 1 unless params.empty?
|
63
|
+
|
64
|
+
rpc(:republish, :hash, params)
|
65
|
+
end
|
66
|
+
|
67
|
+
def pending?
|
68
|
+
response = rpc(:pending_exists, :hash)
|
69
|
+
!response.empty? && response[:exists] == 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def process
|
73
|
+
rpc(:process, :block)
|
74
|
+
end
|
75
|
+
|
76
|
+
def successors(limit: 1000)
|
77
|
+
rpc(:successors, :block, count: limit)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Some RPC calls expect the param that represents the block to be named
|
83
|
+
# "hash", and others "block".
|
84
|
+
# The param_name argument allows us to specify which it should be for this call.
|
85
|
+
def rpc(action, param_name, params={})
|
86
|
+
p = @block.nil? ? {} : { param_name.to_sym => @block }
|
87
|
+
@rpc.call(action, p.merge(params))
|
88
|
+
end
|
89
|
+
|
90
|
+
def block_required!
|
91
|
+
if @block.nil?
|
92
|
+
raise ArgumentError.new("Block must be present")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
data/lib/nanook/error.rb
ADDED
data/lib/nanook/key.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class Nanook
|
2
|
+
class Key
|
3
|
+
|
4
|
+
def initialize(key=nil, rpc)
|
5
|
+
@key = key
|
6
|
+
@rpc = rpc
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate(seed: nil, index: nil)
|
10
|
+
if seed.nil? && index.nil?
|
11
|
+
rpc(:key_create)
|
12
|
+
elsif !seed.nil? && !index.nil?
|
13
|
+
rpc(:deterministic_key, seed: seed, index: index)
|
14
|
+
else
|
15
|
+
raise ArgumentError.new("This method must be called with either seed AND index params given or no params")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def info
|
20
|
+
key_required!
|
21
|
+
rpc(:key_expand)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def rpc(action, params={})
|
27
|
+
p = @key.nil? ? {} : { key: @key }
|
28
|
+
@rpc.call(action, p.merge(params))
|
29
|
+
end
|
30
|
+
|
31
|
+
def key_required!
|
32
|
+
if @key.nil?
|
33
|
+
raise ArgumentError.new("Key must be present")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/lib/nanook/node.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
class Nanook
|
2
|
+
class Node
|
3
|
+
|
4
|
+
def initialize(rpc)
|
5
|
+
@rpc = rpc
|
6
|
+
end
|
7
|
+
|
8
|
+
def block_count
|
9
|
+
rpc(:block_count)
|
10
|
+
end
|
11
|
+
|
12
|
+
def block_count_type
|
13
|
+
rpc(:block_count_type)
|
14
|
+
end
|
15
|
+
|
16
|
+
def bootstrap(address:, port:)
|
17
|
+
rpc(:bootstrap, address: address, port: port)
|
18
|
+
end
|
19
|
+
|
20
|
+
def bootstrap_any
|
21
|
+
rpc(:bootstrap_any)
|
22
|
+
end
|
23
|
+
|
24
|
+
def frontier_count
|
25
|
+
rpc(:frontier_count)
|
26
|
+
end
|
27
|
+
|
28
|
+
def peers
|
29
|
+
rpc(:peers)
|
30
|
+
end
|
31
|
+
|
32
|
+
def representatives
|
33
|
+
rpc(:representatives)
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop
|
37
|
+
rpc(:stop)
|
38
|
+
end
|
39
|
+
|
40
|
+
def version
|
41
|
+
rpc(:version)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def rpc(action, params={})
|
47
|
+
@rpc.call(action, params)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/lib/nanook/rpc.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'symbolized'
|
3
|
+
|
4
|
+
require 'nanook/error'
|
5
|
+
|
6
|
+
class Nanook
|
7
|
+
class Rpc
|
8
|
+
|
9
|
+
DEFAULT_URI = "http://localhost:7076"
|
10
|
+
DEFAULT_TIMEOUT = 500 # seconds
|
11
|
+
|
12
|
+
def initialize(uri=DEFAULT_URI, timeout:DEFAULT_TIMEOUT)
|
13
|
+
rpc_server = URI(uri)
|
14
|
+
|
15
|
+
unless ['http', 'https'].include?(rpc_server.scheme)
|
16
|
+
raise ArgumentError.new("URI must have http or https in it. Was given: #{uri}")
|
17
|
+
end
|
18
|
+
|
19
|
+
@http = Net::HTTP.new(rpc_server.host, rpc_server.port)
|
20
|
+
@http.read_timeout = timeout
|
21
|
+
@request = Net::HTTP::Post.new(rpc_server.request_uri, {"user-agent" => "Ruby nanook gem"})
|
22
|
+
@request.content_type = "application/json"
|
23
|
+
end
|
24
|
+
|
25
|
+
def call(action, params={})
|
26
|
+
# Stringify param values
|
27
|
+
params = Hash[params.map {|k, v| [k, v.to_s] }]
|
28
|
+
|
29
|
+
@request.body = { action: action }.merge(params).to_json
|
30
|
+
|
31
|
+
response = @http.request(@request)
|
32
|
+
|
33
|
+
if response.is_a?(Net::HTTPSuccess)
|
34
|
+
hash = JSON.parse(response.body)
|
35
|
+
process_hash(hash)
|
36
|
+
else
|
37
|
+
raise Nanook::Error.new("Encountered net/http error #{response.code}: #{response.class.name}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Convert Strings of primitives to primitives
|
44
|
+
def process_hash(h)
|
45
|
+
new_hash = h.map do |k,v|
|
46
|
+
v = if v.is_a?(Array)
|
47
|
+
if v[0].is_a?(Hash)
|
48
|
+
v.map{|v| process_hash(v)}
|
49
|
+
else
|
50
|
+
v.map{|v| parse_value(v)}
|
51
|
+
end
|
52
|
+
elsif v.is_a?(Hash)
|
53
|
+
process_hash(v)
|
54
|
+
else
|
55
|
+
parse_value(v)
|
56
|
+
end
|
57
|
+
|
58
|
+
[k, v]
|
59
|
+
end
|
60
|
+
|
61
|
+
Hash[new_hash].to_symbolized_hash
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_value(v)
|
65
|
+
return v.to_i if v.match(/^\d+\Z/)
|
66
|
+
return true if v == "true"
|
67
|
+
return false if v == "false"
|
68
|
+
v
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/lib/nanook/util.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
class Nanook
|
2
|
+
class Wallet
|
3
|
+
|
4
|
+
def initialize(wallet, rpc)
|
5
|
+
@wallet = wallet
|
6
|
+
@rpc = rpc
|
7
|
+
end
|
8
|
+
|
9
|
+
def account(account=nil)
|
10
|
+
Nanook::WalletAccount.new(@wallet, account, @rpc)
|
11
|
+
end
|
12
|
+
|
13
|
+
def accounts
|
14
|
+
wallet_required!
|
15
|
+
rpc(:account_list)
|
16
|
+
end
|
17
|
+
|
18
|
+
def balance(account_break_down: false)
|
19
|
+
wallet_required!
|
20
|
+
if account_break_down
|
21
|
+
rpc(:wallet_balances)
|
22
|
+
else
|
23
|
+
rpc(:wallet_balance_total)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def create
|
28
|
+
rpc(:wallet_create)
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy
|
32
|
+
wallet_required!
|
33
|
+
rpc(:wallet_destroy)
|
34
|
+
end
|
35
|
+
|
36
|
+
def export
|
37
|
+
wallet_required!
|
38
|
+
rpc(:wallet_export)
|
39
|
+
end
|
40
|
+
|
41
|
+
def contains?(account)
|
42
|
+
wallet_required!
|
43
|
+
response = rpc(:wallet_contains, account: account)
|
44
|
+
!response.empty? && response[:exists] == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
def pay(from:, to:, amount:, id:)
|
48
|
+
wallet_required!
|
49
|
+
account(from).pay(to: to, amount: amount, id: id)
|
50
|
+
end
|
51
|
+
|
52
|
+
def receive(block=nil, into:)
|
53
|
+
wallet_required!
|
54
|
+
account(into).receive(block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def locked?
|
58
|
+
wallet_required!
|
59
|
+
response = rpc(:wallet_locked)
|
60
|
+
!response.empty? && response[:locked] != 0
|
61
|
+
end
|
62
|
+
|
63
|
+
def unlock(password)
|
64
|
+
wallet_required!
|
65
|
+
rpc(:password_enter, password: password)
|
66
|
+
end
|
67
|
+
|
68
|
+
def change_password(password)
|
69
|
+
wallet_required!
|
70
|
+
rpc(:password_change, password: password)
|
71
|
+
end
|
72
|
+
|
73
|
+
def all
|
74
|
+
wallet_required!
|
75
|
+
rpc(:account_list)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def rpc(action, params={})
|
81
|
+
p = @wallet.nil? ? {} : { wallet: @wallet }
|
82
|
+
@rpc.call(action, p.merge(params))
|
83
|
+
end
|
84
|
+
|
85
|
+
def wallet_required!
|
86
|
+
if @wallet.nil?
|
87
|
+
raise ArgumentError.new("Wallet must be present")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class Nanook
|
2
|
+
class WalletAccount
|
3
|
+
|
4
|
+
def initialize(wallet, account, rpc)
|
5
|
+
@wallet = wallet
|
6
|
+
@account = account
|
7
|
+
@rpc = rpc
|
8
|
+
|
9
|
+
# An object to delegate account methods that don't
|
10
|
+
# expect a wallet param in the RPC call, to allow this
|
11
|
+
# class to support all methods that can be called on Nanook::Account
|
12
|
+
@nanook_account_instance = Nanook::Account.new(account, rpc)
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
wallet_required!
|
17
|
+
rpc(:account_create)
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy
|
21
|
+
wallet_required!
|
22
|
+
account_required!
|
23
|
+
rpc(:account_remove)
|
24
|
+
end
|
25
|
+
|
26
|
+
def pay(to:, amount:, id:)
|
27
|
+
wallet_required!
|
28
|
+
account_required!
|
29
|
+
|
30
|
+
raw = Nanook::Util.NANO_to_raw(amount)
|
31
|
+
|
32
|
+
# account is called source, so don't use the normal rpc method
|
33
|
+
p = {
|
34
|
+
wallet: @wallet,
|
35
|
+
source: @account,
|
36
|
+
destination: to,
|
37
|
+
amount: raw,
|
38
|
+
id: id
|
39
|
+
}
|
40
|
+
|
41
|
+
@rpc.call(:send, p)
|
42
|
+
end
|
43
|
+
|
44
|
+
def receive(block=nil)
|
45
|
+
wallet_required!
|
46
|
+
account_required!
|
47
|
+
|
48
|
+
if block.nil?
|
49
|
+
_receive_without_block
|
50
|
+
else
|
51
|
+
_receive_with_block(block)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Any method of Nanook::Account can be called on this class too
|
56
|
+
def method_missing(m, *args, &block)
|
57
|
+
if @nanook_account_instance.respond_to?(m)
|
58
|
+
@nanook_account_instance.send(m, *args, &block)
|
59
|
+
else
|
60
|
+
super(m, *args, &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def _receive_without_block
|
67
|
+
# Discover the first pending block
|
68
|
+
pending_blocks = @rpc.call(:pending, { account: @account, count: 1 })
|
69
|
+
|
70
|
+
if pending_blocks[:blocks].empty?
|
71
|
+
return false
|
72
|
+
end
|
73
|
+
|
74
|
+
# Then call receive_with_block as normal
|
75
|
+
block = pending_blocks[:blocks][0]
|
76
|
+
_receive_with_block(block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def _receive_with_block(block)
|
80
|
+
rpc(:receive, block: block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def rpc(action, params={})
|
84
|
+
p = {}
|
85
|
+
p[:wallet] = @wallet unless @wallet.nil?
|
86
|
+
p[:account] = @account unless @account.nil?
|
87
|
+
|
88
|
+
@rpc.call(action, p.merge(params))
|
89
|
+
end
|
90
|
+
|
91
|
+
def wallet_required!
|
92
|
+
if @wallet.nil?
|
93
|
+
raise ArgumentError.new("Wallet must be present")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def account_required!
|
98
|
+
if @account.nil?
|
99
|
+
raise ArgumentError.new("Account must be present")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Nanook
|
2
|
+
class WorkPeer
|
3
|
+
|
4
|
+
def initialize(rpc)
|
5
|
+
@rpc = rpc
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(address:, port:)
|
9
|
+
rpc(:work_peer_add, address: address, port: port)
|
10
|
+
end
|
11
|
+
|
12
|
+
def clear
|
13
|
+
rpc(:work_peers_clear)
|
14
|
+
end
|
15
|
+
|
16
|
+
def list
|
17
|
+
rpc(:work_peers)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def rpc(action, params={})
|
23
|
+
@rpc.call(action, params)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/nanook.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "nanook/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "nanook"
|
8
|
+
spec.version = Nanook::VERSION
|
9
|
+
spec.authors = ["Luke Duncalfe"]
|
10
|
+
spec.email = ["lduncalfe@eml.cc"]
|
11
|
+
|
12
|
+
spec.summary = "Ruby library for managing a nano currency node, including making and receiving payments, using the nano RPC protocol"
|
13
|
+
spec.description = "Ruby library for managing a nano currency node, including making and receiving payments, using the nano RPC protocol"
|
14
|
+
spec.homepage = "https://github.com/lukes/nanook"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
27
|
+
spec.add_development_dependency "webmock", "~> 3.3"
|
28
|
+
|
29
|
+
spec.add_dependency "symbolized"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nanook
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Luke Duncalfe
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webmock
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: symbolized
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Ruby library for managing a nano currency node, including making and
|
84
|
+
receiving payments, using the nano RPC protocol
|
85
|
+
email:
|
86
|
+
- lduncalfe@eml.cc
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".circleci/config.yml"
|
92
|
+
- ".gitignore"
|
93
|
+
- Gemfile
|
94
|
+
- Gemfile.lock
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- bin/console
|
99
|
+
- bin/setup
|
100
|
+
- img/qr.png
|
101
|
+
- lib/nanook.rb
|
102
|
+
- lib/nanook/account.rb
|
103
|
+
- lib/nanook/block.rb
|
104
|
+
- lib/nanook/error.rb
|
105
|
+
- lib/nanook/key.rb
|
106
|
+
- lib/nanook/node.rb
|
107
|
+
- lib/nanook/rpc.rb
|
108
|
+
- lib/nanook/util.rb
|
109
|
+
- lib/nanook/version.rb
|
110
|
+
- lib/nanook/wallet.rb
|
111
|
+
- lib/nanook/wallet_account.rb
|
112
|
+
- lib/nanook/work_peer.rb
|
113
|
+
- nanook.gemspec
|
114
|
+
homepage: https://github.com/lukes/nanook
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.2.2
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Ruby library for managing a nano currency node, including making and receiving
|
138
|
+
payments, using the nano RPC protocol
|
139
|
+
test_files: []
|