Link a Finality Provider EOTS PK to your BABY Address

Before proceeding with this guide, please make sure you sign the terms first.

Proof-of-Possession (PoP) establishes ownership of both your finality provider’s EOTS key and your BABY address. For finality providers, the EOTS key is essentially a Schnorr key, which should have received delegations from the phase-1 network.

This guide demonstrates how to generate PoP, validate it, submit it to the API, and remove it if you need to bond your EOTS 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 finality providers

The Airdrop API requires the following JSON message format of a PoP for finality providers

{
  "eotsPublicKey": "3d0bebcbe800236ce8603c5bb1ab6c2af0932e947db4956a338f119797c37f1e",
  "babyPublicKey": "A0V6yw74EdvoAWVauFqkH/GVM9YIpZitZf6bVEzG69tT",
  "babySignEotsPk": "AOoIG2cwC2IMiJL3OL0zLEIUY201X1qKumDr/1qDJ4oQvAp78W1nb5EnVasRPQ/XrKXqudUDnZFprLd0jaRJtQ==",
  "eotsSignBaby": "pR6vxgU0gXq+VqO+y7dHpZgHTz3zr5hdqXXh0WcWNkqUnRjHrizhYAHDMV8gh4vks4PqzKAIgZ779Wqwf5UrXQ==",
  "babyAddress": "bbn17ew0he6svxrqj2c7mef7qsyg0assc2upa5gy7w"
}

Detailed specification of each field:

  • eotsPublicKey: The EOTS public key of the finality provider in hex format.
  • babyPublicKey: The Babylon secp256k1 public key in base64 format.
  • babyAddress: The BABY account address (bbn1..). The address is derived from the babyPublicKey and used as the primary identifier on the Babylon network.
  • eotsSignBaby: A Schnorr signature in base64 format, created by signing the sha256(babyAddress) with the EOTS private key.
  • babySignEotsPk: A signature of the eotsPublicKey, created by the Babylon private key. This signature follows the Cosmos ADR-036 specification and is encoded in base64. The signing doc spec can be found here.

One can develop tools by themselves following the above spec, or they can use our reference implementation and follow the guidance below.

1. Create PoP

1.1. Setup the EOTS Daemon

The EOTS daemon is utilized to create and manage the EOTS key of the finality provider. If you participated as a finality provider during the first phase of the Babylon mainnet, you should have already created your EOTS keys and stored them safely following this guide.

Note that for the purposes of this guide, you will need to upgrade your eotsd version to version v0.4.3 (previously v0.4.0 was used). To do this, please follow the instructions below.

First, download the finality provider toolset repository with git clone

git clone https://github.com/babylonlabs-io/finality-provider.git

Cloning into 'finality-provider'...

Then, checkout to the v0.4.3 release tag:

cd finality-provider # cd into the project directory
git checkout v0.4.3

Note: switching to 'v0.4.3'.

At the root of the finality provider repository install the finality provider binaries using make install.

make install
CGO_CFLAGS="-O -D__BLST_PORTABLE__" go install -mod=readonly --tags "" --ldflags ''  ./...

eotsd is part of the finality provider service suite, so running make install also generates fpd which is not used in this guide.

You can check if the installation succeeded by running eotsd --help.

eotsd --help
NAME:
   eotsd - Extractable One Time Signature Daemon (eotsd).

USAGE:
   eotsd [global options] command [command options] [arguments...]

COMMANDS:
   start               Start the Extractable One Time Signature Daemon.
   init                Initialize the eotsd home directory.
   sign-schnorr        Signs a Schnorr signature over arbitrary data with the EOTS private key.
   verify-schnorr-sig  Verify a Schnorr signature over arbitrary data with the given public key.
   pop                 Proof of Possession commands
   help, h             Shows a list of commands or help for one command

   Key management:
     keys  Command sets of managing keys for interacting with BTC eots keys.

