The current Gem trying to make as easy as possible working with Banano currency. More information about the Banano currency networking can be found on the Banano Currency Wiki pages. The current library is still work in progress, but the basic functionallity is already implemented:
- Good part of the RPC protocol for working with Banano nodes
- Wallet, Account operations - send and receive payments etc.
- Conversion between units - RAW to Banano and Banano to RAW
Some parts of the library are heavily influenced by the great nanook Ruby library for working with the similar NANO currency.
Everybody is welcome to contrubute to the project. Have fun and use Ruby and Banano.
Add this line to your application's Gemfile:
gem 'banano'
And then execute:
bundle install
Or install it yourself as:
gem install banano
The code is divided on following the parts:
Banano::Protocol
- including all other parts. Can be used also for some syntax sugar (to avoid sending node parameter to constructors)Banano::Client
- very thin wrapper around Faraday HTTP Client for easy JSON-based communicationsBanano::Node
- Banano Node abstraction - mostly encapsulate JSON communicationsBanano::Wallet
- wallets holding for Banano accounts on the current nodeBanano::Account
- uniq 'ban_...' addresses used for currency tokens exchangeBanano::WalletAccount
- link betweenAccount
andWallet
- check if account exists in the wallet etc.Banano::Key
- account key managementBanano::Block
- low level work with individual blocksBanano::WorkPeer
- do work on peersBanano::Unit
- conversion between RAW and Banano units
Usually everything starts here. By default the library will work with locally running Banano node. If it is impossible to be done, you can use the Public bananode RPC API. Example below is for that case:
BETA_URL = 'https://api-beta.banano.cc'
@banano = Banano::Protocol.new(uri: BETA_URL)
# From here it is easy to create other object, without sending URI to them
wallet = @banano.wallet('WALLET15263636...')
account = @banano.account('ban_1...')
Not used directly, better use Banano::Node
instead
client = Banano::Client.new(uri: BETA_URL)
client.rpc_call(action: :version)
Most of the information about the running node is encapsulated here. The other parts using mostly the Banano::Node.rpc()
method, not the low level client one:
Banano::Node.account_count # number of node accounts
Banano::Node.block_count # check here if there are still non-syncronized blocks
Banano::Node.peers # other nodes connected to that one
# accounts with voting power
Banano::Node.representatives
Banano::Node.representatives_online
# Is your node synced already
Banano::Node.synchronizing_blocks
Banano::Node.sync_progress
Wallets are like a bags of accounts. Accounts can be only local, created on the current node. They will not be visible for other nodes.
wallet = Banano::Wallet.create # create new wallet
wallet.restore(seed: 'XVVREGNN...') # restore some wallet and its accounts
wallet.accounts # current wellet accounts
wallet.contains?('ban_1...') # check if the account exists in the current wallet
wallet.export # export wallet to JSON
wallet.destroy # remove the wallet
# Accounts with voting power
wallet.default_representative
wallet.change_default_representative('ban_1...')
# Security
wallet.change_password('SomePassword') # protect your wallet
wallet.lock # no more payments
wallet.locked?
wallet.unlock('SomePassword') # resume receiving payments
# Payments
block_id = wallet.pay(from: 'ban_1...', to: 'ban_3...', amount: '1.23', raw: false, id: 'x123')
wallet.pending(limit: 10, detailed: true) # waiting payments (does not work well unless enable_control = true)
wallet.receive(into: 'ban_1', block: block_id) # receive the pending banano into some wallet account
wallet.balance # check how many banano the whole wallet have, RAW units
wallet.balance(raw: false) # wallet balance in Banano units
wallet.balance(account_break_down: true) # banano per acount, RAW units
Account are holding units with unique address, where the banano tokens are accumulated. They can be local for the current node and not accessable for other nodes.
account = Banano::Account(node: @banano.node, address: 'ban1_...') # create new account on that node
account.exists? # check if account exists
# some account attributes
account.last_modified_at
account.public_key
account.representative
account.balance # in RAW units
account.balance(raw: false) # in banano units
# Payments
account.pending(limit: 100, detailed: true) # detailed information about the pending payments
account.history(limit: 10) # the latest payments - send and receive
Because accounts and wallets so closly connected, some linkage object is very helpful.
wallet = @banano.wallet('XBHHNN...')
# create wallet <-> accounts connection
wallet_acc = Banano::WalletAccount(node: @banano.node, wallet: wallet.id)
wallet_acc.create # create new account in the wallet
wallet_acc.create(3) # create additional 3 accounts inside the same wallet
# Working with specific account
account = @banano.account('ban_1')
wallet_other_acc = Banano::WalletAccount(node: @banano.node, wallet: wallet.id, account: account.id)
block_id = wallet_other_acc.pay(to: 'ban_1...', amount: 10, raw: false, id: 'x1234') # send some banano
wallet_other_acc.receive(block_id) # receive some banano
Most of the information is identicat with the NANO currency docs.
key_builder = @banano.key # create new key (still unpopulated, cannot be used)
key_builder.generate # generate private, public key and account address
{:private=>"43E6B...",
:public=>"7EBC0C...",
:account=>"ban_1zow3..."}
SEED = 'ABF56EBB...' # Random seed
key_builder.generate(seed: SEED, index: 0) # will always generate SAME pair of keys and address
key_builder.generate(seed: SEED, index: 1)
new_builder = @banano.key(saved_private_key) # generate keys from saved private key
new_builder.expand # return private, public key and account address
Delegate block validating work to some network peers:
work = Banano::WorkPeer(@banano.node)
work.add(address: '::ffff:1.2.3.4', port: '7071') # add peer to the work flow
work.list # list of working peers
work.clear # remove all peers
Blocks, also known as transactions are the building items of the banano network. Every block have uniq ID, which can be used for processing the block
block = Banano::Block(node: @banano.node, block: 'F1B7EDB1...')
block.account # account associated with the block
block.successors(limit: 10)
block.chain(limit: 10) # also 'block.ancestors' - blocks chain, leading to the current one
block.history # more detailed chain history
block.info # information about the block
block.confirm # block confirmation from the online representatives
work = block.generate_work(use_peers: true) # start some work
block.is_valid_work?(work) # check if the work done is valid
block.cancel_work # stop generating work for block
block.pending? # is the block in pending state. not work very well...
block.publish('send') # dependes what kind of block is this: 'send', 'receive' etc.
Using Ruby bigdecimal library for all operations:
Banano::Unit.ban_to_raw(1) # -> BigDecimal('100000000000000000000000000000')
Banano::Unit.raw_to_ban('1') # -> BigDecimal('0.00000000000000000000000000001')
The library also is checking some currency related limits, for example total supply limit: 3402823669.20938463463374607431768211455
banano max
After checking out the repo, run bin/setup
to install dependencies. You can also run bin/console
for an interactive prompt that will allow you to experiment.
Clone the gem source code and start experimenting:
git clone https://github.com/zh/rbanano
rspec
is used for testing. To run all tests execute:
bundle exec rspec spec
Still a lot of tests needed. For now Banano::Unit
and Banano:Util
are ready. The other parts tests will be added soon.
Bug reports and pull requests are welcome on GitHub at https://github.com/zh/rbanano.
The gem is available as open source under the terms of the MIT License.