Link a BTC PK to Your BABY Address
The Proof-of-Possession (PoP) establishes ownership of both your BTC key and BABY address. For BTC stakers, the BTC key refers to the Schnorr key that signs the staking transaction.
This guide demonstrates how to generate the PoP, validate it, submit it to the airdrop API, and remove it if you need to link your BTC key to a different BABY address.
This guide assumes that you have created a Babylon address to receive the airdrop using the Babylon Address CLI Creation guide. Please ensure that you have access to your keyring before proceeding.
PoP format for BTC stakers
The Airdrop API requires the following JSON message format of a PoP for btc stakers:
{
"babyAddress": "bbn1xjz8fs9vkmefdqaxan5kv2d09vmwzru7jhy424",
"btcAddress": "bc1qcpty6lpueassw9rhfrvkq6h0ufnhmc2nhgvpcr",
"btcPublicKey": "79f71003589158b2579345540b08bbc74974c49dd5e0782e31d0de674540d513",
"btcSignBaby": "AkcwRAIgcrI2IdD2JSFVIeQmtRA3wFjjiy+qEvqbX57rn6xvWWECIDis7vHSJeR8X91uMQReG0pPQFFLpeM0ga4BW+Tt2V54ASEDefcQA1iRWLJXk0VUCwi7x0l0xJ3V4HguMdDeZ0VA1RM=",
"babySignBtc": "FnYTm9ZbhJZY202R9YBkjGEJqeJ/n5McZBpGH38P2pt0YRcjwOh8XgoeVQTU9So7/RHVHHdKNB09DVmtQJ7xtw==",
"babyPublicKey": "Asezdqkvh+kLbuD75DirSwi/QFbJjFe2SquiivMaPS65"
}
Detailed specification of each field:
babyAddress
: The Bech-32 encoded BABY address.btcAddress
: The Bech-32 encoded address of the staker BTC key used in phase-1 staking.btcPublicKey
: The hex encoded staker public key used.btcSignBaby
: The Base64 encoded BIP322 signature made using the key corresponding to thebtcAddress
.babySignBtc
: The Base64 encoded ADR36 signature made using the key corresponding to thebabyPublicKey
. The signing doc spec can be found here.babyPublicKey
: The Base64 encoded Babylon public key corresponding to thebabyAddress
.
You have the option to either develop your own tooling following the above specification or use our reference implementation following the rest of the guide.
1. Generate PoP
1.1. Prepare the BTC wallet
We'll use the bitcoind
wallet to demonstrate how to prepare your BTC wallet.
Launch your bitcoind instance and load the wallet you used for phase-1 staking (see instructions for bitcoind
setup for phase-1):
bitcoin-cli -rpcuser=user -rpcpassword=pass loadwallet "walletName"
where:
rpcuser=user
specifies the username for bitcoind RPC access.rpcpassword=pass
specifies the password for bitcoind RPC access.loadwallet "walletName"
specifies the name of wallet used in phase-1 staking.
1.2. Setup the stakercli
The stakercli
program facilitates communication between your BABY keyring and bitcoind wallet to create a valid PoP payload.
First, clone the btc-staker
repository:
git clone https://github.com/babylonlabs-io/btc-staker.git
Cloning into 'btc-staker'...
Next, checkout to the v0.15.2
release tag:
cd btc-staker
git checkout v0.15.2
In the root directory of btc-staker
, install the binaries using make install
:
make installCGO_CFLAGS="-O -D__BLST_PORTABLE__" go install -mod=readonly --tags "" --ldflags '' ./...
Verify the installation by running stakercli --help
.
make install
CGO_CFLAGS="-O -D__BLST_PORTABLE__" go install -mod=readonly --tags "" --ldflags '' ./...
1.3. Create PoP
You can create and export the PoP using the stakercli pop gcp
command:
stakercli --help
NAME:
stakercli - Bitcoin staking controller
USAGE:
stakercli [global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
Admin:
admin, ad Different utility and admin commands
Daemon commands:
daemon, dn More advanced commands which require staker daemon to be running.
PoP commands:
pop Commands realted to generation and verification of the Proof of Possession
transaction commands:
transaction, tr Commands related to Babylon BTC transactions Staking/Unbonding/Slashing
GLOBAL OPTIONS:
--btc-network value Bitcoin network on which staking should take place (default: "testnet3")
--btc-wallet-host value Bitcoin wallet rpc host (default: "127.0.0.1:18554")
--btc-wallet-rpc-user value Bitcoin wallet rpc user (default: "user")
--btc-wallet-rpc-pass value Bitcoin wallet rpc password (default: "pass")
--btc-wallet-passphrase value Bitcoin wallet passphrase
--help, -h show help
When --output-file
is specified, this command generates a JSON file containing the PoP result at the specified path. Here are the available flag options:
--btc-address
is the Bech-32 encoded address of the BTC key used in phase-1 staking.--baby-address
is the Bech-32 encoded BABY address.--keyring-dir
is the directory on which the BABY key that will receive the airdrop is stored. Note that this should not contain the direct parent directory of the key files (e.g.,keyring-xxx
). For example, if the keyring file is stored under~/.babylond/keyring-file/
, then~/.babylond/
should be specified in the flag.--keyring-backend
is the backend of the BABY key. It should be the same as the one when the key was created.--btc-wallet-host
is the host of the BTC wallet. The default for BTC mainnet islocalhost:8332
.--btc-wallet-rpc-user
Bitcoin wallet rpc user (default:user
). Specify if needed.--btc-wallet-rpc-pass
Bitcoin wallet rpc password (default:pass
). Specify if needed.--btc-wallet-passphrase
Bitcoin wallet passphrase. Specify if needed.--output-file
specifies the file path of the raw JSON result. Note that if the flag is not specified, the JSON file won't be generated.
1.4. Validate PoP
To validate the JSON file that contains the PoP, run stakercli pop validate
command:
stakercli pop validate /path/to/pop.json
Proof of Possession is valid!
2. Submit PoP via API
To register your staker’s information for the airdrop (if eligible), you need to submit the previously created PoP payload to the airdrop API endpoint:
curl -X POST 'https://airdrop-api.babylon.foundation/pop/baby-btc' \
-H 'Content-Type: application/json' \
-d '{
"babyAddress": "bbn1xjz8fs9vkmefdqaxan5kv2d09vmwzru7jhy424",
"btcAddress": "bc1qcpty6lpueassw9rhfrvkq6h0ufnhmc2nhgvpcr",
"btcPublicKey": "79f71003589158b2579345540b08bbc74974c49dd5e0782e31d0de674540d513",
"btcSignBaby": "AkcwRAIgcrI2IdD2JSFVIeQmtRA3wFjjiy+qEvqbX57rn6xvWWECIDis7vHSJeR8X91uMQReG0pPQFFLpeM0ga4BW+Tt2V54ASEDefcQA1iRWLJXk0VUCwi7x0l0xJ3V4HguMdDeZ0VA1RM=",
"babySignBtc": "FnYTm9ZbhJZY202R9YBkjGEJqeJ/n5McZBpGH38P2pt0YRcjwOh8XgoeVQTU9So7/RHVHHdKNB09DVmtQJ7xtw==",
"babyPublicKey": "Asezdqkvh+kLbuD75DirSwi/QFbJjFe2SquiivMaPS65"
}'
In case of success, the API will return a 200 status code and the following response:
{"message":"ok"}
In the case that your staker key does not have any stake/points or is otherwise not eligible, the API will return a 400 status code and the following response:
{"message":"Sorry, you are not in the staker list","code":400}
To make sure your staker key was successfully registered, you can query it by the associated baby address and check whether your staker public key matches
curl -X 'GET' 'https://airdrop-api.babylon.foundation/pop/baby-btc?babyAddress=your-baby-address' -H 'accept: application/json'
The API will return the following response (formatted by jq
):
[
{
"babyAddress": "bbn1xjz8fs9vkmefdqaxan5kv2d09vmwzru7jhy424",
"btcAddress": "bc1qcpty6lpueassw9rhfrvkq6h0ufnhmc2nhgvpcr",
"btcPublicKey": "79f71003589158b2579345540b08bbc74974c49dd5e0782e31d0de674540d513",
"btcSignBaby": "AkcwRAIgcrI2IdD2JSFVIeQmtRA3wFjjiy+qEvqbX57rn6xvWWECIDis7vHSJeR8X91uMQReG0pPQFFLpeM0ga4BW+Tt2V54ASEDefcQA1iRWLJXk0VUCwi7x0l0xJ3V4HguMdDeZ0VA1RM=",
"babySignBtc": "FnYTm9ZbhJZY202R9YBkjGEJqeJ/n5McZBpGH38P2pt0YRcjwOh8XgoeVQTU9So7/RHVHHdKNB09DVmtQJ7xtw==",
"babyPublicKey": "Asezdqkvh+kLbuD75DirSwi/QFbJjFe2SquiivMaPS65"
}
]
This response returns all the staker public keys associated with this BABY address. If there is no Proof of Possession associated with this baby address it will return an empty slice.
3. Delete submitted PoP
If you wish to remove the BABY address associated with your BTC key, you can delete the submitted PoP and re-submit a new PoP that bonds the BTC staker to a different BABY address. Please note that this is a necessary first step if you want to change your BABY address to a new one — i.e., you must first delete the existing association and then create a new one.
3.1. Retrieve the Deletion Message
The first step to deleting your PoP is to retrieve a message containing a custom nonce from the Babylon API. You can obtain this by calling the following endpoint (replace your-baby-address
with the BABY address used in the submitted PoP):
curl -X GET 'https://airdrop-api.babylon.foundation/pop/baby-sign-message?address=your-baby-address'
Example response in JSON format:
{"message":"Welcome to Babylon Airdrop!\\r\\nAddress: bbn1v2a65yjl5cathzl8hdysqr9xz7w503xvvu85fx\\r\\nNonce: 0f7c99f145"}
3.2. Sign the response message
To prove ownership of the staker key that intends to delete the existing PoP, you need to cryptographically sign the entire string literal found in the message
attribute of the previous JSON response.
You can accomplish this by running stakercli pop gdp
command:
stakercli pop gdp --btc-address bc1qrxxqcyf7deu669wku78np3nzyg5jdnegvpg9lt \
--baby-address bbn1xjz8fs9vkmefdqaxan5kv2d09vmwzru7jhy424 \
--keyring-dir /path/to/babylon/keyring \
--keyring-backend file \
--msg='Welcome to Babylon Airdrop!\\r\\nAddress: bbn1v2a65yjl5cathzl8hdysqr9xz7w503xvvu85fx\\r\\nNonce: 0f7c99f145'
Enter keyring passphrase (attempt 1/3):
{
"babyAddress": "bbn1xjz8fs9vkmefdqaxan5kv2d09vmwzru7jhy424",
"babySignature": "adEjxmRv+ujogTKt5Vnngo8BLatv+e0Xqs4KQzQm+gEUCTe8c4pXNAfYa5UMaEI0pbkqD5qKAo++LBbxVz/kkA==",
"babyPublicKey": "Asezdqkvh+kLbuD75DirSwi/QFbJjFe2SquiivMaPS65",
"btcAddress": "bc1qrxxqcyf7deu669wku78np3nzyg5jdnegvpg9lt"
}
where:
--msg
is the message received from the API. It is important that string is closed in single quotes.--keyring-dir
is where the BABY key is stored.--keyring-backend
is the backend of the BABY key. It should be the same as the one when the key is created.--btc-address
is the address of the BTC key used in phase-1 staking. Bech-32 encoded.--baby-address
is the address derived from the BABY key used in a submitted PoP. Bech-32 encoded.
3.3. Submit the PoP Deletion Request
The output of the stakercli pop gdp
command is the payload you need submit to the API in order to finalize the deletion request:
curl -X DELETE 'https://airdrop-api.babylon.foundation/pop/baby-btc' \
-H 'Content-Type: application/json' \
-d '{
"babyAddress": "bbn1xjz8fs9vkmefdqaxan5kv2d09vmwzru7jhy424",
"babySignature": "adEjxmRv+ujogTKt5Vnngo8BLatv+e0Xqs4KQzQm+gEUCTe8c4pXNAfYa5UMaEI0pbkqD5qKAo++LBbxVz/kkA==",
"babyPublicKey": "Asezdqkvh+kLbuD75DirSwi/QFbJjFe2SquiivMaPS65",
"btcAddress": "bc1qrxxqcyf7deu669wku78np3nzyg5jdnegvpg9lt"
}'
In case of success, the API will return a 200 status code and the following response:
{"message":"ok"}
To ensure deletion, getting PoP by your BABY wallet address will return an empty array:
curl -X GET 'https://airdrop-api.babylon.foundation/pop/baby-btc?babyAddress=your-baby-address'
[]
Now, you can submit a new PoP with a new BABY address.