GLOBAL OPTIONS:
   --help, -h  show help

1.2. Create the Proof of Possession (PoP)

The PoP can be created and exported using the eotsd pop export command. After which, you will need to enter passphrases for eots key and baby key consecutively.

eotsd pop export --home /path/to/eotsd/home/ --key-name <my-key-name> --keyring-backend file \
  --baby-home /path/to/babylon/home/ --baby-key-name <my-baby-key-name> --baby-keyring-backend file \
  --output-file /path/to/pop_fp.json
Enter keyring passphrase (attempt 1/3): # for your eots keyring
Enter keyring passphrase (attempt 1/3): # for your baby keyring
{
  "eotsPublicKey": "3d0bebcbe800236ce8603c5bb1ab6c2af0932e947db4956a338f119797c37f1e",
  "babyPublicKey": "A0V6yw74EdvoAWVauFqkH/GVM9YIpZitZf6bVEzG69tT",
  "babySignEotsPk": "AOoIG2cwC2IMiJL3OL0zLEIUY201X1qKumDr/1qDJ4oQvAp78W1nb5EnVasRPQ/XrKXqudUDnZFprLd0jaRJtQ==",
  "eotsSignBaby": "pR6vxgU0gXq+VqO+y7dHpZgHTz3zr5hdqXXh0WcWNkqUnRjHrizhYAHDMV8gh4vks4PqzKAIgZ779Wqwf5UrXQ==",
  "babyAddress": "bbn17ew0he6svxrqj2c7mef7qsyg0assc2upa5gy7w"
}

This command has several flag options:

  • --home specifies the home directory of the EOTS daemon in which the EOTS key created for phase-1 has been stored.
  • --key-name specified the name assigned to the EOTS key (is the value of the flag -key-name specified when running eotsd keys add --key-name ... ).
  • --passphrase specifies the password used to decrypt the key. The passphrase is required if it was specified when creating the EOTS key eotsd keys add --passphrase ....
  • --eots-pk is the EOTS public key which is specified as eots_pk in the GitHub registry for each finality provider (the -eots-pk flag takes priority over the -key-name flag, which requires eots.db in the -home directory).
  • --keyring-backend specifies the keyring backend. Any of [file, os, kwallet, test, pass, memory] are available. You can find more details about the available keyring backends here. By default, the test keyring backend is used, although it is recommended that you use an encrypted keyring.
  • --baby-home specifies the location where the BABY key is stored.
  • --baby-key-name specifies the key name of the BABY key.
  • --baby-keyring-backend specifies the keyring backend of the BABY key.
  • --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.

Please refer to the Phase-1 registration guide if you want a reminder on where you stored your EOTS home directory.

If you accidentally lost the keyring file, you can recover the keyring with the mnemonic phrases by running the eotsd keys add --recover flag option to prompt input the mnemonic phrases and recover the key:

eotsd keys add --home /path/to/eotsd/home/ --key-name <key-name-recover> --keyring-backend file --recover

1.3. Validate the Proof of Possession (PoP)

To validate the JSON file that contains the PoP, run eotsd pop validate command:

eotsd pop validate /path/to/pop_fp.json
 Proof of Possession is valid!

If Proof of Possession is valid! is shown, the pop is successfully validated.

1.4. Troubleshooting

Common problems and possible errors that might appear.

DB timeout

If you can’t connect to the database and get the following error:

[eotsd] failed to create db backend: timeout

You should stop the process that is keeping the .db file locked

Config error

If there is something wrong with your current config and the following error pops up:

[eotsd] failed to load config at...

This is probably due to a new parameter appeared in the config and you could create a new default config with eotsd init ..., just remember to update the values to your key name and directory path

2. Submit PoP via API

