nanook 2.5.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -0
- data/README.md +135 -85
- data/bin/console +4 -3
- data/lib/nanook.rb +76 -20
- data/lib/nanook/account.rb +232 -164
- data/lib/nanook/block.rb +343 -150
- data/lib/nanook/errors.rb +10 -0
- data/lib/nanook/node.rb +164 -132
- 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 +67 -18
- data/lib/nanook/version.rb +3 -1
- data/lib/nanook/wallet.rb +348 -161
- data/lib/nanook/wallet_account.rb +148 -88
- data/lib/nanook/work_peer.rb +14 -7
- metadata +20 -18
- 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,18 +1,22 @@
|
|
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
|
17
|
+
def NANO_to_raw(nano)
|
18
|
+
return if nano.nil?
|
19
|
+
|
16
20
|
(BigDecimal(nano.to_s) * STEP).to_i
|
17
21
|
end
|
18
22
|
|
@@ -20,25 +24,70 @@ class Nanook
|
|
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
|
#
|
@@ -47,10 +50,32 @@ class Nanook
|
|
47
50
|
# rpc_conn = Nanook::Rpc.new
|
48
51
|
# wallet = Nanook::Wallet.new(rpc_conn, wallet_id)
|
49
52
|
class Wallet
|
53
|
+
include Nanook::Util
|
50
54
|
|
51
|
-
def initialize(rpc, wallet)
|
55
|
+
def initialize(rpc, wallet = nil)
|
52
56
|
@rpc = rpc
|
53
|
-
@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
|
54
79
|
end
|
55
80
|
|
56
81
|
# Returns the given account in the wallet as a {Nanook::WalletAccount} instance
|
@@ -69,14 +94,15 @@ class Nanook
|
|
69
94
|
# wallet.account("nano_...") # => Nanook::WalletAccount
|
70
95
|
# wallet.account.create # => Nanook::WalletAccount
|
71
96
|
#
|
72
|
-
# @param [String]
|
97
|
+
# @param account [String] optional String of an account (starting with
|
73
98
|
# <tt>"xrb..."</tt>) to start working with. Must be an account within
|
74
99
|
# the wallet. When no account is given, the instance returned only
|
75
100
|
# allows you to call +create+ on it, to create a new account.
|
76
|
-
# @raise [ArgumentError] if the wallet does
|
101
|
+
# @raise [ArgumentError] if the wallet does not contain the account
|
77
102
|
# @return [Nanook::WalletAccount]
|
78
|
-
def account(account=nil)
|
79
|
-
|
103
|
+
def account(account = nil)
|
104
|
+
check_wallet_required!
|
105
|
+
as_wallet_account(account)
|
80
106
|
end
|
81
107
|
|
82
108
|
# Array of {Nanook::WalletAccount} instances of accounts in the wallet.
|
@@ -90,13 +116,33 @@ class Nanook
|
|
90
116
|
#
|
91
117
|
# @return [Array<Nanook::WalletAccount>] all accounts in the wallet
|
92
118
|
def accounts
|
93
|
-
|
94
|
-
|
95
|
-
Nanook::Util.coerce_empty_string_to_type(response, Array).map do |account|
|
96
|
-
Nanook::WalletAccount.new(@rpc, @wallet, account)
|
119
|
+
rpc(:account_list, _access: :accounts, _coerce: Array).map do |account|
|
120
|
+
as_wallet_account(account)
|
97
121
|
end
|
98
122
|
end
|
99
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
|
+
|
100
146
|
# Balance of all accounts in the wallet, optionally breaking the balances down by account.
|
101
147
|
#
|
102
148
|
# ==== Examples:
|
@@ -137,51 +183,50 @@ class Nanook
|
|
137
183
|
# },
|
138
184
|
# }
|
139
185
|
#
|
140
|
-
# @param [Boolean]
|
186
|
+
# @param account_break_down [Boolean] (default is +false+). When +true+
|
141
187
|
# the response will contain balances per account.
|
142
188
|
# @param unit (see Nanook::Account#balance)
|
143
189
|
#
|
144
190
|
# @return [Hash{Symbol=>Integer|Float|Hash}]
|
191
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
145
192
|
def balance(account_break_down: false, unit: Nanook.default_unit)
|
146
|
-
|
147
|
-
|
148
|
-
unless Nanook::UNITS.include?(unit)
|
149
|
-
raise ArgumentError.new("Unsupported unit: #{unit}")
|
150
|
-
end
|
193
|
+
validate_unit!(unit)
|
151
194
|
|
152
195
|
if account_break_down
|
153
|
-
return
|
196
|
+
return rpc(:wallet_balances, _access: :balances, _coerce: Hash).tap do |r|
|
154
197
|
if unit == :nano
|
155
|
-
r.each do |account,
|
156
|
-
r[account][:balance] =
|
157
|
-
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])
|
158
201
|
end
|
159
202
|
end
|
160
203
|
end
|
161
204
|
end
|
162
205
|
|
163
|
-
rpc(:
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
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
|
+
}
|
169
213
|
end
|
170
214
|
|
171
215
|
# Changes a wallet's seed.
|
172
216
|
#
|
173
217
|
# It's recommended to only change the seed of a wallet that contains
|
174
|
-
# no accounts.
|
218
|
+
# no accounts. This will clear all deterministic accounts in the wallet.
|
219
|
+
# To restore accounts after changing the seed, see Nanook::WalletAccount#create.
|
175
220
|
#
|
176
221
|
# ==== Example:
|
177
222
|
#
|
178
223
|
# wallet.change_seed("000D1BA...") # => true
|
224
|
+
# wallet.account.create(5) # Restores first 5 accounts for wallet with new seed
|
179
225
|
#
|
180
226
|
# @param seed [String] the seed to change to.
|
181
227
|
# @return [Boolean] indicating whether the change was successful.
|
182
228
|
def change_seed(seed)
|
183
|
-
|
184
|
-
rpc(:wallet_change_seed, seed: seed).has_key?(:success)
|
229
|
+
rpc(:wallet_change_seed, seed: seed).key?(:success)
|
185
230
|
end
|
186
231
|
|
187
232
|
# Creates a new wallet.
|
@@ -199,7 +244,8 @@ class Nanook
|
|
199
244
|
#
|
200
245
|
# @return [Nanook::Wallet]
|
201
246
|
def create
|
202
|
-
|
247
|
+
skip_wallet_required!
|
248
|
+
@wallet = rpc(:wallet_create, _access: :wallet)
|
203
249
|
self
|
204
250
|
end
|
205
251
|
|
@@ -211,19 +257,33 @@ class Nanook
|
|
211
257
|
#
|
212
258
|
# @return [Boolean] indicating success of the action
|
213
259
|
def destroy
|
214
|
-
|
215
|
-
rpc(:wallet_destroy)
|
216
|
-
true
|
260
|
+
rpc(:wallet_destroy, _access: :destroyed) == 1
|
217
261
|
end
|
218
262
|
|
219
263
|
# Generates a String containing a JSON representation of your wallet.
|
220
264
|
#
|
221
265
|
# ==== Example:
|
222
266
|
#
|
223
|
-
# 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]
|
224
271
|
def export
|
225
|
-
|
226
|
-
|
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
|
227
287
|
end
|
228
288
|
|
229
289
|
# Will return +true+ if the account exists in the wallet.
|
@@ -234,20 +294,14 @@ class Nanook
|
|
234
294
|
# @param account [String] id (will start with <tt>"nano_..."</tt>)
|
235
295
|
# @return [Boolean] indicating if the wallet contains the given account
|
236
296
|
def contains?(account)
|
237
|
-
|
238
|
-
response = rpc(:wallet_contains, account: account)
|
239
|
-
!response.empty? && response[:exists] == 1
|
240
|
-
end
|
241
|
-
|
242
|
-
# @return [String] the wallet id
|
243
|
-
def id
|
244
|
-
@wallet
|
297
|
+
rpc(:wallet_contains, account: account, _access: :exists) == 1
|
245
298
|
end
|
246
299
|
|
247
300
|
# @return [String]
|
248
|
-
def
|
249
|
-
"#{self.class.name}(id: \"#{
|
301
|
+
def to_s
|
302
|
+
"#{self.class.name}(id: \"#{short_id}\")"
|
250
303
|
end
|
304
|
+
alias inspect to_s
|
251
305
|
|
252
306
|
# Makes a payment from an account in your wallet to another account
|
253
307
|
# on the nano network.
|
@@ -263,7 +317,8 @@ class Nanook
|
|
263
317
|
# ==== Examples:
|
264
318
|
#
|
265
319
|
# wallet.pay(from: "nano_...", to: "nano_...", amount: 1.1, id: "myUniqueId123") # => "9AE2311..."
|
266
|
-
# wallet.pay(from: "nano_...", to: "nano_...", amount: 54000000000000, unit: :raw, id: "myUniqueId123")
|
320
|
+
# wallet.pay(from: "nano_...", to: "nano_...", amount: 54000000000000, unit: :raw, id: "myUniqueId123")
|
321
|
+
# # => "9AE2311..."
|
267
322
|
#
|
268
323
|
# @param from [String] account id of an account in your wallet
|
269
324
|
# @param to (see Nanook::WalletAccount#pay)
|
@@ -272,8 +327,7 @@ class Nanook
|
|
272
327
|
# @params id (see Nanook::WalletAccount#pay)
|
273
328
|
# @return (see Nanook::WalletAccount#pay)
|
274
329
|
# @raise [Nanook::Error] if unsuccessful
|
275
|
-
def pay(from:, to:, amount:, unit: Nanook.default_unit
|
276
|
-
wallet_required!
|
330
|
+
def pay(from:, to:, amount:, id:, unit: Nanook.default_unit)
|
277
331
|
validate_wallet_contains_account!(from)
|
278
332
|
account(from).pay(to: to, amount: amount, unit: unit, id: id)
|
279
333
|
end
|
@@ -294,12 +348,12 @@ class Nanook
|
|
294
348
|
# Example response:
|
295
349
|
#
|
296
350
|
# {
|
297
|
-
#
|
298
|
-
#
|
299
|
-
# "
|
351
|
+
# Nanook::Account=>[
|
352
|
+
# Nanook::Block,
|
353
|
+
# Nanook::Block"
|
300
354
|
# ],
|
301
|
-
#
|
302
|
-
#
|
355
|
+
# Nanook::Account=>[
|
356
|
+
# Nanook::Block
|
303
357
|
# ]
|
304
358
|
# }
|
305
359
|
#
|
@@ -310,57 +364,69 @@ class Nanook
|
|
310
364
|
# Example response:
|
311
365
|
#
|
312
366
|
# {
|
313
|
-
#
|
367
|
+
# Nanook::Account=>[
|
314
368
|
# {
|
315
369
|
# :amount=>6.0,
|
316
|
-
# :source=>
|
317
|
-
# :block
|
370
|
+
# :source=>Nanook::Account,
|
371
|
+
# :block=>Nanook::Block
|
318
372
|
# },
|
319
373
|
# {
|
320
374
|
# :amount=>12.0,
|
321
|
-
# :source=>
|
322
|
-
# :block
|
375
|
+
# :source=>Nanook::Account,
|
376
|
+
# :block=>Nanook::Block
|
323
377
|
# }
|
324
378
|
# ],
|
325
|
-
#
|
379
|
+
# Nanook::Account=>[
|
326
380
|
# {
|
327
381
|
# :amount=>106.370018,
|
328
|
-
# :source=>
|
329
|
-
# :block
|
382
|
+
# :source=>Nanook::Account,
|
383
|
+
# :block=>Nanook::Block
|
330
384
|
# }
|
331
385
|
# ]
|
332
386
|
# }
|
333
|
-
|
334
|
-
|
387
|
+
#
|
388
|
+
# @raise [Nanook::NanoUnitError] if `unit` is invalid
|
389
|
+
def pending(limit: 1000, detailed: false, unit: Nanook.default_unit)
|
390
|
+
validate_unit!(unit)
|
335
391
|
|
336
|
-
|
337
|
-
|
338
|
-
|
392
|
+
params = {
|
393
|
+
count: limit,
|
394
|
+
_access: :blocks,
|
395
|
+
_coerce: Hash
|
396
|
+
}
|
339
397
|
|
340
|
-
params = { count: limit }
|
341
398
|
params[:source] = true if detailed
|
342
399
|
|
343
|
-
response = rpc(:wallet_pending, params)
|
344
|
-
response = Nanook::Util.coerce_empty_string_to_type(response, Hash)
|
400
|
+
response = rpc(:wallet_pending, params)
|
345
401
|
|
346
|
-
|
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
|
408
|
+
|
409
|
+
return Hash[x]
|
410
|
+
end
|
347
411
|
|
348
412
|
# Map the RPC response, which is:
|
349
413
|
# account=>block=>[amount|source] into
|
350
414
|
# account=>[block|amount|source]
|
351
415
|
x = response.map do |account, data|
|
352
416
|
new_data = data.map do |block, amount_and_source|
|
353
|
-
d =
|
354
|
-
|
355
|
-
|
356
|
-
|
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
|
357
423
|
d
|
358
424
|
end
|
359
425
|
|
360
|
-
[account, new_data]
|
426
|
+
[as_account(account), new_data]
|
361
427
|
end
|
362
428
|
|
363
|
-
Hash[x]
|
429
|
+
Hash[x]
|
364
430
|
end
|
365
431
|
|
366
432
|
# Receives a pending payment into an account in the wallet.
|
@@ -368,7 +434,7 @@ class Nanook
|
|
368
434
|
# When called with no +block+ argument, the latest pending payment
|
369
435
|
# for the account will be received.
|
370
436
|
#
|
371
|
-
# Returns a <i>receive</i> block
|
437
|
+
# Returns a <i>receive</i> block if a receive was successful,
|
372
438
|
# or +false+ if there were no pending payments to receive.
|
373
439
|
#
|
374
440
|
# You can receive a specific pending block if you know it by
|
@@ -376,19 +442,33 @@ class Nanook
|
|
376
442
|
#
|
377
443
|
# ==== Examples:
|
378
444
|
#
|
379
|
-
# wallet.receive(into: "xrb...") # =>
|
380
|
-
# wallet.receive("718CC21...", into: "xrb...") # =>
|
445
|
+
# wallet.receive(into: "xrb...") # => Nanook::Block
|
446
|
+
# wallet.receive("718CC21...", into: "xrb...") # => Nanook::Block
|
381
447
|
#
|
382
448
|
# @param block (see Nanook::WalletAccount#receive)
|
383
449
|
# @param into [String] account id of account in your wallet to receive the
|
384
450
|
# payment into
|
385
451
|
# @return (see Nanook::WalletAccount#receive)
|
386
|
-
def receive(block=nil, into:)
|
387
|
-
wallet_required!
|
452
|
+
def receive(block = nil, into:)
|
388
453
|
validate_wallet_contains_account!(into)
|
389
454
|
account(into).receive(block)
|
390
455
|
end
|
391
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
|
+
|
392
472
|
# The default representative account id for the wallet. This is the
|
393
473
|
# representative that all new accounts created in this wallet will have.
|
394
474
|
#
|
@@ -399,11 +479,12 @@ class Nanook
|
|
399
479
|
#
|
400
480
|
# wallet.default_representative # => "nano_3pc..."
|
401
481
|
#
|
402
|
-
# @return [
|
482
|
+
# @return [Nanook::Account] Representative account. Can be nil.
|
403
483
|
def default_representative
|
404
|
-
rpc(:wallet_representative
|
484
|
+
representative = rpc(:wallet_representative, _access: :representative)
|
485
|
+
as_account(representative) if representative
|
405
486
|
end
|
406
|
-
|
487
|
+
alias representative default_representative
|
407
488
|
|
408
489
|
# Sets the default representative for the wallet. A wallet's default
|
409
490
|
# representative is the representative all new accounts created in
|
@@ -415,23 +496,21 @@ class Nanook
|
|
415
496
|
#
|
416
497
|
# wallet.change_default_representative("nano_...") # => "nano_..."
|
417
498
|
#
|
418
|
-
# @param [String]
|
499
|
+
# @param representative [String] id of the representative account
|
419
500
|
# to set as this account's representative
|
420
|
-
# @return [
|
421
|
-
# @raise [ArgumentError] if the representative account does not exist
|
501
|
+
# @return [Nanook::Account] the representative account
|
422
502
|
# @raise [Nanook::Error] if setting the representative fails
|
423
503
|
def change_default_representative(representative)
|
424
|
-
unless
|
425
|
-
raise
|
504
|
+
unless as_account(representative).exists?
|
505
|
+
raise Nanook::Error, "Representative account does not exist: #{representative}"
|
426
506
|
end
|
427
507
|
|
428
|
-
|
429
|
-
representative
|
430
|
-
|
431
|
-
|
432
|
-
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)
|
433
512
|
end
|
434
|
-
|
513
|
+
alias change_representative change_default_representative
|
435
514
|
|
436
515
|
# Restores a previously created wallet by its seed.
|
437
516
|
# A new wallet will be created on your node (with a new wallet id)
|
@@ -446,21 +525,68 @@ class Nanook
|
|
446
525
|
#
|
447
526
|
# @return [Nanook::Wallet] a new wallet
|
448
527
|
# @raise [Nanook::Error] if unsuccessful
|
449
|
-
def restore(seed, accounts:0)
|
528
|
+
def restore(seed, accounts: 0)
|
529
|
+
skip_wallet_required!
|
530
|
+
|
450
531
|
create
|
451
532
|
|
452
|
-
unless change_seed(seed)
|
453
|
-
raise Nanook::Error.new("Unable to set seed for wallet")
|
454
|
-
end
|
533
|
+
raise Nanook::Error, 'Unable to set seed for wallet' unless change_seed(seed)
|
455
534
|
|
456
|
-
if accounts
|
457
|
-
account.create(accounts)
|
458
|
-
end
|
535
|
+
account.create(accounts) if accounts.positive?
|
459
536
|
|
460
537
|
self
|
461
538
|
end
|
462
539
|
|
463
|
-
# 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.
|
464
590
|
#
|
465
591
|
# ==== Examples:
|
466
592
|
#
|
@@ -469,42 +595,68 @@ class Nanook
|
|
469
595
|
# Example response:
|
470
596
|
#
|
471
597
|
# {
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
475
|
-
#
|
476
|
-
#
|
477
|
-
#
|
478
|
-
#
|
479
|
-
# balance: 1.45,
|
480
|
-
# modified_timestamp: 1511476234,
|
481
|
-
# block_count: 2
|
482
|
-
# },
|
483
|
-
# { ... }
|
484
|
-
# ]
|
485
|
-
# }
|
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
|
+
# }
|
486
605
|
#
|
487
|
-
# @param unit (see #balance)
|
488
|
-
# @return [Hash{Symbol=>
|
489
|
-
#
|
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
|
490
609
|
def info(unit: Nanook.default_unit)
|
491
|
-
|
492
|
-
raise ArgumentError.new("Unsupported unit: #{unit}")
|
493
|
-
end
|
610
|
+
validate_unit!(unit)
|
494
611
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
end
|
501
|
-
payload
|
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])
|
502
617
|
end
|
503
618
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
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
|
659
|
+
end
|
508
660
|
end
|
509
661
|
|
510
662
|
# Locks the wallet. A locked wallet cannot pocket pending transactions or make payments. See {#unlock}.
|
@@ -515,9 +667,7 @@ class Nanook
|
|
515
667
|
#
|
516
668
|
# @return [Boolean] indicates if the wallet was successfully locked
|
517
669
|
def lock
|
518
|
-
|
519
|
-
response = rpc(:wallet_lock)
|
520
|
-
!response.empty? && response[:locked] == 1
|
670
|
+
rpc(:wallet_lock, _access: :locked) == 1
|
521
671
|
end
|
522
672
|
|
523
673
|
# Returns +true+ if the wallet is locked.
|
@@ -528,9 +678,7 @@ class Nanook
|
|
528
678
|
#
|
529
679
|
# @return [Boolean] indicates if the wallet is locked
|
530
680
|
def locked?
|
531
|
-
|
532
|
-
response = rpc(:wallet_locked)
|
533
|
-
!response.empty? && response[:locked] != 0
|
681
|
+
rpc(:wallet_locked, _access: :locked) == 1
|
534
682
|
end
|
535
683
|
|
536
684
|
# Unlocks a previously locked wallet.
|
@@ -540,9 +688,8 @@ class Nanook
|
|
540
688
|
# wallet.unlock("new_pass") #=> true
|
541
689
|
#
|
542
690
|
# @return [Boolean] indicates if the unlocking action was successful
|
543
|
-
def unlock(password)
|
544
|
-
|
545
|
-
rpc(:password_enter, password: password)[:valid] == 1
|
691
|
+
def unlock(password = nil)
|
692
|
+
rpc(:password_enter, password: password, _access: :valid) == 1
|
546
693
|
end
|
547
694
|
|
548
695
|
# Changes the password for a wallet.
|
@@ -552,33 +699,73 @@ class Nanook
|
|
552
699
|
# wallet.change_password("new_pass") #=> true
|
553
700
|
# @return [Boolean] indicates if the action was successful
|
554
701
|
def change_password(password)
|
555
|
-
|
556
|
-
|
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]
|
557
734
|
end
|
558
735
|
|
559
736
|
private
|
560
737
|
|
561
|
-
def rpc(action, params={})
|
562
|
-
|
563
|
-
|
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! }
|
564
743
|
end
|
565
744
|
|
566
|
-
def
|
567
|
-
|
568
|
-
|
569
|
-
|
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'
|
570
757
|
end
|
571
758
|
|
572
759
|
def validate_wallet_contains_account!(account)
|
573
760
|
@known_valid_accounts ||= []
|
574
761
|
return if @known_valid_accounts.include?(account)
|
575
762
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
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}"
|
580
766
|
end
|
581
|
-
end
|
582
767
|
|
768
|
+
@known_valid_accounts << account
|
769
|
+
end
|
583
770
|
end
|
584
771
|
end
|