Class: Nanook::Wallet
- Inherits:
-
Object
- Object
- Nanook::Wallet
- Defined in:
- lib/nanook/wallet.rb
Overview
The Nanook::Wallet class lets you manage your nano wallets, as well as some account-specific things like making and receiving payments.
Wallet seeds vs ids
Your wallets each have an id as well as a seed. Both are 32-byte uppercase hex strings that look like this:
000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F
This class uses wallet ids to identify your wallet. A wallet id only exists locally on the nano node that it was created on. The person who knows this id can only perform all read and write actions against the wallet and all accounts inside the wallet from the same nano node that it was created on. This makes wallet ids fairly safe to use as a person needs to know your wallet id as well as have access to run RPC commands against your nano node to be able to control your accounts.
A seed on the other hand can be used to link any wallet to another wallet’s accounts, from anywhere in the nano network. This happens by setting a wallet’s seed to be the same as a previous wallet’s seed. When a wallet has the same seed as another wallet, any accounts created in the second wallet will be the same accounts as those that were created in the previous wallet, and the new wallet’s owner will also gain ownership of the previous wallet’s accounts. Note, that the two wallets will have different ids, but the same seed.
Nanook is based on the Nano RPC, which uses wallet ids and not seeds. The RPC and therefore Nanook cannot tell you what a wallet’s seed is, only its id. Knowing a wallet’s seed is very useful for if you ever want to restore the wallet anywhere else on the nano network besides the node you originally created it on. The nano command line interface (CLI) is the only method for discovering a wallet’s seed. See the –wallet_decrypt_unsafe CLI command.
Initializing
Initialize this class through the convenient #wallet method:
nanook = Nanook.new
wallet = nanook.wallet(wallet_id)
Or compose the longhand way like this:
rpc_conn = Nanook::Rpc.new
wallet = Nanook::Wallet.new(rpc_conn, wallet_id)
Instance Method Summary collapse
-
#account(account = nil) ⇒ Nanook::WalletAccount
Returns the given account in the wallet as a WalletAccount instance to let you start working with it.
-
#accounts ⇒ Array<Nanook::WalletAccount>
Array of WalletAccount instances of accounts in the wallet.
-
#balance(account_break_down: false, unit: Nanook.default_unit) ⇒ Hash{Symbol=>Integer|Float|Hash}
Balance of all accounts in the wallet, optionally breaking the balances down by account.
-
#change_default_representative(representative) ⇒ String
(also: #change_representative)
Sets the default representative for the wallet.
-
#change_password(password) ⇒ Boolean
Changes the password for a wallet.
-
#change_seed(seed) ⇒ Boolean
Changes a wallet’s seed.
-
#contains?(account) ⇒ Boolean
Will return
trueif the account exists in the wallet. -
#create ⇒ Nanook::Wallet
Creates a new wallet.
-
#default_representative ⇒ String
(also: #representative)
The default representative account id for the wallet.
-
#destroy ⇒ Boolean
Destroys the wallet.
-
#export ⇒ Object
Generates a String containing a JSON representation of your wallet.
-
#id ⇒ String
The wallet id.
-
#info(unit: Nanook.default_unit) ⇒ Hash{Symbol=>String|Array<Hash{Symbol=>String|Integer|Float}>}
Information about this wallet and all of its accounts.
-
#initialize(rpc, wallet) ⇒ Wallet
constructor
A new instance of Wallet.
- #inspect ⇒ String
-
#lock ⇒ Boolean
Locks the wallet.
-
#locked? ⇒ Boolean
Returns
trueif the wallet is locked. -
#pay(from:, to:, amount:, unit: Nanook.default_unit, id:) ⇒ String
Makes a payment from an account in your wallet to another account on the nano network.
-
#pending(limit: 1000, detailed: false, unit: Nanook.default_unit) ⇒ Object
Information about pending blocks (payments) that are waiting to be received by accounts in this wallet.
-
#receive(block = nil, into:) ⇒ String, false
Receives a pending payment into an account in the wallet.
-
#restore(seed, accounts: 0) ⇒ Nanook::Wallet
Restores a previously created wallet by its seed.
-
#unlock(password) ⇒ Boolean
Unlocks a previously locked wallet.
Constructor Details
#initialize(rpc, wallet) ⇒ Wallet
Returns a new instance of Wallet.
52 53 54 55 |
# File 'lib/nanook/wallet.rb', line 52 def initialize(rpc, wallet) @rpc = rpc @wallet = wallet end |
Instance Method Details
#account(account = nil) ⇒ Nanook::WalletAccount
Returns the given account in the wallet as a Nanook::WalletAccount instance to let you start working with it.
Call with no account argument if you wish to create a new account in the wallet, like this:
wallet.account.create # => Nanook::WalletAccount
See Nanook::WalletAccount for all the methods you can call on the account object returned.
Examples:
wallet.account("nano_...") # => Nanook::WalletAccount
wallet.account.create # => Nanook::WalletAccount
79 80 81 |
# File 'lib/nanook/wallet.rb', line 79 def account(account=nil) Nanook::WalletAccount.new(@rpc, @wallet, account) end |
#accounts ⇒ Array<Nanook::WalletAccount>
Array of Nanook::WalletAccount instances of accounts in the wallet.
See Nanook::WalletAccount for all the methods you can call on the account objects returned.
Example:
wallet.accounts # => [Nanook::WalletAccount, Nanook::WalletAccount...]
93 94 95 96 97 98 99 |
# File 'lib/nanook/wallet.rb', line 93 def accounts wallet_required! response = rpc(:account_list)[:accounts] Nanook::Util.coerce_empty_string_to_type(response, Array).map do |account| Nanook::WalletAccount.new(@rpc, @wallet, account) end end |
#balance(account_break_down: false, unit: Nanook.default_unit) ⇒ Hash{Symbol=>Integer|Float|Hash}
Balance of all accounts in the wallet, optionally breaking the balances down by account.
Examples:
wallet.balance
Example response:
{
"balance"=>5,
"pending"=>0.001
}
Asking for the balances to be returned in raw instead of NANO.
wallet.balance(unit: :raw)
Example response:
{
"balance"=>5000000000000000000000000000000,
"pending"=>1000000000000000000000000000
}
Asking for totals to be broken down by account:
wallet.balance(account_break_down: true)
Example response:
{
"nano_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000"=>{
"balance"=>2.5,
"pending"=>1
},
"nano_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx"=>{
"balance"=>51.4,
"pending"=>0
},
}
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/nanook/wallet.rb', line 146 def balance(account_break_down: false, unit: Nanook.default_unit) wallet_required! unless Nanook::UNITS.include?(unit) raise ArgumentError.new("Unsupported unit: #{unit}") end if account_break_down return Nanook::Util.coerce_empty_string_to_type(rpc(:wallet_balances)[:balances], Hash).tap do |r| if unit == :nano r.each do |account, balances| r[account][:balance] = Nanook::Util.raw_to_NANO(r[account][:balance]) r[account][:pending] = Nanook::Util.raw_to_NANO(r[account][:pending]) end end end end rpc(:wallet_balance_total).tap do |r| if unit == :nano r[:balance] = Nanook::Util.raw_to_NANO(r[:balance]) r[:pending] = Nanook::Util.raw_to_NANO(r[:pending]) end end end |
#change_default_representative(representative) ⇒ String Also known as: change_representative
Sets the default representative for the wallet. A wallet’s default representative is the representative all new accounts created in the wallet will have. Changing the default representative for a wallet does not change the representatives for existing accounts in the wallet.
Example:
wallet.change_default_representative("nano_...") # => "nano_..."
424 425 426 427 428 429 430 431 432 433 434 |
# File 'lib/nanook/wallet.rb', line 424 def change_default_representative(representative) unless Nanook::Account.new(@rpc, representative).exists? raise ArgumentError.new("Representative account does not exist: #{representative}") end if rpc(:wallet_representative_set, representative: representative)[:set] == 1 representative else raise Nanook::Error.new("Setting the representative failed") end end |
#change_password(password) ⇒ Boolean
Changes the password for a wallet.
Example:
wallet.change_password("new_pass") #=> true
555 556 557 558 |
# File 'lib/nanook/wallet.rb', line 555 def change_password(password) wallet_required! rpc(:password_change, password: password)[:changed] == 1 end |
#change_seed(seed) ⇒ Boolean
Changes a wallet’s seed.
It’s recommended to only change the seed of a wallet that contains no accounts.
Example:
wallet.change_seed("000D1BA...") # => true
183 184 185 186 |
# File 'lib/nanook/wallet.rb', line 183 def change_seed(seed) wallet_required! rpc(:wallet_change_seed, seed: seed).has_key?(:success) end |
#contains?(account) ⇒ Boolean
Will return true if the account exists in the wallet.
Example:
wallet.contains?("nano_...") # => true
237 238 239 240 241 |
# File 'lib/nanook/wallet.rb', line 237 def contains?(account) wallet_required! response = rpc(:wallet_contains, account: account) !response.empty? && response[:exists] == 1 end |
#create ⇒ Nanook::Wallet
Creates a new wallet.
The wallet will be created only on this node. It’s important that if you intend to add funds to accounts in this wallet that you backup the wallet seed in order to restore the wallet in future. The nano command line interface (CLI) is the only method for backing up a wallet’s seed. See the –wallet_decrypt_unsafe CLI command.
Example:
Nanook.new.wallet.create # => Nanook::Wallet
202 203 204 205 |
# File 'lib/nanook/wallet.rb', line 202 def create @wallet = rpc(:wallet_create)[:wallet] self end |
#default_representative ⇒ String Also known as: representative
The default representative account id for the wallet. This is the representative that all new accounts created in this wallet will have.
Changing the default representative for a wallet does not change the representatives for any accounts that have been created.
Example:
wallet.default_representative # => "nano_3pc..."
404 405 406 |
# File 'lib/nanook/wallet.rb', line 404 def default_representative rpc(:wallet_representative)[:representative] end |
#destroy ⇒ Boolean
Destroys the wallet.
Example:
wallet.destroy # => true
214 215 216 217 218 |
# File 'lib/nanook/wallet.rb', line 214 def destroy wallet_required! rpc(:wallet_destroy) true end |
#export ⇒ Object
Generates a String containing a JSON representation of your wallet.
Example:
wallet.export # => "{\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"
225 226 227 228 |
# File 'lib/nanook/wallet.rb', line 225 def export wallet_required! rpc(:wallet_export)[:json] end |
#id ⇒ String
Returns the wallet id.
244 245 246 |
# File 'lib/nanook/wallet.rb', line 244 def id @wallet end |
#info(unit: Nanook.default_unit) ⇒ Hash{Symbol=>String|Array<Hash{Symbol=>String|Integer|Float}>}
Information about this wallet and all of its accounts.
Examples:
wallet.info
Example response:
{
id: "2C3C570EA8898443C0FD04A1C385A3E3A8C985AD792635FCDCEBB30ADF6A0570",
accounts: [
{
id: "nano_11119gbh8hb4hj1duf7fdtfyf5s75okzxdgupgpgm1bj78ex3kgy7frt3s9n"
frontier: "E71AF3E9DD86BBD8B4620EFA63E065B34D358CFC091ACB4E103B965F95783321",
open_block: "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F",
representative_block: "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F",
balance: 1.45,
modified_timestamp: 1511476234,
block_count: 2
},
{ ... }
]
}
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
# File 'lib/nanook/wallet.rb', line 491 def info(unit: Nanook.default_unit) unless Nanook::UNITS.include?(unit) raise ArgumentError.new("Unsupported unit: #{unit}") end wallet_required! accounts = rpc(:wallet_ledger)[:accounts].map do |account_id, payload| payload[:id] = account_id if unit == :nano payload[:balance] = Nanook::Util.raw_to_NANO(payload[:balance]) end payload end { id: @wallet, accounts: accounts }.to_symbolized_hash end |
#inspect ⇒ String
249 250 251 |
# File 'lib/nanook/wallet.rb', line 249 def inspect "#{self.class.name}(id: \"#{id}\", object_id: \"#{"0x00%x" % (object_id << 1)}\")" end |
#lock ⇒ Boolean
Locks the wallet. A locked wallet cannot pocket pending transactions or make payments. See #unlock.
Example:
wallet.lock #=> true
518 519 520 521 522 |
# File 'lib/nanook/wallet.rb', line 518 def lock wallet_required! response = rpc(:wallet_lock) !response.empty? && response[:locked] == 1 end |
#locked? ⇒ Boolean
Returns true if the wallet is locked.
Example:
wallet.locked? #=> false
531 532 533 534 535 |
# File 'lib/nanook/wallet.rb', line 531 def locked? wallet_required! response = rpc(:wallet_locked) !response.empty? && response[:locked] != 0 end |
#pay(from:, to:, amount:, unit: Nanook.default_unit, id:) ⇒ String
Makes a payment from an account in your wallet to another account on the nano network.
Note, there may be a delay in receiving a response due to Proof of Work being done. From the Nano RPC:
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.
Examples:
wallet.pay(from: "nano_...", to: "nano_...", amount: 1.1, id: "myUniqueId123") # => "9AE2311..."
wallet.pay(from: "nano_...", to: "nano_...", amount: 54000000000000, unit: :raw, id: "myUniqueId123") # => "9AE2311..."
276 277 278 279 280 |
# File 'lib/nanook/wallet.rb', line 276 def pay(from:, to:, amount:, unit: Nanook.default_unit, id:) wallet_required! validate_wallet_contains_account!(from) account(from).pay(to: to, amount: amount, unit: unit, id: id) end |
#pending(limit: 1000, detailed: false, unit: Nanook.default_unit) ⇒ Object
Information about pending blocks (payments) that are waiting to be received by accounts in this wallet.
See also the #receive method of this class for how to receive a pending payment.
Examples:
wallet.pending
Example response:
{
:nano_1111111111111111111111111111111111111111111111111117353trpda=>[
"142A538F36833D1CC78B94E11C766F75818F8B940771335C6C1B8AB880C5BB1D",
"718CC2121C3E641059BC1C2CFC45666C99E8AE922F7A807B7D07B62C995D79E2"
],
:nano_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3=>[
"4C1FEEF0BEA7F50BE35489A1233FE002B212DEA554B55B1B470D78BD8F210C74"
]
}
Asking for more information:
wallet.pending(detailed: true)
Example response:
{
:nano_1111111111111111111111111111111111111111111111111117353trpda=>[
{
:amount=>6.0,
:source=>"nano_3dcfozsmekr1tr9skf1oa5wbgmxt81qepfdnt7zicq5x3hk65fg4fqj58mbr",
:block=>:"142A538F36833D1CC78B94E11C766F75818F8B940771335C6C1B8AB880C5BB1D"
},
{
:amount=>12.0,
:source=>"nano_3dcfozsmekr1tr9skf1oa5wbgmxt81qepfdnt7zicq5x3hk65fg4fqj58mbr",
:block=>:"242A538F36833D1CC78B94E11C766F75818F8B940771335C6C1B8AB880C5BB1D"
}
],
:nano_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3=>[
{
:amount=>106.370018,
:source=>"nano_13ezf4od79h1tgj9aiu4djzcmmguendtjfuhwfukhuucboua8cpoihmh8byo",
:block=>:"4C1FEEF0BEA7F50BE35489A1233FE002B212DEA554B55B1B470D78BD8F210C74"
}
]
}
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/nanook/wallet.rb', line 334 def pending(limit:1000, detailed:false, unit:Nanook.default_unit) wallet_required! unless Nanook::UNITS.include?(unit) raise ArgumentError.new("Unsupported unit: #{unit}") end params = { count: limit } params[:source] = true if detailed response = rpc(:wallet_pending, params)[:blocks] response = Nanook::Util.coerce_empty_string_to_type(response, Hash) return response unless detailed # Map the RPC response, which is: # account=>block=>[amount|source] into # account=>[block|amount|source] x = response.map do |account, data| new_data = data.map do |block, amount_and_source| d = amount_and_source.merge(block: block.to_s) if unit == :nano d[:amount] = Nanook::Util.raw_to_NANO(d[:amount]) end d end [account, new_data] end Hash[x].to_symbolized_hash end |
#receive(block = nil, into:) ⇒ String, false
Receives a pending payment into an account in the wallet.
When called with no block argument, the latest pending payment for the account will be received.
Returns a receive block hash id if a receive was successful, or false if there were no pending payments to receive.
You can receive a specific pending block if you know it by passing the block has in as an argument.
Examples:
wallet.receive(into: "xrb...") # => "9AE2311..."
wallet.receive("718CC21...", into: "xrb...") # => "9AE2311..."
387 388 389 390 391 |
# File 'lib/nanook/wallet.rb', line 387 def receive(block=nil, into:) wallet_required! validate_wallet_contains_account!(into) account(into).receive(block) end |
#restore(seed, accounts: 0) ⇒ Nanook::Wallet
Restores a previously created wallet by its seed. A new wallet will be created on your node (with a new wallet id) and will have its seed set to the given seed.
Example:
Nanook.new.wallet.restore(seed) # => Nanook::Wallet
450 451 452 453 454 455 456 457 458 459 460 461 462 |
# File 'lib/nanook/wallet.rb', line 450 def restore(seed, accounts:0) create unless change_seed(seed) raise Nanook::Error.new("Unable to set seed for wallet") end if accounts > 0 account.create(accounts) end self end |
#unlock(password) ⇒ Boolean
Unlocks a previously locked wallet.
Example:
wallet.unlock("new_pass") #=> true
544 545 546 547 |
# File 'lib/nanook/wallet.rb', line 544 def unlock(password) wallet_required! rpc(:password_enter, password: password)[:valid] == 1 end |