To register your finality provider 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-eots' \
-H 'Content-Type: application/json' \
-d '{
  "eotsPublicKey": "3d0bebcbe800236ce8603c5bb1ab6c2af0932e947db4956a338f119797c37f1e",
  "babyPublicKey": "A0V6yw74EdvoAWVauFqkH/GVM9YIpZitZf6bVEzG69tT",
  "babySignEotsPk": "AOoIG2cwC2IMiJL3OL0zLEIUY201X1qKumDr/1qDJ4oQvAp78W1nb5EnVasRPQ/XrKXqudUDnZFprLd0jaRJtQ==",
  "eotsSignBaby": "pR6vxgU0gXq+VqO+y7dHpZgHTz3zr5hdqXXh0WcWNkqUnRjHrizhYAHDMV8gh4vks4PqzKAIgZ779Wqwf5UrXQ==",
  "babyAddress": "bbn17ew0he6svxrqj2c7mef7qsyg0assc2upa5gy7w"
}'

In case of success, the API will return a 200 status code and the following response:

{"message": "ok"}

In the case that your EOTS key does not receive 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 FP list","code":400}

To make sure your finality provider was successfully registered, you can query it by the associated baby address and check whether your EOTS public key matches

curl -X 'GET' 'https://airdrop-api.babylon.foundation/pop/baby-eots?babyAddress=your-baby-address' -H 'accept: application/json'

The API will return the following response (formatted by jq):

[
  {
    "eotsPublicKey": "289719ef19e455816e474588007f1824df7f6b1bace7decf8bb1c435e4cb849e",
    "babyPublicKey": "Ax4u7IEfmG6q5Ai//uD9m9vKRdU/uhWd4GSVwxwHIYQm",
    "babyAddress": "bbn1v2auyq4pwgtp3yas9fdlkzehnhefzxg7vfpfdz"
  }
]

This response returns all the ETOS public keys associated with this BABY address. If there is no PoP 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 finality provider, you can delete the submitted PoP and re-submit a new PoP that bonds the EOTS key to a different BABY address. Please note that this is a necessary first step if you want to change your Babylon 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 that you are the owner of the finality provider key that intends to delete the existing proof of possession, you need to cryptographically sign the string literal that is stored inside the message attribute of the prior JSON response.

You can accomplish this by running eotsd pop delete command:

eotsd pop delete --home /path/to/eotsd/home/ --key-name <my-key-name> \
   --keyring-backend file --baby-home /path/to/babylon/home/ \
   --baby-key-name <my-baby-key-name> --baby-keyring-backend file \
   --message 'Welcome to Babylon Airdrop!\\r\\nAddress: bbn1v2a65yjl5cathzl8hdysqr9xz7w503xvvu85fx\\r\\nNonce: 0f7c99f145'
{
  "eotsPublicKey": "3d0bebcbe800236ce8603c5bb1ab6c2af0932e947db4956a338f119797c37f1e",
  "babyPublicKey": "A0V6yw74EdvoAWVauFqkH/GVM9YIpZitZf6bVEzG69tT",
  "babySignature": "FKc2rpM30yfc6ivx40H/UXF9YM+yv6Bu0UrdpS+CZx1XGCdCAxkMewr3D786hx/YhBm3UBV8qhdPp86OTVrShw==",
  "babyAddress": "bbn17ew0he6svxrqj2c7mef7qsyg0assc2upa5gy7w"
}

One additional flag to the previous eotsd pop export is -message, which specifies the message to be signed. In this example it would be 'Welcome to Babylon Airdrop!\\r\\nAddress: bbn1v2a65yjl5cathzl8hdysqr9xz7w503xvvu85fx\\r\\nNonce: 0f7c99f145'.

3.3. Submit the PoP Deletion Request

The output of the eotsd pop delete command is the payload you need to submit to the API to finalize the deletion request:

