Hive Developers logo

Hive Developer Portal

Power Down

Perform a power down on all or part of an account’s VESTS using either Hive Signer or client-side signing.

Full, runnable src of Power Down can be downloaded as part of: tutorials/python (or download just this tutorial: devportal-master-tutorials-python-25_power_down.zip).

In this tutorial we will explain and show you how to power down some or all of your available HIVE Power on the Hive blockchain using the beem library.

Intro

The beem library has a built-in function to transmit transactions to the blockchain. We are using the withdraw_vesting method found within the account instance. When you power down, the converted VESTS (HIVE Power) will not be available as HIVE immediately. It is converted in 13 equal parts and transferred into your HIVE wallet weekly, the first portion only being available a week after the power down was initiated. Before we do the conversion, we check the current balance of the account to check how much HIVE Power is available. This is not strictly necessary as the process will automatically abort with the corresponding error, but it does give some insight into the process as a whole. We use the Account module to check for this.

Also see:

Steps

  1. App setup - Library install and import. Connection to testnet
  2. User information and Hive node - Input user information and connection to Hive node
  3. Check balance - Check current vesting balance of user account
  4. Conversion amount and commit - Input of VESTS amount to convert and commit to blockchain

1. App setup

In this tutorial we use 2 packages:

We import the libraries and connect to the testnet.

import pprint
from pick import pick
import getpass
from beem import Hive
from beem.account import Account
from beem.amount import Amount

Because this tutorial alters the blockchain we connect to the testnet so we don’t create spam on the production server.

2. User information and Hive node

We require the private active key of the user in order for the conversion to be committed to the blockchain. This is why we have to specify this alongside the testnet node. The values are supplied via the terminal/console before we initialize the beem class.

# capture user information
account = input('Enter username: ')
wif_active_key = getpass.getpass('Enter private ACTIVE key: ')

# node_url = 'https://testnet.openhive.network' # Public Testnet
node_url = 'http://127.0.0.1:8090' # Local Testnet

# connect node and private active key
client = Hive(node_url, keys=[wif_active_key])

3. Check balance

In order to give the user enough information to make the conversion we check the current balance of the account using the Account module.

# get account balance for vesting shares
account = Account(account, blockchain_instance=client)
balance = account['balance']
symbol = balance.symbol

# we need high precision because VESTS
denom = 1e6
delegated_vests = account['delegated_vesting_shares']
vesting_shares = account['vesting_shares']
vesting_symbol = vesting_shares.symbol
to_withdraw_vests = float(account['to_withdraw']) / denom
withdrawn_vests = float(account['withdrawn']) / denom

Here, we are gathering the current account details.

dgpo = client.get_dynamic_global_properties()
total_vesting_fund_hive = Amount(dgpo['total_vesting_fund_hive']).amount
total_vesting_shares_mvest = Amount(dgpo['total_vesting_shares']).amount / denom
base_per_mvest = total_vesting_fund_hive / total_vesting_shares_mvest

This block will help us convert VESTS to HIVE Power for display purposes. Best practice is to always allow the end-user to work with HIVE Power, not raw VESTS.

available_vests = (vesting_shares.amount - delegated_vests.amount - ((to_withdraw_vests - withdrawn_vests)))
available_base = (available_vests / denom) * base_per_mvest
powering_down = ((to_withdraw_vests - withdrawn_vests) / denom) * base_per_mvest

The available vesting shares to withdraw is not directly available from the user information and needs to be calculated. In order to find the total VESTS available to power down we need to know how much is currently in power down, how much has been delegated and then the total amount of vesting shares. The values are assigned from the query directly as float type to make the calculations a little simpler.

print(symbol + ' Power currently powering down: ' + format(powering_down, '.3f') + ' ' + symbol +
  '\n' + 'Available ' + symbol + ' Power: ' + format(available_base, '.3f') + ' ' + symbol)

input('\n' + 'Press enter to continue' + '\n')

The results of the query and calculation are converted to string type and displayed in the console/terminal.

4. Conversion amount and commit

The user is given the option to withdraw all available vesting shares, a portion of the shares or to cancel the transaction completely.

# choice of transfer
title = 'Please choose an option: '
options = ['Power down ALL', 'Power down PORTION', 'Cancel Transaction']
# get index and selected transfer type
option, index = pick(options, title)

Based on the input from the user the amount variable can be assigned and the transaction is broadcasted to the blockchain. The amount must be between zero and the total amount of vesting shares (both pending conversion and available VESTS combined). The amount you set to be withdrawn will override the current amount of vesting shares pending withdrawal. If for example the user enters a new amount of '0' shares to be withdrawn, it will cancel the current withdrawal completely.

