The wallet module allows users to peg-in or peg-out from the fed using on-chain bitcoin transactions.
- WalletClient::get_new_pegin_address - the user client generates a new peg-in address by creating a random private/public key pair, and tweaking the fed's public multisig with the random public key.
- Next the user sends an on-chain bitcoin transaction to the generated peg-in address using whatever wallet software they prefer.
- WalletClient::create_pegin_input - after sending bitcoin on-chain to the address, the client sends a
PegInProof
to the fed which includes the public key tweak that allows the federation to spend the UTXO, and signs the transaction using the private key tweak to prove they sent the bitcoin.
let address = user_client.get_new_pegin_address();
let (txout_proof, btc_transaction) = bitcoin.send(&address, amount);
let (keys, proof) = user_client.create_pegin_input(txout_proof, btc_transaction);
tx.input(keys, proof);
user_client.submit_tx_with_change(tx);
Using a public key tweak instead of querying the federation for a new address avoids an unnecessary request to the federation and allows a client to prove they sent bitcoin by signing a message.
- Wallet::validate_input - verifies that the
PegInProof
is in a block and is spendable by the federation's multisig. - Wallet::apply_input - stores the
SpendableUTXO
containing the transaction details and tweak key in the federation's wallet database. - Wallet::begin_consensus_epoch - determines the
RoundConsensus
containing the consensus block height which is delayed by a configurablefinalty_delay
of 10 blocks after which peg-ins accepted.
- Client::new_peg_out_with_fees - creates a new
PegOut
for users by requesting the current peg-out fees from the fed's wallet API which is estimated based on the on-chain size of the transaction and the sats/byte to confirm in aCONFIRMATION_TARGET
of 10 blocks. - Client::peg_out - submits a transaction to the fed to spend input ecash and receive bitcoin on-chain.
let peg_out = user_client.new_peg_out_with_fees(amount, address);
if (peg_out.fees < user_configured_amount) {
user_client.peg_out(peg_out);
}
- Wallet::validate_output - verifies the address is valid, the fees are high enough, and the federation has enough
SpendableUTXO
to create the transaction. - Wallet::apply_output - generates a PSBT (partially signed bitcoin transaction) with a signature and removes UTXOs so they are not double-spent.
- Wallet::consensus_proposal - proposes the PSBT and the
RoundConsensus
containing the block height, peg-out fees, and randomness beacon (tweak for receiving peg-out change) as new consensus items. - Wallet::end_consensus_epoch - if all peers behave properly they will have submitted PSBT signatures which can be combined into a final
PendingTransaction
. - run_broadcast_pending_tx - is a thread that will periodically look broadcast any pending transactions.
In the future there are a number of improvements we could make:
- Allow for users to bump their transaction fees using RBF if the transactions are stuck
- Aggregate transactions to reduce the total fees paid (or lower the min sat/byte)
- Make the multisig a taproot UTXO, saving on fees, adding privacy, and allowing for federations beyond 20 peers