Prerequisites
For this tutorial, you will need:
- A working install of the
cardano-node
andcardano-cli
binaries. Check out our pre-built Docker containers if you need help with this. - A running instance of
cardano-node
fully synced with the blockchain. - The latest Cardano-Tools python library.
- A Shelley wallet with enough ADA for the registration fees, transaction fees, and pool pledge.
If you are new to setting up a node, check out this tutorial.
Setting Up Accounts
First, we are going to create the necessary owner accounts for registering a stake pool. Once these are created, we will transfer funds from our wallet software, i.e., Daedalus, to these accounts. One could theoretically use their Daedalus wallets directly; however, currently, Daedalus does not provide an easy way to export the signing and verification keys we need.
In order to provide a more complete demonstration, we will create three new accounts:
- Owner #1 account (both wallet and staking accounts)
- Owner #2 account (both wallet and staking accounts)
- Rewards account (both wallet and staking accounts)
A single account may be used to register a stake pool; however, it is often desirable to have multiple accounts responsible for the pledge, for instance, when a pool has multiple operators.
The code to create the accounts is demonstrated below. Note that the ShelleyTools
object needs the path to the cardano-cli
binary, the path to the node.socket
file, and the path to a working directory where the generated key files will be placed.
from cardano_tools import ShelleyTools
# Inputs (change for your node!)
path_to_cli = "/home/cardano/.cabal/bin/cardano-cli"
path_to_socket = "/home/cardano/node/node.socket"
working_dir = "/home/cardano/pool-setup/"
# Create a ShelleyTools object
shelley = ShelleyTools(
path_to_cli,
path_to_socket,
working_dir)
)
shelley.debug = True # This enables useful output
# Create the new address and all the required key files.
owner1_addr = shelley.make_address("owner1")
owner2_addr = shelley.make_address("owner2")
rewards_addr = shelley.make_address("rewards")
print(f"Owner #1 account number: {owner1_addr}")
print(f"Owner #2 account number: {owner2_addr}")
print(f"Rewards account number: {rewards_addr}")
Fund the Wallets
The wallets will all need a limited amount of ADA in order to pay the transaction fees when registering the staking addresses and the pool certificates. For this example, we will send each of the owner addresses the amount of ADA we want to stake plus an extra 5 ADA. The rewards account will be used to pay the pool deposit of 500 ADA, so we will send 505 ADA to this wallet.
The following code snippet may be used to verify the wallets have received the funds send from your Daedalus account(s).
# ...using the ShelleyTools object created previously...
from pathlib import Path
working_dir = Path("/home/cardano/pool-setup/")
owner1_addr = open(working_dir / "owner1.addr", 'r').read()
owner2_addr = open(working_dir / "owner2.addr", 'r').read()
rewards_addr = open(working_dir / "rewards.addr", 'r').read()
# List the UTXOs in each account
print(f"Owner #1's account number: {owner1_addr}")
print(
json.dumps(
shelley.get_utxos(owner1_addr),
indent=4,
sort_keys=True
)
)
print(f"Owner #2's account number: {owner2_addr}")
print(
json.dumps(
shelley.get_utxos(owner2_addr),
indent=4,
sort_keys=True
)
)
print(f"Rewards account number: {rewards_addr}")
print(
json.dumps(
shelley.get_utxos(rewards_addr),
indent=4,
sort_keys=True
)
)
Register the Staking Addresses
With some funds in the wallets, we can register the staking addresses.
# ...using some variables created previously...
# Register the associated staking addresses on the blockchain.
shelley.register_stake_address(
owner1_addr,
working_dir / "owner1_stake.vkey",
working_dir / "owner1_stake.skey",
working_dir / "owner1.skey",
cleanup=True
)
shelley.register_stake_address(
owner2_addr,
working_dir / "owner2_stake.vkey",
working_dir / "owner2_stake.skey",
working_dir / "owner2.skey",
cleanup=True
)
shelley.register_stake_address(
rewards_addr,
working_dir / "rewards_stake.vkey",
working_dir / "rewards_stake.skey",
working_dir / "rewards.skey",
cleanup=True
)
Once the staking addresses are registered on the blockchain, we can register the stake pool.
Register the Stake Pool
Registering a stake pool will be divided into three steps: metadata (for wallets), stake pool key generation, and finally stake pool certificate registration.
Stake Pool Metadata
In order for the pool to be included in wallets, pool metadata must be generated and hosted at a static web address. The hash of the file must also be saved or re-calculated for inclusion during pool registration. The website, pooltool.io can be used to generate and host this metadata, but we will generate it manually in this tutorial.
# ...using the ShelleyTools object created previously...
metadata = {
"name": "My Stake Pool Name",
"description": "My pool description--its awesome!.",
"ticker": "TICKR",
"homepage": "https://yourstakingbusinesswebsite.com/"
}
# Create the Metadata JSON file
metadata_hash = shelley.create_metadata_file(metadata)
print(metadata_hash)
Files created:
TICKR_metadata.json
Upload the created file to your website.
Generate Pool Keys
A rather extensive set of pool keys must be generated before operating the stake pool. Luckily, Cardano-Tools provides an easy interface for this.
# ...using the ShelleyTools object created previously...
# Generate the pool keys.
pool_id = shelley.create_block_producing_keys(genesis_file, pool_name="TICKR")
print(f"TICKR Stake Pool ID: {pool_id}")
Files created:
TICKR.cert
TICKR.id
TICKR_cold.counter
TICKR_cold.skey
TICKR_cold.vkey
TICKR_vrf.skey
TICKR_vrf.vkey
TICKR_kes.skey
TICKR_kes.vkey
Note: It is recommended that these keys be generated offline if possible. However, the next step assumes access to a connected node to send a transaction. Do not store private keys on a network-connected server.
Register the Pool
Finally, the pool must be registered on the blockchain. The registration requires creating a pool certificate (containing all of the pool’s information), which must be signed and submitted to the blockchain as a transaction.
# ...using the ShelleyTools object created previously...
# Stakepool registration inputs
working_dir = Path("/home/lovelace/cardano-node/")
genesis_file = working_dir / "mainnet-shelley-genesis.json"
rewards_addr = open(working_dir / "rewards.addr", 'r').read()
pledge_ada = 10_000 # will convert to lovelace below
cost_ada = 500 # minimum is 340
margin = 3 # pool margin in percent
args = {
"pool_name": "TICKR",
"pool_pledge": pledge_ada*1_000_000,
"pool_cost": cost_ada*1_000_000,
"pool_margin": margin,
"pool_cold_vkey": working_dir / "TICKR_cold.vkey",
"pool_cold_skey": working_dir / "TICKR_cold.skey",
"pool_vrf_key": working_dir / "TICKR_vrf.vkey",
"pool_reward_vkey": working_dir / "rewards_stake.vkey",
"owner_stake_vkeys": [
working_dir / "owner1_stake.vkey",
working_dir / "owner2_stake.vkey"
],
"owner_stake_skeys": [
working_dir / "owner1_stake.skey",
working_dir / "owner2_stake.skey"
],
"payment_addr": rewards_addr,
"payment_skey": working_dir / "rewards.skey",
"genesis_file": genesis_file,
"pool_relays": [
{
"port": "3001",
"host": "relay1.yourstakingbusinesswebsit.com",
"host-type": "single"
}
],
"pool_metadata_url": "https://yourstakingbusinesswebsit/TICKR_metadata.json",
"folder": working_dir
}
# Resister the stakepool on the blockchain
shelley.register_stake_pool(**args)
As in the above example, when the metadata file hash is not provided, the code will pull down the file from the URL and compute the hash on the fly.
Updating the Pool Registration
Inevitably, someone will need to update the information in their pool registration. To do this, we simply update the pool registration dictionary as above, only this time we use it with the update_stake_pool_registration function. We use this function because it does not pay the registration deposit of 500 ADA, which is only required during initial registration.
# ...using previously defined values....
# Update the stakepool resistration on the blockchain
shelley.update_stake_pool_registration(**args)
Summary
In this tutorial, we walked through the process of registering a stake pool using the Cardano-Tools library from beginning to end. As always, if you have questions, please contact us in our Telegram channel.