Note that if the user decides to power down only a portion, we capture the amount they intend to power down as HIVE Power, then convert that amount to VESTS behind the scenes, in keeping with the principle of only interacting with the end user in terms of HIVE Power, which is the recommended best practice.

# parameters: amount, account
if (option == 'Cancel Transaction'):
  print('transaction cancelled')
  exit()

if (option == 'Power down ALL'):
  if (available_vests == 0):
    print('No change to withdraw amount')
    exit()
  amount_vests = to_withdraw_vests + available_vests
  amount = (amount_vests / denom) * base_per_mvest
else:
  amount = float(input('Please enter the amount of ' + symbol + ' you would like to power down: ') or '0')
  amount_vests = (amount * denom) / base_per_mvest

if (amount_vests <= (to_withdraw_vests + available_vests)):
  account.withdraw_vesting(amount_vests)
  print(format(amount, '.3f') + ' ' + symbol + ' (' + format(amount_vests, '.6f') + ' ' + vesting_symbol + ') now powering down')
  exit()

if (amount_vests == to_withdraw_vests):
  print('No change to withdraw amount')
  exit()

print('Insufficient funds available')

The result is displayed on the console/terminal.

Final code:

import pprint
from pick import pick
import getpass
from beem import Hive
from beem.account import Account
from beem.amount import Amount

# capture user information
account = input('Enter username: ')
wif_active_key = getpass.getpass('Enter private ACTIVE key: ')

# node_url = 'https://testnet.openhive.network' # Public Testnet
node_url = 'http://127.0.0.1:8090' # Local Testnet

# connect node and private active key
client = Hive(node_url, keys=[wif_active_key])

# get account balance for vesting shares
account = Account(account, blockchain_instance=client)
balance = account['balance']
symbol = balance.symbol

# we need high precision because VESTS
denom = 1e6
delegated_vests = account['delegated_vesting_shares']
vesting_shares = account['vesting_shares']
vesting_symbol = vesting_shares.symbol
to_withdraw_vests = float(account['to_withdraw']) / denom
withdrawn_vests = float(account['withdrawn']) / denom

dgpo = client.get_dynamic_global_properties()
total_vesting_fund_hive = Amount(dgpo['total_vesting_fund_hive']).amount
total_vesting_shares_mvest = Amount(dgpo['total_vesting_shares']).amount / denom
base_per_mvest = total_vesting_fund_hive / total_vesting_shares_mvest
available_vests = (vesting_shares.amount - delegated_vests.amount - ((to_withdraw_vests - withdrawn_vests)))
available_base = (available_vests / denom) * base_per_mvest
powering_down = ((to_withdraw_vests - withdrawn_vests) / denom) * base_per_mvest

print(symbol + ' Power currently powering down: ' + format(powering_down, '.3f') + ' ' + symbol +
  '\n' + 'Available ' + symbol + ' Power: ' + format(available_base, '.3f') + ' ' + symbol)

input('\n' + 'Press enter to continue' + '\n')

# choice of transfer
title = 'Please choose an option: '
options = ['Power down ALL', 'Power down PORTION', 'Cancel Transaction']
# get index and selected transfer type
option, index = pick(options, title)

# parameters: amount, account
if (option == 'Cancel Transaction'):
  print('transaction cancelled')
  exit()

if (option == 'Power down ALL'):
  if (available_vests == 0):
    print('No change to withdraw amount')
    exit()
  amount_vests = to_withdraw_vests + available_vests
  amount = (amount_vests / denom) * base_per_mvest
else:
  amount = float(input('Please enter the amount of ' + symbol + ' you would like to power down: ') or '0')
  amount_vests = (amount * denom) / base_per_mvest

if (amount_vests <= (to_withdraw_vests + available_vests)):
  account.withdraw_vesting(amount_vests)
  print(format(amount, '.3f') + ' ' + symbol + ' (' + format(amount_vests, '.6f') + ' ' + vesting_symbol + ') now powering down')
  exit()

if (amount_vests == to_withdraw_vests):
  print('No change to withdraw amount')
  exit()

print('Insufficient funds available')


To Run the tutorial

You can launch a local testnet, with port 8090 mapped locally to the docker container:

docker run -d -p 8090:8090 inertia/tintoy:latest

For details on running a local testnet, see: Setting Up a Testnet

  1. review dev requirements
  2. git clone https://gitlab.syncad.com/hive/devportal.git
  3. cd devportal/tutorials/python/25_power_down
  4. pip install -r requirements.txt
  5. python index.py
  6. After a few moments, you should see a prompt for input in terminal screen.