nanook 2.3.0 → 3.0.1
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 +5 -5
- data/CHANGELOG.md +140 -0
- data/README.md +154 -91
- data/bin/console +4 -3
- data/lib/nanook.rb +77 -21
- data/lib/nanook/account.rb +238 -168
- data/lib/nanook/block.rb +374 -119
- data/lib/nanook/errors.rb +10 -0
- data/lib/nanook/node.rb +229 -66
- data/lib/nanook/private_key.rb +115 -0
- data/lib/nanook/public_key.rb +55 -0
- data/lib/nanook/rpc.rb +104 -44
- data/lib/nanook/util.rb +68 -19
- data/lib/nanook/version.rb +3 -1
- data/lib/nanook/wallet.rb +369 -167
- data/lib/nanook/wallet_account.rb +151 -91
- data/lib/nanook/work_peer.rb +14 -7
- metadata +28 -27
- data/lib/nanook/error.rb +0 -5
- data/lib/nanook/key.rb +0 -46
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
4
|
+
|
5
|
+
class Nanook
|
6
|
+
# The <tt>Nanook::PublicKey</tt> class lets you manage your node's keys.
|
7
|
+
class PublicKey
|
8
|
+
include Nanook::Util
|
9
|
+
|
10
|
+
def initialize(rpc, key)
|
11
|
+
@rpc = rpc
|
12
|
+
@key = key.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def id
|
16
|
+
@key
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param other [Nanook::PublicKey] public key to compare
|
20
|
+
# @return [Boolean] true if keys are equal
|
21
|
+
def ==(other)
|
22
|
+
other.class == self.class &&
|
23
|
+
other.id == id
|
24
|
+
end
|
25
|
+
alias eql? ==
|
26
|
+
|
27
|
+
# The hash value is used along with #eql? by the Hash class to determine if two objects
|
28
|
+
# reference the same hash key.
|
29
|
+
#
|
30
|
+
# @return [Integer]
|
31
|
+
def hash
|
32
|
+
id.hash
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the account for a public key
|
36
|
+
#
|
37
|
+
# @return [Nanook::Account] account for the public key
|
38
|
+
def account
|
39
|
+
account = rpc(:account_get, _access: :account)
|
40
|
+
as_account(account)
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [String]
|
44
|
+
def to_s
|
45
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
46
|
+
end
|
47
|
+
alias inspect to_s
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def rpc(action, params = {})
|
52
|
+
@rpc.call(action, { key: @key }.merge(params))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/nanook/rpc.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'symbolized'
|
3
5
|
|
4
6
|
class Nanook
|
5
|
-
|
6
7
|
# The <tt>Nanook::Rpc</tt> class is responsible for maintaining the
|
7
8
|
# connection to the RPC server, calling the RPC and parsing its response
|
8
9
|
# into Ruby primitives.
|
@@ -14,23 +15,35 @@ class Nanook
|
|
14
15
|
# nanook = Nanook.new
|
15
16
|
# nanook.rpc(:accounts_create, wallet: wallet_id, count: 2)
|
16
17
|
class Rpc
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
# Default request timeout in seconds
|
18
|
+
# Default RPC server and port to connect to.
|
19
|
+
DEFAULT_URI = 'http://[::1]:7076'
|
20
|
+
# Default request timeout in seconds.
|
21
21
|
DEFAULT_TIMEOUT = 60
|
22
|
+
# Error expected to be returned when the RPC makes a call that requires the
|
23
|
+
# `enable_control` setting to be enabled when it is disabled.
|
24
|
+
RPC_CONTROL_DISABLED_ERROR = 'RPC control is disabled'
|
22
25
|
|
23
|
-
def initialize(uri=DEFAULT_URI, timeout:DEFAULT_TIMEOUT)
|
26
|
+
def initialize(uri = DEFAULT_URI, timeout: DEFAULT_TIMEOUT)
|
24
27
|
@rpc_server = URI(uri)
|
25
28
|
|
26
|
-
unless [
|
27
|
-
raise ArgumentError
|
29
|
+
unless %w[http https].include?(@rpc_server.scheme)
|
30
|
+
raise ArgumentError, "URI must have http or https in it. Was given: #{uri}"
|
28
31
|
end
|
29
32
|
|
30
|
-
@http = Net::HTTP.new(@rpc_server.
|
33
|
+
@http = Net::HTTP.new(@rpc_server.hostname, @rpc_server.port)
|
31
34
|
@http.read_timeout = timeout
|
32
|
-
@request = Net::HTTP::Post.new(@rpc_server.request_uri, {
|
33
|
-
@request.content_type =
|
35
|
+
@request = Net::HTTP::Post.new(@rpc_server.request_uri, { 'user-agent' => "Ruby nanook gem v#{Nanook::VERSION}" })
|
36
|
+
@request.content_type = 'application/json'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Tests the RPC connection. Returns +true+ if connection is successful,
|
40
|
+
# otherwise raises an exception.
|
41
|
+
#
|
42
|
+
# @raise [Errno::ECONNREFUSED] if connection is unsuccessful
|
43
|
+
# @return [Boolean] true if connection is successful
|
44
|
+
def test
|
45
|
+
call(:telemetry)
|
46
|
+
true
|
34
47
|
end
|
35
48
|
|
36
49
|
# Calls the RPC server and returns the response.
|
@@ -39,57 +52,104 @@ class Nanook
|
|
39
52
|
# expects an "action" param to identify what RPC action is being called.
|
40
53
|
# @param params [Hash] all other params to pass to the RPC
|
41
54
|
# @return [Hash] the response from the RPC
|
42
|
-
def call(action, params={})
|
43
|
-
|
44
|
-
|
55
|
+
def call(action, params = {})
|
56
|
+
coerce_to = params.delete(:_coerce)
|
57
|
+
access_as = params.delete(:_access)
|
45
58
|
|
46
|
-
|
59
|
+
raw_hash = make_call(action, params)
|
47
60
|
|
48
|
-
|
61
|
+
check_for_errors!(raw_hash)
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
63
|
+
hash = parse_values(raw_hash)
|
64
|
+
|
65
|
+
hash = hash[access_as] if access_as
|
66
|
+
hash = coerce_empty_string_to_type(hash, coerce_to) if coerce_to
|
67
|
+
|
68
|
+
hash
|
56
69
|
end
|
57
70
|
|
58
71
|
# @return [String]
|
59
|
-
def
|
60
|
-
"#{self.class.name}(host: \"#{@rpc_server}\", timeout: #{@http.read_timeout}
|
72
|
+
def to_s
|
73
|
+
"#{self.class.name}(host: \"#{@rpc_server}\", timeout: #{@http.read_timeout})"
|
61
74
|
end
|
75
|
+
alias inspect to_s
|
62
76
|
|
63
77
|
private
|
64
78
|
|
79
|
+
def make_call(action, params)
|
80
|
+
# Stringify param values
|
81
|
+
params = params.dup.transform_values do |v|
|
82
|
+
next v if v.is_a?(Array)
|
83
|
+
|
84
|
+
v.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
@request.body = { action: action }.merge(params).to_json
|
88
|
+
|
89
|
+
response = @http.request(@request)
|
90
|
+
|
91
|
+
raise Nanook::ConnectionError, "Encountered net/http error #{response.code}: #{response.class.name}" \
|
92
|
+
unless response.is_a?(Net::HTTPSuccess)
|
93
|
+
|
94
|
+
JSON.parse(response.body)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Raises a {Nanook::NodeRpcConfigurationError} or {Nanook::NodeRpcError} if the RPC
|
98
|
+
# response contains an `:error` key.
|
99
|
+
def check_for_errors!(response)
|
100
|
+
# Raise a special error for when `enable_control` should be enabled.
|
101
|
+
if response['error'] == RPC_CONTROL_DISABLED_ERROR
|
102
|
+
raise Nanook::NodeRpcConfigurationError,
|
103
|
+
'RPC must have the `enable_control` setting enabled to perform this action.'
|
104
|
+
end
|
105
|
+
|
106
|
+
# Raise any other error.
|
107
|
+
raise Nanook::NodeRpcError, "An error was returned from the RPC: #{response['error']}" if response.key?('error')
|
108
|
+
end
|
109
|
+
|
65
110
|
# Recursively parses the RPC response, sending values to #parse_value
|
66
|
-
def
|
67
|
-
new_hash =
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
111
|
+
def parse_values(hash)
|
112
|
+
new_hash = hash.map do |k, val|
|
113
|
+
new_val = case val
|
114
|
+
when Array
|
115
|
+
if val[0].is_a?(Hash)
|
116
|
+
val.map { |v| parse_values(v) }
|
117
|
+
else
|
118
|
+
val.map { |v| parse_value(v) }
|
119
|
+
end
|
120
|
+
when Hash
|
121
|
+
parse_values(val)
|
122
|
+
else
|
123
|
+
parse_value(val)
|
124
|
+
end
|
125
|
+
|
126
|
+
[k, new_val]
|
81
127
|
end
|
82
128
|
|
83
129
|
Hash[new_hash.sort].to_symbolized_hash
|
84
130
|
end
|
85
131
|
|
86
132
|
# Converts Strings to primitives
|
87
|
-
def parse_value(
|
88
|
-
return
|
89
|
-
return true if
|
90
|
-
return false if
|
91
|
-
|
133
|
+
def parse_value(value)
|
134
|
+
return value.to_i if value.match(/^\d+\Z/)
|
135
|
+
return true if value == 'true'
|
136
|
+
return false if value == 'false'
|
137
|
+
|
138
|
+
value
|
92
139
|
end
|
93
140
|
|
141
|
+
# Converts an empty String value into an empty version of another type.
|
142
|
+
#
|
143
|
+
# The RPC often returns an empty String as a value to signal
|
144
|
+
# emptiness, rather than consistent types like an empty Array,
|
145
|
+
# or empty Hash.
|
146
|
+
#
|
147
|
+
# @param response the value returned from the RPC server
|
148
|
+
# @param type the type to return an empty of
|
149
|
+
def coerce_empty_string_to_type(response, type)
|
150
|
+
return type.new if response == '' || response.nil?
|
151
|
+
|
152
|
+
response
|
153
|
+
end
|
94
154
|
end
|
95
155
|
end
|
data/lib/nanook/util.rb
CHANGED
@@ -1,44 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'bigdecimal'
|
2
4
|
|
3
5
|
class Nanook
|
4
|
-
|
5
|
-
|
6
|
-
class Util
|
7
|
-
|
6
|
+
# Set of utility methods.
|
7
|
+
module Util
|
8
8
|
# Constant used to convert back and forth between raw and NANO.
|
9
|
-
STEP = BigDecimal
|
9
|
+
STEP = BigDecimal('10')**BigDecimal('30')
|
10
|
+
|
11
|
+
private
|
10
12
|
|
11
13
|
# Converts an amount of NANO to an amount of raw.
|
12
14
|
#
|
13
15
|
# @param nano [Float|Integer] amount in nano
|
14
16
|
# @return [Integer] amount in raw
|
15
|
-
def
|
16
|
-
|
17
|
+
def NANO_to_raw(nano)
|
18
|
+
return if nano.nil?
|
19
|
+
|
20
|
+
(BigDecimal(nano.to_s) * STEP).to_i
|
17
21
|
end
|
18
22
|
|
19
23
|
# Converts an amount of raw to an amount of NANO.
|
20
24
|
#
|
21
25
|
# @param raw [Integer] amount in raw
|
22
26
|
# @return [Float|Integer] amount in NANO
|
23
|
-
def
|
27
|
+
def raw_to_NANO(raw)
|
28
|
+
return if raw.nil?
|
29
|
+
|
24
30
|
(raw.to_f / STEP).to_f
|
25
31
|
end
|
26
32
|
|
27
|
-
#
|
33
|
+
# @return [TrueClass] if unit is valid.
|
34
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid.
|
35
|
+
def validate_unit!(unit)
|
36
|
+
unless Nanook::UNITS.include?(unit.to_sym)
|
37
|
+
raise Nanook::NanoUnitError, "Unit #{unit} must be one of #{Nanook::UNITS}"
|
38
|
+
end
|
39
|
+
|
40
|
+
true
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the +id+ of the object as a short id.
|
44
|
+
# See #shorten_id.
|
28
45
|
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
46
|
+
# @return [String]
|
47
|
+
def short_id
|
48
|
+
shorten_id(id)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns an id string (hash or nano account) truncated with an ellipsis.
|
52
|
+
# The first 7 and last 4 characters are retained for easy identification.
|
32
53
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
54
|
+
# ==== Examples:
|
55
|
+
#
|
56
|
+
# shorten_id('nano_16u1uufyoig8777y6r8iqjtrw8sg8maqrm36zzcm95jmbd9i9aj5i8abr8u5')
|
57
|
+
# # => "16u1uuf...r8u5"
|
58
|
+
#
|
59
|
+
# shorten_id('A170D51B94E00371ACE76E35AC81DC9405D5D04D4CEBC399AEACE07AE05DD293')
|
60
|
+
# # => "A170D51...D293"
|
61
|
+
#
|
62
|
+
# @return [String]
|
63
|
+
def shorten_id(long_id)
|
64
|
+
return unless long_id
|
65
|
+
|
66
|
+
[long_id.sub('nano_', '')[0..6], long_id[-4, 4]].join('...')
|
67
|
+
end
|
39
68
|
|
40
|
-
|
69
|
+
def as_account(account_id)
|
70
|
+
Nanook::Account.new(@rpc, account_id)
|
41
71
|
end
|
42
72
|
|
73
|
+
def as_wallet_account(account_id)
|
74
|
+
Nanook::WalletAccount.new(@rpc, @wallet, account_id)
|
75
|
+
end
|
76
|
+
|
77
|
+
def as_block(block_id)
|
78
|
+
Nanook::Block.new(@rpc, block_id)
|
79
|
+
end
|
80
|
+
|
81
|
+
def as_private_key(key)
|
82
|
+
Nanook::PrivateKey.new(@rpc, key)
|
83
|
+
end
|
84
|
+
|
85
|
+
def as_public_key(key)
|
86
|
+
Nanook::PublicKey.new(@rpc, key)
|
87
|
+
end
|
88
|
+
|
89
|
+
def as_time(time)
|
90
|
+
Time.at(time).utc if time
|
91
|
+
end
|
43
92
|
end
|
44
93
|
end
|
data/lib/nanook/version.rb
CHANGED
data/lib/nanook/wallet.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'util'
|
2
4
|
|
3
|
-
|
4
|
-
#
|
5
|
+
class Nanook
|
6
|
+
# The <tt>Nanook::Wallet</tt> class lets you manage your nano wallets.
|
7
|
+
# Your node will need the <tt>enable_control</tt> setting enabled.
|
5
8
|
#
|
6
9
|
# === Wallet seeds vs ids
|
7
10
|
#
|
@@ -33,8 +36,7 @@ class Nanook
|
|
33
36
|
# want to restore the wallet anywhere else on the nano network besides
|
34
37
|
# the node you originally created it on. The nano command line interface
|
35
38
|
# (CLI) is the only method for discovering a wallet's seed. See the
|
36
|
-
# {https://
|
37
|
-
# --wallet_decrypt_unsafe CLI command}.
|
39
|
+
# {https://docs.nano.org/commands/command-line-interface/#-wallet_decrypt_unsafe-walletwallet-passwordpassword}.
|
38
40
|
#
|
39
41
|
# === Initializing
|
40
42
|
#
|
@@ -48,10 +50,32 @@ class Nanook
|
|
48
50
|
# rpc_conn = Nanook::Rpc.new
|
49
51
|
# wallet = Nanook::Wallet.new(rpc_conn, wallet_id)
|
50
52
|
class Wallet
|
53
|
+
include Nanook::Util
|
51
54
|
|
52
|
-
def initialize(rpc, wallet)
|
55
|
+
def initialize(rpc, wallet = nil)
|
53
56
|
@rpc = rpc
|
54
|
-
@wallet = wallet
|
57
|
+
@wallet = wallet.to_s if wallet
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [String] the wallet id
|
61
|
+
def id
|
62
|
+
@wallet
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param other [Nanook::Wallet] wallet to compare
|
66
|
+
# @return [Boolean] true if wallets are equal
|
67
|
+
def ==(other)
|
68
|
+
other.class == self.class &&
|
69
|
+
other.id == id
|
70
|
+
end
|
71
|
+
alias eql? ==
|
72
|
+
|
73
|
+
# The hash value is used along with #eql? by the Hash class to determine if two objects
|
74
|
+
# reference the same hash key.
|
75
|
+
#
|
76
|
+
# @return [Integer]
|
77
|
+
def hash
|
78
|
+
id.hash
|
55
79
|
end
|
56
80
|
|
57
81
|
# Returns the given account in the wallet as a {Nanook::WalletAccount} instance
|
@@ -67,17 +91,18 @@ class Nanook
|
|
67
91
|
#
|
68
92
|
# ==== Examples:
|
69
93
|
#
|
70
|
-
# wallet.account("
|
94
|
+
# wallet.account("nano_...") # => Nanook::WalletAccount
|
71
95
|
# wallet.account.create # => Nanook::WalletAccount
|
72
96
|
#
|
73
|
-
# @param [String]
|
97
|
+
# @param account [String] optional String of an account (starting with
|
74
98
|
# <tt>"xrb..."</tt>) to start working with. Must be an account within
|
75
99
|
# the wallet. When no account is given, the instance returned only
|
76
100
|
# allows you to call +create+ on it, to create a new account.
|
77
|
-
# @raise [ArgumentError] if the wallet does
|
101
|
+
# @raise [ArgumentError] if the wallet does not contain the account
|
78
102
|
# @return [Nanook::WalletAccount]
|
79
|
-
def account(account=nil)
|
80
|
-
|
103
|
+
def account(account = nil)
|
104
|
+
check_wallet_required!
|
105
|
+
as_wallet_account(account)
|
81
106
|
end
|
82
107
|
|
83
108
|
# Array of {Nanook::WalletAccount} instances of accounts in the wallet.
|
@@ -91,13 +116,33 @@ class Nanook
|
|
91
116
|
#
|
92
117
|
# @return [Array<Nanook::WalletAccount>] all accounts in the wallet
|
93
118
|
def accounts
|
94
|
-
|
95
|
-
|
96
|
-
Nanook::Util.coerce_empty_string_to_type(response, Array).map do |account|
|
97
|
-
Nanook::WalletAccount.new(@rpc, @wallet, account)
|
119
|
+
rpc(:account_list, _access: :accounts, _coerce: Array).map do |account|
|
120
|
+
as_wallet_account(account)
|
98
121
|
end
|
99
122
|
end
|
100
123
|
|
124
|
+
# Move accounts from another {Nanook::Wallet} on the node to this {Nanook::Wallet}.
|
125
|
+
#
|
126
|
+
# ==== Example:
|
127
|
+
#
|
128
|
+
# wallet.move_accounts("0023200...", ["nano_3e3j5...", "nano_5f2a1..."]) # => true
|
129
|
+
#
|
130
|
+
# @return [Boolean] true when the move was successful
|
131
|
+
def move_accounts(wallet, accounts)
|
132
|
+
rpc(:account_move, source: wallet, accounts: accounts, _access: :moved) == 1
|
133
|
+
end
|
134
|
+
|
135
|
+
# Remove an {Nanook::Account} from this {Nanook::Wallet}.
|
136
|
+
#
|
137
|
+
# ==== Example:
|
138
|
+
#
|
139
|
+
# wallet.remove_account("nano_3e3j5...") # => true
|
140
|
+
#
|
141
|
+
# @return [Boolean] true when the remove was successful
|
142
|
+
def remove_account(account)
|
143
|
+
rpc(:account_remove, account: account, _access: :removed) == 1
|
144
|
+
end
|
145
|
+
|
101
146
|
# Balance of all accounts in the wallet, optionally breaking the balances down by account.
|
102
147
|
#
|
103
148
|
# ==== Examples:
|
@@ -128,58 +173,60 @@ class Nanook
|
|
128
173
|
# Example response:
|
129
174
|
#
|
130
175
|
# {
|
131
|
-
# "
|
176
|
+
# "nano_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000"=>{
|
132
177
|
# "balance"=>2.5,
|
133
178
|
# "pending"=>1
|
134
179
|
# },
|
135
|
-
# "
|
180
|
+
# "nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx"=>{
|
136
181
|
# "balance"=>51.4,
|
137
182
|
# "pending"=>0
|
138
183
|
# },
|
139
184
|
# }
|
140
185
|
#
|
141
|
-
# @param [Boolean]
|
186
|
+
# @param account_break_down [Boolean] (default is +false+). When +true+
|
142
187
|
# the response will contain balances per account.
|
143
188
|
# @param unit (see Nanook::Account#balance)
|
144
189
|
#
|
145
190
|
# @return [Hash{Symbol=>Integer|Float|Hash}]
|
191
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
146
192
|
def balance(account_break_down: false, unit: Nanook.default_unit)
|
147
|
-
|
148
|
-
|
149
|
-
unless Nanook::UNITS.include?(unit)
|
150
|
-
raise ArgumentError.new("Unsupported unit: #{unit}")
|
151
|
-
end
|
193
|
+
validate_unit!(unit)
|
152
194
|
|
153
195
|
if account_break_down
|
154
|
-
return
|
196
|
+
return rpc(:wallet_balances, _access: :balances, _coerce: Hash).tap do |r|
|
155
197
|
if unit == :nano
|
156
|
-
r.each do |account,
|
157
|
-
r[account][:balance] =
|
158
|
-
r[account][:pending] =
|
198
|
+
r.each do |account, _balances|
|
199
|
+
r[account][:balance] = raw_to_NANO(r[account][:balance])
|
200
|
+
r[account][:pending] = raw_to_NANO(r[account][:pending])
|
159
201
|
end
|
160
202
|
end
|
161
203
|
end
|
162
204
|
end
|
163
205
|
|
164
|
-
rpc(:
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
206
|
+
response = rpc(:wallet_info, _coerce: Hash).slice(:balance, :pending)
|
207
|
+
return response unless unit == :nano
|
208
|
+
|
209
|
+
{
|
210
|
+
balance: raw_to_NANO(response[:balance]),
|
211
|
+
pending: raw_to_NANO(response[:pending])
|
212
|
+
}
|
170
213
|
end
|
171
214
|
|
172
215
|
# Changes a wallet's seed.
|
173
216
|
#
|
217
|
+
# It's recommended to only change the seed of a wallet that contains
|
218
|
+
# no accounts. This will clear all deterministic accounts in the wallet.
|
219
|
+
# To restore accounts after changing the seed, see Nanook::WalletAccount#create.
|
220
|
+
#
|
174
221
|
# ==== Example:
|
175
222
|
#
|
176
223
|
# wallet.change_seed("000D1BA...") # => true
|
224
|
+
# wallet.account.create(5) # Restores first 5 accounts for wallet with new seed
|
177
225
|
#
|
178
226
|
# @param seed [String] the seed to change to.
|
179
227
|
# @return [Boolean] indicating whether the change was successful.
|
180
228
|
def change_seed(seed)
|
181
|
-
|
182
|
-
rpc(:wallet_change_seed, seed: seed).has_key?(:success)
|
229
|
+
rpc(:wallet_change_seed, seed: seed).key?(:success)
|
183
230
|
end
|
184
231
|
|
185
232
|
# Creates a new wallet.
|
@@ -197,7 +244,8 @@ class Nanook
|
|
197
244
|
#
|
198
245
|
# @return [Nanook::Wallet]
|
199
246
|
def create
|
200
|
-
|
247
|
+
skip_wallet_required!
|
248
|
+
@wallet = rpc(:wallet_create, _access: :wallet)
|
201
249
|
self
|
202
250
|
end
|
203
251
|
|
@@ -209,49 +257,57 @@ class Nanook
|
|
209
257
|
#
|
210
258
|
# @return [Boolean] indicating success of the action
|
211
259
|
def destroy
|
212
|
-
|
213
|
-
rpc(:wallet_destroy)
|
214
|
-
true
|
260
|
+
rpc(:wallet_destroy, _access: :destroyed) == 1
|
215
261
|
end
|
216
262
|
|
217
263
|
# Generates a String containing a JSON representation of your wallet.
|
218
264
|
#
|
219
265
|
# ==== Example:
|
220
266
|
#
|
221
|
-
# wallet.export
|
267
|
+
# wallet.export
|
268
|
+
# # => "{\n \"0000000000000000000000000000000000000000000000000000000000000000\": \"0000000000000000000000000000000000000000000000000000000000000003\",\n \"0000000000000000000000000000000000000000000000000000000000000001\": \"C3A176FC3B90113277BFC91F55128FC9A1F1B6166A73E7446927CFFCA4C2C9D9\",\n \"0000000000000000000000000000000000000000000000000000000000000002\": \"3E58EC805B99C52B4715598BD332C234A1FBF1780577137E18F53B9B7F85F04B\",\n \"0000000000000000000000000000000000000000000000000000000000000003\": \"5FF8021122F3DEE0E4EC4241D35A3F41DEF63CCF6ADA66AF235DE857718498CD\",\n \"0000000000000000000000000000000000000000000000000000000000000004\": \"A30E0A32ED41C8607AA9212843392E853FCBCB4E7CB194E35C94F07F91DE59EF\",\n \"0000000000000000000000000000000000000000000000000000000000000005\": \"E707002E84143AA5F030A6DB8DD0C0480F2FFA75AB1FFD657EC22B5AA8E395D5\",\n \"0000000000000000000000000000000000000000000000000000000000000006\": \"0000000000000000000000000000000000000000000000000000000000000001\",\n \"8646C0423160DEAEAA64034F9C6858F7A5C8A329E73E825A5B16814F6CCAFFE3\": \"0000000000000000000000000000000000000000000000000000000100000000\"\n}\n"
|
269
|
+
#
|
270
|
+
# @return [String]
|
222
271
|
def export
|
223
|
-
|
224
|
-
|
272
|
+
rpc(:wallet_export, _access: :json)
|
273
|
+
end
|
274
|
+
|
275
|
+
# Returns true if wallet exists on the node.
|
276
|
+
#
|
277
|
+
# ==== Example:
|
278
|
+
#
|
279
|
+
# wallet.exists? # => true
|
280
|
+
#
|
281
|
+
# @return [Boolean] true if wallet exists on the node
|
282
|
+
def exists?
|
283
|
+
export
|
284
|
+
true
|
285
|
+
rescue Nanook::NodeRpcError
|
286
|
+
false
|
225
287
|
end
|
226
288
|
|
227
289
|
# Will return +true+ if the account exists in the wallet.
|
228
290
|
#
|
229
291
|
# ==== Example:
|
230
|
-
# wallet.contains?("
|
292
|
+
# wallet.contains?("nano_...") # => true
|
231
293
|
#
|
232
|
-
# @param account [String] id (will start with <tt>"
|
294
|
+
# @param account [String] id (will start with <tt>"nano_..."</tt>)
|
233
295
|
# @return [Boolean] indicating if the wallet contains the given account
|
234
296
|
def contains?(account)
|
235
|
-
|
236
|
-
response = rpc(:wallet_contains, account: account)
|
237
|
-
!response.empty? && response[:exists] == 1
|
238
|
-
end
|
239
|
-
|
240
|
-
# @return [String] the wallet id
|
241
|
-
def id
|
242
|
-
@wallet
|
297
|
+
rpc(:wallet_contains, account: account, _access: :exists) == 1
|
243
298
|
end
|
244
299
|
|
245
300
|
# @return [String]
|
246
|
-
def
|
247
|
-
"#{self.class.name}(id: \"#{
|
301
|
+
def to_s
|
302
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
248
303
|
end
|
304
|
+
alias inspect to_s
|
249
305
|
|
250
306
|
# Makes a payment from an account in your wallet to another account
|
251
307
|
# on the nano network.
|
252
308
|
#
|
253
309
|
# Note, there may be a delay in receiving a response due to Proof of
|
254
|
-
# Work being done. From the {Nano RPC}[https://
|
310
|
+
# Work being done. From the {Nano RPC}[https://docs.nano.org/commands/rpc-protocol/#send]:
|
255
311
|
#
|
256
312
|
# <i>Proof of Work is precomputed for one transaction in the
|
257
313
|
# background. If it has been a while since your last transaction it
|
@@ -260,8 +316,9 @@ class Nanook
|
|
260
316
|
#
|
261
317
|
# ==== Examples:
|
262
318
|
#
|
263
|
-
# wallet.pay(from: "
|
264
|
-
# wallet.pay(from: "
|
319
|
+
# wallet.pay(from: "nano_...", to: "nano_...", amount: 1.1, id: "myUniqueId123") # => "9AE2311..."
|
320
|
+
# wallet.pay(from: "nano_...", to: "nano_...", amount: 54000000000000, unit: :raw, id: "myUniqueId123")
|
321
|
+
# # => "9AE2311..."
|
265
322
|
#
|
266
323
|
# @param from [String] account id of an account in your wallet
|
267
324
|
# @param to (see Nanook::WalletAccount#pay)
|
@@ -270,8 +327,7 @@ class Nanook
|
|
270
327
|
# @params id (see Nanook::WalletAccount#pay)
|
271
328
|
# @return (see Nanook::WalletAccount#pay)
|
272
329
|
# @raise [Nanook::Error] if unsuccessful
|
273
|
-
def pay(from:, to:, amount:, unit: Nanook.default_unit
|
274
|
-
wallet_required!
|
330
|
+
def pay(from:, to:, amount:, id:, unit: Nanook.default_unit)
|
275
331
|
validate_wallet_contains_account!(from)
|
276
332
|
account(from).pay(to: to, amount: amount, unit: unit, id: id)
|
277
333
|
end
|
@@ -292,12 +348,12 @@ class Nanook
|
|
292
348
|
# Example response:
|
293
349
|
#
|
294
350
|
# {
|
295
|
-
#
|
296
|
-
#
|
297
|
-
# "
|
351
|
+
# Nanook::Account=>[
|
352
|
+
# Nanook::Block,
|
353
|
+
# Nanook::Block"
|
298
354
|
# ],
|
299
|
-
#
|
300
|
-
#
|
355
|
+
# Nanook::Account=>[
|
356
|
+
# Nanook::Block
|
301
357
|
# ]
|
302
358
|
# }
|
303
359
|
#
|
@@ -308,57 +364,69 @@ class Nanook
|
|
308
364
|
# Example response:
|
309
365
|
#
|
310
366
|
# {
|
311
|
-
#
|
367
|
+
# Nanook::Account=>[
|
312
368
|
# {
|
313
369
|
# :amount=>6.0,
|
314
|
-
# :source=>
|
315
|
-
# :block
|
370
|
+
# :source=>Nanook::Account,
|
371
|
+
# :block=>Nanook::Block
|
316
372
|
# },
|
317
373
|
# {
|
318
374
|
# :amount=>12.0,
|
319
|
-
# :source=>
|
320
|
-
# :block
|
375
|
+
# :source=>Nanook::Account,
|
376
|
+
# :block=>Nanook::Block
|
321
377
|
# }
|
322
378
|
# ],
|
323
|
-
#
|
379
|
+
# Nanook::Account=>[
|
324
380
|
# {
|
325
381
|
# :amount=>106.370018,
|
326
|
-
# :source=>
|
327
|
-
# :block
|
382
|
+
# :source=>Nanook::Account,
|
383
|
+
# :block=>Nanook::Block
|
328
384
|
# }
|
329
385
|
# ]
|
330
386
|
# }
|
331
|
-
|
332
|
-
|
387
|
+
#
|
388
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
389
|
+
def pending(limit: 1000, detailed: false, unit: Nanook.default_unit)
|
390
|
+
validate_unit!(unit)
|
333
391
|
|
334
|
-
|
335
|
-
|
336
|
-
|
392
|
+
params = {
|
393
|
+
count: limit,
|
394
|
+
_access: :blocks,
|
395
|
+
_coerce: Hash
|
396
|
+
}
|
337
397
|
|
338
|
-
params = { count: limit }
|
339
398
|
params[:source] = true if detailed
|
340
399
|
|
341
|
-
response = rpc(:wallet_pending, params)
|
342
|
-
|
400
|
+
response = rpc(:wallet_pending, params)
|
401
|
+
|
402
|
+
unless detailed
|
403
|
+
|
404
|
+
x = response.map do |account, block_ids|
|
405
|
+
blocks = block_ids.map { |block_id| as_block(block_id) }
|
406
|
+
[as_account(account), blocks]
|
407
|
+
end
|
343
408
|
|
344
|
-
|
409
|
+
return Hash[x]
|
410
|
+
end
|
345
411
|
|
346
412
|
# Map the RPC response, which is:
|
347
413
|
# account=>block=>[amount|source] into
|
348
414
|
# account=>[block|amount|source]
|
349
415
|
x = response.map do |account, data|
|
350
416
|
new_data = data.map do |block, amount_and_source|
|
351
|
-
d =
|
352
|
-
|
353
|
-
|
354
|
-
|
417
|
+
d = {
|
418
|
+
block: as_block(block),
|
419
|
+
source: as_account(amount_and_source[:source]),
|
420
|
+
amount: amount_and_source[:amount]
|
421
|
+
}
|
422
|
+
d[:amount] = raw_to_NANO(d[:amount]) if unit == :nano
|
355
423
|
d
|
356
424
|
end
|
357
425
|
|
358
|
-
[account, new_data]
|
426
|
+
[as_account(account), new_data]
|
359
427
|
end
|
360
428
|
|
361
|
-
Hash[x]
|
429
|
+
Hash[x]
|
362
430
|
end
|
363
431
|
|
364
432
|
# Receives a pending payment into an account in the wallet.
|
@@ -366,7 +434,7 @@ class Nanook
|
|
366
434
|
# When called with no +block+ argument, the latest pending payment
|
367
435
|
# for the account will be received.
|
368
436
|
#
|
369
|
-
# Returns a <i>receive</i> block
|
437
|
+
# Returns a <i>receive</i> block if a receive was successful,
|
370
438
|
# or +false+ if there were no pending payments to receive.
|
371
439
|
#
|
372
440
|
# You can receive a specific pending block if you know it by
|
@@ -374,19 +442,33 @@ class Nanook
|
|
374
442
|
#
|
375
443
|
# ==== Examples:
|
376
444
|
#
|
377
|
-
# wallet.receive(into: "xrb...") # =>
|
378
|
-
# wallet.receive("718CC21...", into: "xrb...") # =>
|
445
|
+
# wallet.receive(into: "xrb...") # => Nanook::Block
|
446
|
+
# wallet.receive("718CC21...", into: "xrb...") # => Nanook::Block
|
379
447
|
#
|
380
448
|
# @param block (see Nanook::WalletAccount#receive)
|
381
449
|
# @param into [String] account id of account in your wallet to receive the
|
382
450
|
# payment into
|
383
451
|
# @return (see Nanook::WalletAccount#receive)
|
384
|
-
def receive(block=nil, into:)
|
385
|
-
wallet_required!
|
452
|
+
def receive(block = nil, into:)
|
386
453
|
validate_wallet_contains_account!(into)
|
387
454
|
account(into).receive(block)
|
388
455
|
end
|
389
456
|
|
457
|
+
# Rebroadcast blocks for accounts from wallet starting at frontier down to count to the network.
|
458
|
+
#
|
459
|
+
# ==== Examples:
|
460
|
+
#
|
461
|
+
# wallet.republish_blocks # => [Nanook::Block, ...]
|
462
|
+
# wallet.republish_blocks(limit: 10) # => [Nanook::Block, ...
|
463
|
+
#
|
464
|
+
# @param limit [Integer] limit of blocks to publish. Default is 1000.
|
465
|
+
# @return [Array<Nanook::Block>] republished blocks
|
466
|
+
def republish_blocks(limit: 1000)
|
467
|
+
rpc(:wallet_republish, count: limit, _access: :blocks, _coerce: Array).map do |block|
|
468
|
+
as_block(block)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
390
472
|
# The default representative account id for the wallet. This is the
|
391
473
|
# representative that all new accounts created in this wallet will have.
|
392
474
|
#
|
@@ -395,13 +477,14 @@ class Nanook
|
|
395
477
|
#
|
396
478
|
# ==== Example:
|
397
479
|
#
|
398
|
-
# wallet.default_representative # => "
|
480
|
+
# wallet.default_representative # => "nano_3pc..."
|
399
481
|
#
|
400
|
-
# @return [
|
482
|
+
# @return [Nanook::Account] Representative account. Can be nil.
|
401
483
|
def default_representative
|
402
|
-
rpc(:wallet_representative
|
484
|
+
representative = rpc(:wallet_representative, _access: :representative)
|
485
|
+
as_account(representative) if representative
|
403
486
|
end
|
404
|
-
|
487
|
+
alias representative default_representative
|
405
488
|
|
406
489
|
# Sets the default representative for the wallet. A wallet's default
|
407
490
|
# representative is the representative all new accounts created in
|
@@ -411,25 +494,23 @@ class Nanook
|
|
411
494
|
#
|
412
495
|
# ==== Example:
|
413
496
|
#
|
414
|
-
# wallet.change_default_representative("
|
497
|
+
# wallet.change_default_representative("nano_...") # => "nano_..."
|
415
498
|
#
|
416
|
-
# @param [String]
|
499
|
+
# @param representative [String] id of the representative account
|
417
500
|
# to set as this account's representative
|
418
|
-
# @return [
|
419
|
-
# @raise [ArgumentError] if the representative account does not exist
|
501
|
+
# @return [Nanook::Account] the representative account
|
420
502
|
# @raise [Nanook::Error] if setting the representative fails
|
421
503
|
def change_default_representative(representative)
|
422
|
-
unless
|
423
|
-
raise
|
504
|
+
unless as_account(representative).exists?
|
505
|
+
raise Nanook::Error, "Representative account does not exist: #{representative}"
|
424
506
|
end
|
425
507
|
|
426
|
-
|
427
|
-
representative
|
428
|
-
|
429
|
-
|
430
|
-
end
|
508
|
+
raise Nanook::Error, 'Setting the representative failed' \
|
509
|
+
unless rpc(:wallet_representative_set, representative: representative, _access: :set) == 1
|
510
|
+
|
511
|
+
as_account(representative)
|
431
512
|
end
|
432
|
-
|
513
|
+
alias change_representative change_default_representative
|
433
514
|
|
434
515
|
# Restores a previously created wallet by its seed.
|
435
516
|
# A new wallet will be created on your node (with a new wallet id)
|
@@ -444,21 +525,68 @@ class Nanook
|
|
444
525
|
#
|
445
526
|
# @return [Nanook::Wallet] a new wallet
|
446
527
|
# @raise [Nanook::Error] if unsuccessful
|
447
|
-
def restore(seed, accounts:0)
|
528
|
+
def restore(seed, accounts: 0)
|
529
|
+
skip_wallet_required!
|
530
|
+
|
448
531
|
create
|
449
532
|
|
450
|
-
unless change_seed(seed)
|
451
|
-
raise Nanook::Error.new("Unable to set seed for wallet")
|
452
|
-
end
|
533
|
+
raise Nanook::Error, 'Unable to set seed for wallet' unless change_seed(seed)
|
453
534
|
|
454
|
-
if accounts
|
455
|
-
account.create(accounts)
|
456
|
-
end
|
535
|
+
account.create(accounts) if accounts.positive?
|
457
536
|
|
458
537
|
self
|
459
538
|
end
|
460
539
|
|
461
|
-
# Information about this wallet
|
540
|
+
# Information ledger information about this wallet's accounts.
|
541
|
+
#
|
542
|
+
# This call may return results that include unconfirmed blocks, so it should not be
|
543
|
+
# used in any processes or integrations requiring only details from blocks confirmed
|
544
|
+
# by the network.
|
545
|
+
#
|
546
|
+
# ==== Examples:
|
547
|
+
#
|
548
|
+
# wallet.ledger
|
549
|
+
#
|
550
|
+
# Example response:
|
551
|
+
#
|
552
|
+
# {
|
553
|
+
# Nanook::Account => {
|
554
|
+
# frontier: "E71AF3E9DD86BBD8B4620EFA63E065B34D358CFC091ACB4E103B965F95783321",
|
555
|
+
# open_block: "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F",
|
556
|
+
# representative_block: "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F",
|
557
|
+
# balance: 1.45,
|
558
|
+
# modified_timestamp: 1511476234,
|
559
|
+
# block_count: 2
|
560
|
+
# },
|
561
|
+
# Nanook::Account => { ... }
|
562
|
+
# }
|
563
|
+
#
|
564
|
+
# @param unit (see Nanook::Account#balance)
|
565
|
+
# @return [Hash{Nanook::Account=>Hash{Symbol=>Nanook::Block|Integer|Float|Time}}] ledger.
|
566
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
567
|
+
def ledger(unit: Nanook.default_unit)
|
568
|
+
validate_unit!(unit)
|
569
|
+
|
570
|
+
response = rpc(:wallet_ledger, _access: :accounts, _coerce: Hash)
|
571
|
+
|
572
|
+
accounts = response.map do |account_id, data|
|
573
|
+
data[:frontier] = as_block(data[:frontier]) if data[:frontier]
|
574
|
+
data[:open_block] = as_block(data[:open_block]) if data[:open_block]
|
575
|
+
data[:representative_block] = as_block(data[:representative_block]) if data[:representative_block]
|
576
|
+
data[:balance] = raw_to_NANO(data[:balance]) if unit == :nano && data[:balance]
|
577
|
+
data[:last_modified_at] = as_time(data.delete(:modified_timestamp))
|
578
|
+
|
579
|
+
[as_account(account_id), data]
|
580
|
+
end
|
581
|
+
|
582
|
+
Hash[accounts]
|
583
|
+
end
|
584
|
+
|
585
|
+
# Information about this wallet.
|
586
|
+
#
|
587
|
+
# This call may return results that include unconfirmed blocks, so it should not be
|
588
|
+
# used in any processes or integrations requiring only details from blocks confirmed
|
589
|
+
# by the network.
|
462
590
|
#
|
463
591
|
# ==== Examples:
|
464
592
|
#
|
@@ -467,42 +595,79 @@ class Nanook
|
|
467
595
|
# Example response:
|
468
596
|
#
|
469
597
|
# {
|
470
|
-
#
|
471
|
-
#
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
# balance: 1.45,
|
478
|
-
# modified_timestamp: 1511476234,
|
479
|
-
# block_count: 2
|
480
|
-
# },
|
481
|
-
# { ... }
|
482
|
-
# ]
|
483
|
-
# }
|
598
|
+
# balance: 1.0,
|
599
|
+
# pending: 2.3
|
600
|
+
# accounts_count: 3,
|
601
|
+
# adhoc_count: 1,
|
602
|
+
# deterministic_count: 2,
|
603
|
+
# deterministic_index: 2
|
604
|
+
# }
|
484
605
|
#
|
485
|
-
# @param unit (see #balance)
|
486
|
-
# @return [Hash{Symbol=>
|
487
|
-
#
|
606
|
+
# @param unit (see Nanook::Account#balance)
|
607
|
+
# @return [Hash{Symbol=>Integer|Float}] information about the wallet.
|
608
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
488
609
|
def info(unit: Nanook.default_unit)
|
489
|
-
|
490
|
-
|
610
|
+
validate_unit!(unit)
|
611
|
+
|
612
|
+
response = rpc(:wallet_info, _coerce: Hash)
|
613
|
+
|
614
|
+
if unit == :nano
|
615
|
+
response[:balance] = raw_to_NANO(response[:balance])
|
616
|
+
response[:pending] = raw_to_NANO(response[:pending])
|
491
617
|
end
|
492
618
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
619
|
+
response
|
620
|
+
end
|
621
|
+
|
622
|
+
# Reports send/receive information for accounts in wallet. Change blocks are skipped,
|
623
|
+
# open blocks will appear as receive. Response will start with most recent blocks
|
624
|
+
# according to local ledger.
|
625
|
+
#
|
626
|
+
# ==== Example:
|
627
|
+
#
|
628
|
+
# wallet.history
|
629
|
+
#
|
630
|
+
# Example response:
|
631
|
+
#
|
632
|
+
# [
|
633
|
+
# {
|
634
|
+
# "type": "send",
|
635
|
+
# "account": Nanook::Account,
|
636
|
+
# "amount": 3.2,
|
637
|
+
# "block_account": Nanook::Account,
|
638
|
+
# "hash": Nanook::Block,
|
639
|
+
# "local_timestamp": Time
|
640
|
+
# },
|
641
|
+
# {
|
642
|
+
# ...
|
643
|
+
# }
|
644
|
+
# ]
|
645
|
+
#
|
646
|
+
# @param unit (see #balance)
|
647
|
+
# @return [Array<Hash{Symbol=>String|Nanook::Account|Nanook::WalletAccount|Nanook::Block|Integer|Float|Time}>]
|
648
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
649
|
+
def history(unit: Nanook.default_unit)
|
650
|
+
validate_unit!(unit)
|
651
|
+
|
652
|
+
rpc(:wallet_history, _access: :history, _coerce: Array).map do |h|
|
653
|
+
h[:account] = account(h[:account])
|
654
|
+
h[:block_account] = as_account(h[:block_account])
|
655
|
+
h[:amount] = raw_to_NANO(h[:amount]) if unit == :nano
|
656
|
+
h[:block] = as_block(h.delete(:hash))
|
657
|
+
h[:local_timestamp] = as_time(h[:local_timestamp])
|
658
|
+
h
|
500
659
|
end
|
660
|
+
end
|
501
661
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
662
|
+
# Locks the wallet. A locked wallet cannot pocket pending transactions or make payments. See {#unlock}.
|
663
|
+
#
|
664
|
+
# ==== Example:
|
665
|
+
#
|
666
|
+
# wallet.lock #=> true
|
667
|
+
#
|
668
|
+
# @return [Boolean] indicates if the wallet was successfully locked
|
669
|
+
def lock
|
670
|
+
rpc(:wallet_lock, _access: :locked) == 1
|
506
671
|
end
|
507
672
|
|
508
673
|
# Returns +true+ if the wallet is locked.
|
@@ -513,9 +678,7 @@ class Nanook
|
|
513
678
|
#
|
514
679
|
# @return [Boolean] indicates if the wallet is locked
|
515
680
|
def locked?
|
516
|
-
|
517
|
-
response = rpc(:wallet_locked)
|
518
|
-
!response.empty? && response[:locked] != 0
|
681
|
+
rpc(:wallet_locked, _access: :locked) == 1
|
519
682
|
end
|
520
683
|
|
521
684
|
# Unlocks a previously locked wallet.
|
@@ -525,9 +688,8 @@ class Nanook
|
|
525
688
|
# wallet.unlock("new_pass") #=> true
|
526
689
|
#
|
527
690
|
# @return [Boolean] indicates if the unlocking action was successful
|
528
|
-
def unlock(password)
|
529
|
-
|
530
|
-
rpc(:password_enter, password: password)[:valid] == 1
|
691
|
+
def unlock(password = nil)
|
692
|
+
rpc(:password_enter, password: password, _access: :valid) == 1
|
531
693
|
end
|
532
694
|
|
533
695
|
# Changes the password for a wallet.
|
@@ -537,33 +699,73 @@ class Nanook
|
|
537
699
|
# wallet.change_password("new_pass") #=> true
|
538
700
|
# @return [Boolean] indicates if the action was successful
|
539
701
|
def change_password(password)
|
540
|
-
|
541
|
-
|
702
|
+
rpc(:password_change, password: password, _access: :changed) == 1
|
703
|
+
end
|
704
|
+
|
705
|
+
# Tells the node to look for pending blocks for any account in the wallet.
|
706
|
+
#
|
707
|
+
# ==== Example:
|
708
|
+
#
|
709
|
+
# wallet.search_pending #=> true
|
710
|
+
# @return [Boolean] indicates if the action was successful
|
711
|
+
def search_pending
|
712
|
+
rpc(:search_pending, _access: :started) == 1
|
713
|
+
end
|
714
|
+
|
715
|
+
# Returns a list of pairs of {Nanook::WalletAccount} and work for wallet.
|
716
|
+
#
|
717
|
+
# ==== Example:
|
718
|
+
#
|
719
|
+
# wallet.work
|
720
|
+
#
|
721
|
+
# ==== Example response:
|
722
|
+
#
|
723
|
+
# {
|
724
|
+
# Nanook::WalletAccount: "432e5cf728c90f4f",
|
725
|
+
# Nanook::WalletAccount: "4efec5f63fc902cf"
|
726
|
+
# }
|
727
|
+
# @return [Boolean] indicates if the action was successful
|
728
|
+
def work
|
729
|
+
hash = rpc(:wallet_work_get, _access: :works, _coerce: Hash).map do |account_id, work|
|
730
|
+
[as_wallet_account(account_id), work]
|
731
|
+
end
|
732
|
+
|
733
|
+
Hash[hash]
|
542
734
|
end
|
543
735
|
|
544
736
|
private
|
545
737
|
|
546
|
-
def rpc(action, params={})
|
547
|
-
|
548
|
-
|
738
|
+
def rpc(action, params = {})
|
739
|
+
check_wallet_required!
|
740
|
+
|
741
|
+
p = { wallet: @wallet }.compact
|
742
|
+
@rpc.call(action, p.merge(params)).tap { reset_skip_wallet_required! }
|
549
743
|
end
|
550
744
|
|
551
|
-
def
|
552
|
-
|
553
|
-
|
554
|
-
|
745
|
+
def skip_wallet_required!
|
746
|
+
@skip_wallet_required_check = true
|
747
|
+
end
|
748
|
+
|
749
|
+
def reset_skip_wallet_required!
|
750
|
+
@skip_wallet_required_check = false
|
751
|
+
end
|
752
|
+
|
753
|
+
def check_wallet_required!
|
754
|
+
return if @wallet || @skip_wallet_required_check
|
755
|
+
|
756
|
+
raise ArgumentError, 'Wallet must be present'
|
555
757
|
end
|
556
758
|
|
557
759
|
def validate_wallet_contains_account!(account)
|
558
760
|
@known_valid_accounts ||= []
|
559
761
|
return if @known_valid_accounts.include?(account)
|
560
762
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
raise ArgumentError.new("Account does not exist in wallet. Account: #{account}, wallet: #{@wallet}")
|
763
|
+
unless contains?(account)
|
764
|
+
raise ArgumentError,
|
765
|
+
"Account does not exist in wallet. Account: #{account}, wallet: #{@wallet}"
|
565
766
|
end
|
566
|
-
end
|
567
767
|
|
768
|
+
@known_valid_accounts << account
|
769
|
+
end
|
568
770
|
end
|
569
771
|
end
|