nanook 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/nanook.svg)](https://badge.fury.io/rb/nanook)
|
6
|
+
[![CircleCI](https://circleci.com/gh/lukes/nanook/tree/master.svg?style=shield)](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
|
+
![alt xrb_3c3ek3k8135f6e8qtfy8eruk9q3yzmpebes7btzncccdest8ymzhjmnr196j](https://raw.githubusercontent.com/lukes/nanook/master/img/qr.png)
|
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: []
|