curl -X DELETE 'https://airdrop-api.babylon.foundation/pop/baby-eots' \
-H 'Content-Type: application/json' \
-d '{
  "eotsPublicKey": "3d0bebcbe800236ce8603c5bb1ab6c2af0932e947db4956a338f119797c37f1e",
  "babyPublicKey": "A0V6yw74EdvoAWVauFqkH/GVM9YIpZitZf6bVEzG69tT",
  "babySignature": "FKc2rpM30yfc6ivx40H/UXF9YM+yv6Bu0UrdpS+CZx1XGCdCAxkMewr3D786hx/YhBm3UBV8qhdPp86OTVrShw==",
  "babyAddress": "bbn17ew0he6svxrqj2c7mef7qsyg0assc2upa5gy7w"
}'

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-eots?babyAddress=bbn17ew0he6svxrqj2c7mef7qsyg0assc2upa5gy7w'
[]

Now, you can submit a new PoP with a new BABY key.

Search Your Wallet Address Here

Wallet 1

bbn10rh86jtzxf7m6xqyj66s98837ry8xzsppd9c7a

Wallet 2

bbn1wq7zn8zv7n4hzwpp3058aw2aewnqqwpkrfxyf6

Wallet 3

bbn1rl5gkegkvf6sxsncgw4qenrq0eh5eha33svdug

Wallet 4

bbn18ufhwqgpxxs70884jq9f3uelsnl45da5t3uqcl

Wallet 5

bbn124jc8uvxup3g9zcjxrgds5f6dvax2fh8czj76u

Wallet 6

bbn18vjeh5c3x2q4s8at28ymqu9nhj68sp2z8fef0w

Wallet 7

bbn13x858q229e5ujw0zuretkye6fmz4hq3y2myrnh

Wallet 8

bbn14ekvxc2ck5ch5q594jggmdgh3xt54wdhtl0rwa

Wallet 9

bbn1dprn0e6hk3325vuzzaaedjx6nzne3flt08rldr

Wallet 10

bbn10p9e8gpekxx6d4d4uyknjvuzhmznxy230zyygy

Wallet 11

bbn1e8fxrv9w6h607z699yfgaatvnvsp7x3mcqct4h

Wallet 12

bbn14u2v9gltqn89q63u8jhnwvh2p0jh6k6y9hgm8l

Wallet 13

bbn1qg07l0h2hqkjuf4wpz3k7d32jsg6hrmr6efnu3

Wallet 14

bbn1kw5qtpnh2eghrtu49l92v8lzcnvl8a043v9pc4

Wallet 15

bbn1f4fzqnnw9afffmuldpa3ugfrnkmpf6k0eud96l

Wallet 16

bbn1n373grch739lspqadtfxxhzs3el65jzuntsmmy

Wallet 17

bbn1jtfee5ra8ct22sq3gclx7ht67e44n5z097mg6f

Wallet 18

bbn106wqjczqnhp8actuy3zpdnscvtqexmeeuldvkv

Wallet 19

bbn1a4whapxufv5ncct22w0m2kumh5sr59qrfgyuam

Wallet 20

bbn1cfyljtyne6m049ndujgtlaf9ddafpx4xtk76va

Wallet 21

bbn1amjplrq5q7ewz9t74jk0vvdx7rcglztuj9xlfy

Wallet 22

bbn132rz7pvhx390ruad7trvjzuhv0scd8hj9a7xnh

Wallet 23

bbn18pq536vl9zeejc0e56cp5sum90e2qlxtzmlst7

Wallet 24

bbn1r97z3fz4y774d4utfycemf03a8m3k6rs3lr4mp

Wallet 25

bbn10xjmgmzgsrr8772rd2h5cqpqgc3ma9wcfyj4xq

Wallet 26

bbn1334mztgkc5t97t4asc94t6wmk44vlczklh9zpa

Wallet 27

bbn1puzavkguwcs0st6e5tx8yxvxme0zxdckqwt6tm

Wallet 28

bbn1pmwvzdt3kqhxjmxlqdu74nn8zz3fdzrqnuf3nu

Wallet 29

