Assessment reports>Babylon Chain>Threat Model>Transaction generation and signing

Transaction generation and signing

Specification

Transaction types

Babylon makes use of two transaction-output types: staking outputs and unbonding outputs.

  1. Staking outputs commit to a taproot disjunction of three possible execution paths.

  • The timelock path, which requires the staker's signature and also requires a certain number of blocks to pass.

  • The unbonding path, which requires the staker's signature as well as a threshold of covenant emulation committee signatures.

  • The slashing path, which requires the staker's signature, the finality provider's signature, and a threshold of covenant emulation committee signatures.

  1. Unbonding outputs commit to a taproot disjunction of two possible execution paths.

  • The timelock path, similar to the staking output's (but with a shorter duration in blocks than the staking output's timelock path).

  • The slashing path, with identical requirements to the staking output's slashing path.

Miniscript formulations

The different taproot script paths can be described in the miniscript language as follows:

  • Timelock path: and_v(vc:pk_k(staker_pk), older(timelock_blocks))

  • Unbonding path: and_v(vc:pk_k(staker_pk), multi_a(covenant_threshold, covenant_pk1, ..., covenant_pkn))

  • Slashing path: and_v(vc:pk_k(staker_pk), and_v(vc:pk_k(finalityprovider_pk), multi_a(covenant_threshold, covenant_pk1, ..., covenant_pkn)))

Security properties

The staking and unbonding transactions, along with their bitcoin scripts, have a few security properties. These are:

  • The timelock paths ensure that the system is fail-safe, in the sense that if all Babylon infrastructure ceases operating, the staker can eventually reclaim their stake with just the Bitcoin network.

  • The covenant emulation committee signatures on the slashing path allow the committee to enforce that slashing transactions have additional structure — that they send a specified percentage of the input to an unspendable burn address and the remainder to a change address controlled by the staker.

  • The staker and covenant emulation committee signatures provide defense-in-depth against slashing occurring in Phase 1. Phase 1 signing flows do not require the slashing path to be presigned by the staker, and covenant-signer (the Phase 1 counterpart to covenant-emulator) only signs unbonding paths.

  • The finality provider's key is used to sign proof-of-stake blocks using EOTS, which leak the key on equivocation (i.e., validator misbehavior). In Phase 2, stake is only considered active once the corresponding slashing path has been presigned by the staker and covenant emulation committee, which allow anyone to submit the slashing transaction upon validator misbehavior.

  • The covenant signatures on the slashing path are adaptor signatures encrypted towards each finality provider to enforce atomic slashing (i.e., that anyone can ensure that if at least one delegator to a finality provider is slashed, all delegators to that finality provider are slashed).

babylon/btcstaking

The btcstaking library contains methods that construct and sign transactions in accordance with the aforementioned specification.

  • newBabylonScriptPaths, called by BuildStakingInfo (for the staking output) and BuildUnbondingInfo (for the unbonding output), builds all three paths.

  • buildTimeLockScript builds the timelock path, with lockTime as a parameter (see Finding ref).

  • buildSingleKeySigScript and buildMultiSigScript are used to build individual signature-checking scripts and m-of-n multi-sig--checking scripts.

  • In newBabylonScriptPaths, unbondingPathScript requires the staker's signature (via stakerKey) and covenantQuorum of the covenant signatures (from the set covenantKeys).

  • In newBabylonScriptPaths, slashingPathScript requires the staker's signature, one finality-provider signature (from a set of fpKeys), and covenantQuorum of the covenant signatures.

  • SignTxWithOneScriptSpendInputFromTapLeaf signs Bitcoin transactions.

  • EncSignTxWithOneScriptSpendInputStrict signs Bitcoin transactions as adaptor signatures (where either the signature or the encryption private key can be recovered from the other).

  • ValidateSlashingTx ensures (among other properties) that a candidate slashing transaction has the expected slashing and change outputs.

  • BuildV0IdentifiableStakingOutputsAndTx constructs an unsigned partial transaction with no inputs and a staking output and OP_RETURN output with metadata.

  • ParseV0StakingTx validates that an existing transaction is a staking transaction.

btc-staking-ts

The btc-staking-ts library contains methods that construct staking, unbonding, and slashing and sign transactions in accordance with the aforementioned specification.

  • stakingTransaction generates an unsigned BTC staking transaction in PSBT format. The output includes an unsigned PSBT with the staking script, change, and optional data embed script, along with the total transaction fee.

  • withdrawTimelockUnbondedTransaction generates transactions to withdraw unbonded staking funds. They call the withdrawalTransaction function to create the actual transaction.

  • unbondingTransaction generates a transaction that converts staking funds to an unbonding state. It just returns PBST, needs to be signed with signTransaction or createWitness, and signs transactions by using BIP-0332. The staking script allows users to, on-demand, unbond their locked stake before the staking-transaction time lock expires, subject to an unbonding period.

  • createWitness creates a witness for use in an unbonding transaction in PSBT format as, apart from the staker’s signature, it also needs a set of signatures from the covenant emulation committee. It combines the original witness data with covenant-related data to generate a new witness.

  • slashingTransaction generates a transaction that sends a portion of the staking funds to a slashing address and returns the remainder to the user when slashing conditions are met. The output consists of two transactions: one sending a portion of the input funds (input * slashing_rate) to the slashing address and the other sending the remaining input funds minus fee (input * (1-slashing_rate) - fee) back to the user's address.

  • withdrawal generates a transaction that consumes the staking output to withdraw funds.

  • buildSingleKeyScript and buildMultiKeyScript allow us to reuse functionality for creating Bitcoin scripts for the unbonding script and the slashing script.

  • buildMultiKeyScript uses BIP-0342 (Tapscript) to build multikey scripts. It validates whether provided keys are unique and the threshold is not greater than the number of keys. If there is only one key provided, it will return single-key--sig script. It checks that the key must be sorted and verifies there are no duplicates.

