The cardano-addresses
utility is a command line tool for manipulating - guess
what - addresses.
You can find its source code in the following repository: https://github.com/input-output-hk/cardano-addresses, but most users would simply want the compiled binaries from the release page
IMPORTANT All of the steps described here apply to linux. You will have to adapt the commands to make things work on Windows, but the sequence of steps is the same.
Simply download the latest released file for your operating system for the release page
Unzip the file and you should get a cardano-address
binary.
For the sake of simplicity, create a dev/cardano
folder under your home
directory, then move the binary into it:
mkdir ~/dev
mkdir ~/dev/cardano
mv ~/Downloads/cardano-address ~/dev/cardano
Make it executable:
cd ~/dev/cardano
chmod +x cardano-address
See if it works
./cardano-address --version
This should output something like:
2.0.0 @ 9a64226fd749513ad0ed2e43e663f7132c92faa7
Once you get there, you are ready to move on to learning how to use this tool.
IOG did a pretty good job with their command line tools: every command is organized as "sub-menus" and every time you type in a command you'll get the options available from the path you took.
For example, from cardano-address
you'll get the top "menu" options:
./cardano-address
>Available commands:
version Show the software current version and build revision.
recovery-phrase About recovery phrases
key About public/private keys
address About addresses
Let's try out the recovery-phrase
option:
./cardano-address recovery-phrase
>Available commands:
generate Generate an English recovery phrase
So it looks like we only have the generate
option from there, let's see what
it does:
./cardano-address recovery-phrase generate
>return arrest letter ready seat weird news you wave profit ritual grace cream lawsuit lend alone crisp foil joy gas caught vintage fresh modify
Amazing, we got a random 24 words seed phrase for a wallet! That was super easy.
You can enable bash to auto-complete the available commands for you with this command:
source <( ./cardano-address --bash-completion-script `which ./cardano-address`)
Now, you can type ./cardano-address
followed by a tab key press to get the
list of available commands and their arguments:
./cardano-address recovery-phrase <TAB>
> generate -h --help
./cardano-address recovery-phrase generate <TAB>
./cardano-address recovery-phrase generate -<TAB>
> -h --help --size
Hm so it looks like the generate
option allows for a --size
parameter, let's
try this out:
./cardano-address recovery-phrase generate --size 9
>work swim render cart amazing valve funny tomato drink
Et voila, a 9 word long seed phrase. Easy as pie.
So now that you got the hang of it, let's dive deeper into it.
To generate a seed phrase, simply run
./cardano-address recovery-phrase generate --size <WORD COUNT>
Where the word count is one of 9, 12, 15, 18, 21 or 24 words, eg:
./cardano-address recovery-phrase generate --size 12
>zebra dinosaur galaxy valve kangaroo image omit mystery faith crime normal omit
./cardano-address recovery-phrase generate --size 21
>sentence sail donate pioneer theory suspect mammal dove impulse second narrow animal concert bless design flag glow area blame noble forget
-
Shelley addresses:
-
For daedalus, use
--size 24
. -
For yoroi, use
--size 15
.
-
-
Byron legacy wallet
-
For daedalus, use
--size 12
. -
For yoroi use
--size 15
.
-
NOTE: There is no support for the legacy Byron paper wallet format, which used 27 words.
To make the upcoming instructions easier to follow and reproduce, store the
seed phrase in a text file. We'll be using --size 24
from now on.
./cardano-address recovery-phrase generate --size 24 > seed.txt
cat seed.txt
>intact engine crumble rotate umbrella flee wire talk creek employ rural state wreck pluck settle later okay foot assault general type mutual excuse valid
With the command above your seed phrase will be insecurely stored in a plain
text file named seed.txt
. With this we can proceed to the next steps.
The private key is the actual identifier of a wallet. You can derive a private key from a seed phrase with:
./cardano-address key from-recovery-phrase <STYLE>
Where <STYLE> is one of:
- Byron (deprecated): used for Byron wallets created by Daedalus
- Icarus (deprecated): used for Byron wallets created in Yoroi
- Jormungandr (deprecated): used for the incentivized testnet (ITN)
- Shelley: basically this is what you should use for new wallets 100% of the time
To create the private key from a seed phrase, execute:
cat seed.txt | ./cardano-address key from-recovery-phrase Shelley > private_key.txt
cat private_key.txt
>xprv13zxmjna3a2v32wtnj60jw53fm4fy54737r9gj4pqape8sn4vgewcm8xsfeuh8f2404fung9lkgedhayalfwepa2he3qwmxppqv6tv36tc6epzmznfgy5j4glkg8lmahyr40lvhthzw9muumdf9guzrvsuqu7740q
The above inputs the seed phrase in seed.txt
to command
cardano-address key from-recovery-phrase Shelley
, and outputs a
private_key.txt
file with your private key in plain text.
NOTE: keeping seed phrases or private keys in plain text files is an obvious security risk
The public key is the key you can use to identify your wallet on the blockchain. You can obtain the public key for your wallet using:
cat private_key.txt | ./cardano-address key public > public_key.txt
cat public_key.txt
>xpub1lxy8vqgzt00dq34u8476ulp60px6aggunztnf98vdn2c4rguwtjyh34jz9k9xjsff923lvs0lhmwg82l7ewhwyutheek6j23cyxepcqhau52r
Notice you can't send ADA to this address. For that you need an account.
Basically from the private key, we derive more keys other than just the public key: you can also derive accounts and payment addresses for each account.
Everything is determined by a derivation path, in the following format:
private_key / purpose / coin_type / account_index / change / address_index
Some of these elements are pretty much fixed constants:
-
purpose =
1852
don't ask me why, it's a constant determined by a higher being -
coin_type =
1815
which means Cardano's ADA (there's a standard for that, and we were assigned this number) -
change =
0
which represents a "receiving" address. 1 means "change" address and as far as I know you won't usually need to worry about this.
If you are interested in generating payment addresses for a wallet, you simply don't have to think about this stuff.
So let's move on to what was left unexplained:
- account_index: typically
0
, but can be any number up to2^31
. Accounts mean you can segregate payments received into your wallet into separate buckets. You could create a "personal account" on index0
, a "business account" on account index1
, a "savings account" in index100
and so on.
IMPORTANT: All desktop/mobile wallets around currently support account 0 only. If you create account 1, 2 or whatever the transactions associated with these accounts will not show up
- address_index: a sequential index for a payment address, starting at
0
. Increment the address_index every time you need a new address to share with someone, so they can send funds to you. You can reuse payment addresses but then multiple people will be able to see how much you are receiving through that same payment address. You can generate up to2^31
addresses for each account.
IMPORTANT: Wallets following the BIP-44 standard basically look for 20 transactions after the last transaction received. So if you receive a payment on address generated with address_index = 6, your wallet will only display the money received on addresses from 0 to 26.
If you received payment on address with address_index = 30, the funds will not be displayed to you even though it's on the blockchain. It will only appear once there is a transaction in some address where address_index is between 10 and 29.
This applies for all current desktop/mobile/hardware wallets, so be aware. The gap limit can be customized on some wallets, but increasing it reduces synchronization performance.
To generate payment addresses for an account of your wallet you need the account derivation path - also known as the public root key. This is essentially the initial section of the HD address:
private_key / purpose / coin_type / account_index
Back to the command line, we can create the root key for account 0
with:
cat private_key.txt | ./cardano-address key child 1852H/1815H/0H > account_0_key_path.txt
cat account_0_key_path.txt
> xprv1fpwz27sk7yht78d4rwaq3a2e9p744w8xz0fe9rqpgkkxsk4vgew5tz6zfkw46xql705c8nzwulswap4zhq3vs3vwcj5cmtsqlxu3nstxheqxwqg2fj608vge2aja5yf5ug2603vkkp8s8jljktkrqzrqn5gykw0q
Here we input the private key, and generate a derivation path with the 1852
and 1815
constants presented earlier, plus the account index.
Notice that every constant in the path is followed by H
, which stands for "hardened".
This means the key path was derived using the private key.
NOTICE: although the
cardano-address
utility will give you an output that looks OK if you don't type in the 'H' after each constant, no payment address generated later on will be valid. If you send funds to such addresses they will be lost.
From the key path, we can generate the public root key:
cat account_0_key_path.txt | ./cardano-address key public > account_0_public_root_key.txt
cat account_0_public_root_key.txt
xpub1exevcxkw9ldsm7szljjyymesml0vzpc59swplz7ftnclk2yamm7kd0jqvuqs5n957wc3j4m9mggnfcs45lzedvz0q09l9vhvxqyxp8gpdvt5a
The public root key allows you or others to generate payment addresses securely without having access to your private key. You can share this key with the world.
The public root key is useful to enable third parties to generate payment
addresses in your behalf. Notice that the payment addresses generated from it
are bound to the account. In the example above, we can only derive payment
addresses for account 0
.
With the public root key ready, we only have to fill out the remaining bits of the derivation path to get a full path:
change / address_index
As already mentioned, change = 0
, and the address index starts from 0
. So
we can generate the full derivation address (still not a payment address) with:
cat account_0_public_root_key.txt | ./cardano-address key child 0/0 > key_for_account_0_address_0.txt
cat key_for_account_0_address_0.txt
> xpub1ccntmvkwgwlzv5r03vpy2n9nruy5x5d5kzww3egpvga7zf2v0gg2n7rlgrh5qnm7sja0wymccdydrvhnk6zgwy4llfcq8j0tzxexwmsn09nwm
That will generate a key which maps to account 0
, address 0
in your wallet.
Notice the private key has not been used here.
We can keep generating full derivation paths for more addresses by incrementing
the address_index
part:
cat account_0_public_root_key.txt | ./cardano-address key child 0/1 > key_for_account_0_address_1.txt
cat key_for_account_0_address_1.txt
xpub1kg7vl5c7nw9ee062u56xrv6dvpsd6lf3auwhggzh2e7edue4hdp6fntl6ux4w4wgy5gfh4tdmc2m6jszfzdnpcfyhhu72fjztcpsmms22e64k
NOTICE: nothing prevents you from creating an address straight to some crazy index such as 1 million, e.g.
cardano-address key child 0/1000000
, but if you send funds to a payment address generated from that key, it won't show up in your wallet as by default it expects one transaction every 20 addresses in sequence.
Finally, once you have the address key with the full derivation path, you can generate a payment address which people can send funds to:
cat key_for_account_0_address_0.txt | ./cardano-address address payment --network-tag 1 > pay_to_account_0_address_0.txt
cat pay_to_account_0_address_0.txt
> addr1v8fet8gavr6elqt6q50skkjf025zthqu6vr56l5k39sp9aqlvz2g4
If you send addr1v8fet8gavr6elqt6q50skkjf025zthqu6vr56l5k39sp9aqlvz2g4
to
others, they will be able to send fund to you.
Notice that --network-tag
was set to 1
. This parameter accepts two values:
-
0
for testnet -
1
for mainnet
Make sure to use the appropriate network tag for your environment.
The cardano-address
utility can be integrated into your software to enable
the generation of seed phrases, public root keys for one or more accounts, and
payment addresses that will work with the blockchain. It is by no means a
wallet and doesn't intend to be used as such.
Make sure to execute all steps in sequence, and test payments made to addresses
generated by your program on the testnet first (using --network-tag 0
).
You will have to use a programming language the allows invoking the
cardano-address
executable from as a system call. I did this using Java and
if you are familiar with that programming language, you can look at the source
code here,
with unit tests that perform the actions described in the tutorial
here.
I will produce a library for other Java developers based on this source code eventually. For now, feel free to copy these classes and use in your program.
I Hope the information here is useful to you and helps you to get started writing your own software for cardano!