bbn1sk2dfuwea943z0rdzqqqa8twjm8tmy56l4vm7s

Wallet 30

bbn1kppgtc5t2kvjgwfn5gkvulmhh9v7sppxywqca2

Wallet 31

bbn1ese6gav6w33kwecu0feraa26axhlaq7x2rh9yt

Wallet 32

bbn1ydemfukvgtkrftnrzxfqznlh0equ0wq2sg398h

Wallet 33

bbn1wvdvu63ygdstjpwvzjhlnsen77253c734zc92f

Wallet 34

bbn1xgcjmgsxa6yjmp9scluck9et6zmpywl3j7ptlc

Wallet 35

bbn1j2l2zw2peumuv6dttss7d4yz0w346syxpqhm7r

Wallet 36

bbn13fpmkujle7d2p6j8y9et85u3jq9shngfurau87

Wallet 37

bbn1fa3trycvug2l42nvwsmmrjmpaa6jzplvwfmt0w

Wallet 38

bbn1azztqetled0u5pzck3rz022pnsx23ramhlm5ds

Wallet 39

bbn16pr5l8l9yakkuupt0re2fqtkd6ajm2w8sslrcx

Wallet 40

bbn1d0qddtxg0mdh2zj0td9jp38r2zw7ueyndf2ras

Wallet 41

bbn13ycjl4sasjmzrtn6hxt4s6z9smn23c70wv2clf

Wallet 42

bbn1d8979nzt99fqjj74j2896pelz63lw6du0e465l

Wallet 43

bbn1q499ng50gt3gctdtywpre2dgv6kh80yxmfpc23

Wallet 44

bbn1nfsn0zvzusuv02g50prjvhd45amnqqhn8nlcg0

Wallet 45

bbn1lak6nldhv38pjsx32xlgswplrc9yf66c3h99ja

Wallet 46

bbn1d7jw3ply86e4kcudmlv78ask32kdp7r22l3f8l

Wallet 47

bbn14wugxz2urj4q7f7ersjx98kn4hm7fzxraclflh

Wallet 48

bbn1swyqw8nc337wj085zj2lz0tus9dnu50k78txyf

Wallet 49

bbn1ggx42rdapec973mr77pfv2x30apcw7fl7vvfda

Wallet 50

bbn175apaxz8ftcqf95xpm0jgn8r8aemggcywadnaj

Wallet 51

bbn1kgkhuw96fsart5qj0wz98979repkmflcnwle5d

Wallet 52

bbn1c3wwy7pzfsqdvskxhtwvutv7yf4jz2a24c8mgl

Wallet 53

bbn192derv4ygx2dmx6aaepurkluefukhheqd7ztxs

Wallet 54

bbn1vpefq8se8ng4mu8607l3lpzqlq5cdlw2mm85zz

Wallet 55

bbn1rr36znfay0047epyplhmtaywhwzac9kw6xk04t

Wallet 56

bbn174jrrw2hsqdj2jww2dsa3rg7y2papjls6e7knf

Wallet 57

bbn1tf92cu2nvtt9fcklnxl4mkfn4f6d4c9ls8y2g2

Wallet 58

bbn1kqvj0rzmyy2v9qtsa08gdm8jr7gc8lfm3ta44e

Wallet 59

bbn18y3ws467knzses8ku4pcutve23vfpfc6xqwrad

Wallet 60

bbn1awejwcxcm2fq4uttkqmr75040r8hn0079k4rsk

Wallet 61

bbn1g2tpjj236gulpalkt54c9gcfhh54ayr7dacg5u

Wallet 62

bbn1jdnvt9speuqp3eqvkwp0l0pk2tmvunzuhppzz6

Wallet 63

bbn1ndr908qqmfs0atazz205rq84v06g78zc9pjz62

Wallet 64

bbn1k83fut7dmspnmwyaxgvt0h38n0lnyytp67zvqw

Wallet 65