cli-tools

The cli-tools binary contains several commands relevant to transactions:

  • create-phase1-staking-tx, which uses btcstaking.BuildV0IdentifiableStakingOutputsAndTx to produce an unsigned partial staking transaction (to be completed with bitcoind's fundrawtransaction and signrawtransactionwithwallet commands)

  • create-phase1-unbonding-request, which creates and signs (with the staker's key) an unbonding transaction, given information on the corresponding staking transaction

  • create-phase1-withdaw-request, which creates and signs (with the staker's key) a timelock path of either a staking or an unbonding transaction

  • run-unbonding-pipeline, which retrieves unbonding transactions from a MongoDB instance populated by staking-api-service and sends them to covenant-signer to attach covenant emulation committee signatures.

simple-staking

The simple-staking is a front-end dApp for creating Bitcoin staking transactions. It integrates with a set of extension wallets satisfying its expected interface. It is hosted by Babylon and serves as a reference implementation for entities that want to set up their own staking website. This uses btc-staking-ts for constructing staking/unbonding transactions, signs through extension wallets imported, then submits to staking-api.

btc-staker

The staker-cli command contains the following Phase 1 commands under the transaction subcommand:

  • check-phase1-staking-transaction validates a staking transaction with btcstaking.ParseV0StakingTx and optionally checks that provided additional data matches.

  • create-phase1-staking-transaction creates an unsigned partial staking transaction with btcstaking.BuildV0IdentifiableStakingOutputsAndTx, similarly to cli tools create-phase1-staking-tx.

  • create-phase1-unbonding-transaction creates a BIP174 PSBT for an unbonding transaction, given the corresponding staking transaction to be used as input.

  • create-phase1-staking-transaction-json is similar to create-phase1-staking-transaction but takes its parameters through a JSON file instead of via CLI arguments.

The stakerd service contains behavior relevant to Phase 2, including automatically synchronizing state between the Bitcoin and Babylon chains and signing slashing transactions for staking transactions that have been processed by Bitcoin but that are not yet recognized as delegations by Babylon.

covenant-signer

The covenant-signer service exposes a "/v1/sign-unbonding-tx" route that provides covenant emulation committee signatures for unbonding transactions whose parameters are in bounds, whose only input is a staking output (that parses according to btcstaking.ParseV0StakingTx) that has sufficient confirmation depth on the Bitcoin blockchain, and whose only output is equal to an unbonding output reconstructed from the staking output's information. The covenant-signer service does not sign slashing transactions, which mitigates the risk of Phase 1 slashing.

covenant-emulator

The covenant-emulator service is a Phase 2 service. It periodically queries for new delegations on Babylon and provides covenant signatures for the slashing and unbonding transactions for each delegation. There are checks performed to ensure that these transactions are valid (for example, the unbonding transaction's minimum unbonding time must be correct).

staking-indexer

The staking-indexer service scans the Bitcoin blockchain for staking, unbonding, and withdrawal (i.e., timelock path) transactions that have the expected structure and that their values are in bounds (including checking statefully that the total stake does not exceed a parameterized cap) and forwards them as {ActiveStakingEvent,UnbondingStakingEvent,WithdrawStakingEvent}s to the queue.

staking-api-service

The staking-api-service service provides several HTTP GET endpoints that simple-staking uses to display the state of Babylon as well as a POST endpoint that is used to initiate unbonding (which saves the provided transactions and staker signature to the MongoDB table to be read by unbonding-pipeline). It also receives messages from the various queues, keeping its database state in sync with the Babylon and Bitcoin chains.

staking-expiry-checker

The staking-expiry-checker service connects to the same MongoDB instance as staking-api-service, which has a table of staking transactions together with the heights they will expire at. It retrieves transactions that have expired by the current height according to a Bitcoin client and submits ExpiredStakingEvents to the queue for them, removing them from the database upon successful queue submission.

vigilante

The vigilante consists of four subcomponents. The submitter component handles submission of Babylon checkpoints to Bitcoin. The reporter component handles submission of Bitcoin headers and confirmed Babylon checkpoint submissions to Babylon itself. The monitor component monitors for censorship of Babylon checkpoints (along with a liveness checker to detect liveness attacks on Babylon). Finally, the btcstaking-tracker handles slashing malicious finality providers and automatically submitting unbonding delegations to Babylon.

finality-provider

The finality-provider is a service that all Babylon validators are supposed to run. This service automatically commits public randomness numbers to each Babylon block and subsequently provides finality signatures for each block. A block can only achieve finality once enough finality-provider signatures have been collected to achieve quorum.

Zellic © 2025Back to top ↑