bbn1dgkwlq7p8z2r483stzuts20d8rmk7n97ettvhw

Wallet 66

bbn1l8yf5ek359dqszfy2r3frzmmcsu27nua8ce0wm

Wallet 67

bbn1ejs9evfk3aau3krz4dasdk8e5c00ms64cr2xry

Wallet 68

bbn1yffmajcszy0smt4g7ra4pqhfj5779tf3r5cvaf

Wallet 69

bbn19hx35p4y77ewdl3qcj3j65nwf60063sr4ykvew

Wallet 70

bbn1pqq9ncvfalrx46a3ru5vgr3uvdajgywarxahzp

Wallet 71

bbn1tarkqzxg7fgqrthmefdlrwurawfrsxzaqkly2l

Wallet 72

bbn15yktnc52zlyugmlydcnjln7csjvlut2c82mn0h

Wallet 73

bbn1v24m290u8kz6286d8f8tcr85ha9kqvrhs9wlh7

Wallet 74

bbn18erprsxdrjvmzpze30j52l9za7x8h9dju77ew9

Wallet 75

bbn1wfpxpppes7sh6uvy56srnvfwn9jgwg9kpyp3jx

Wallet 76

bbn1y47aut2y9vmgy3hshzu8g9y823qa76xraqfw98

Wallet 77

bbn177mtk089uemq5u48wwpwagx2gm366kwchw0f6f

Wallet 78

bbn1957xsfazc4we7k0gqu44fyu4gg7gl75zy3gqk4

Wallet 79

bbn18f58pllscysfp6w3eswalsdg8gputk8gmt2cgh

Wallet 80

bbn14f3gx0sdjfz4x5kedllgl6d6rcq0w54lfwq7jw

Wallet 81

bbn1cfc55nny67xld0s84n0dqrfn7m2p3zsk7nu0a8

Wallet 82

bbn1nlxqx29eesv8wculyucju78ycz44z94557ekal

Wallet 83

bbn16r30du375ew82c6qy2h98rp7gep49tn0gjp5jt

Wallet 84

bbn165acjr45aje464yc06ff4snmuhl242najp3kap

Wallet 85

bbn1gss7c798p8256etftxfwv7j3nptf6z6g8773jj

Wallet 86

bbn136ux5m72glkwdnr09p2uwvpsywqx2yrc6ndql6

Wallet 87

bbn1cnxz0qlnrkmf4mxuf8ae8a6v4lt5ua8wp30k7g

Wallet 88

bbn19zq3gdp0dkza7arm32tmm205e3vcjq0dmjlywt

Wallet 89

bbn1g6arx4d3hpwshf8zs23pnhs0km5ktzs5pew6f5

Wallet 90

bbn1v7sw3fckp4mkd4uq3576ekyx5gr6yaqz55xsup

Wallet 91

bbn189nl335lcc90u0sga9dn5a73grx2ucql9mya9t

Wallet 92

bbn1q45eg648gpvvwsymuag6gpqkgmj9wuvg7dnfw4

Wallet 93

bbn1ld9cu7fnmmgjafq2s4r34hzqlzd8p8qwuvnvnn

Wallet 94

bbn1ww9yc58e0df2wfy8pk0hc5xw5w9qt2n50d63t8

Wallet 95

bbn18fehsvf75yz0nq7xf7r453qdxt8u38kre254ya

Wallet 96

bbn136ha68u7ug5ujj8xun8mst6z84tfv397xtqnte

Wallet 97

bbn1j40n4aacyg2skalj3kl4a5rpd2sp02r7f84neq

Wallet 98

bbn12c4wpycefle09md692mgf5wn8wmw5dnc6euwa9

Wallet 99

bbn1dm79tnzpd4k8g8r66evsn2qhmvh8w2eq3yantr

Wallet 100

bbn1s3qg9wvmey602qavdfa4l4e9hpfc3234qvc00d