mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-01-24 06:11:14 -05:00
Delete leftover xmr_btc crate
This commit is contained in:
parent
dcea54dbf1
commit
a3e896684c
@ -1,285 +0,0 @@
|
|||||||
mod timelocks;
|
|
||||||
pub mod transactions;
|
|
||||||
|
|
||||||
use crate::{config::Config, ExpiredTimelocks};
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
|
||||||
use async_trait::async_trait;
|
|
||||||
use bitcoin::hashes::{hex::ToHex, Hash};
|
|
||||||
use ecdsa_fun::{adaptor::Adaptor, fun::Point, nonce::Deterministic, ECDSA};
|
|
||||||
use miniscript::{Descriptor, Segwitv0};
|
|
||||||
use rand::{CryptoRng, RngCore};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use sha2::Sha256;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
pub use bitcoin::{util::psbt::PartiallySignedTransaction, *};
|
|
||||||
pub use ecdsa_fun::{adaptor::EncryptedSignature, fun::Scalar, Signature};
|
|
||||||
pub use timelocks::*;
|
|
||||||
pub use transactions::{TxCancel, TxLock, TxPunish, TxRedeem, TxRefund};
|
|
||||||
|
|
||||||
// TODO: Configurable tx-fee (note: parties have to agree prior to swapping)
|
|
||||||
// Current reasoning:
|
|
||||||
// tx with largest weight (as determined by get_weight() upon broadcast in e2e
|
|
||||||
// test) = 609 assuming segwit and 60 sat/vB:
|
|
||||||
// (609 / 4) * 60 (sat/vB) = 9135 sats
|
|
||||||
// Recommended: Overpay a bit to ensure we don't have to wait too long for test
|
|
||||||
// runs.
|
|
||||||
pub const TX_FEE: u64 = 15_000;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
|
|
||||||
pub struct SecretKey {
|
|
||||||
inner: Scalar,
|
|
||||||
public: Point,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SecretKey {
|
|
||||||
pub fn new_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
|
||||||
let scalar = Scalar::random(rng);
|
|
||||||
|
|
||||||
let ecdsa = ECDSA::<()>::default();
|
|
||||||
let public = ecdsa.verification_key_for(&scalar);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
inner: scalar,
|
|
||||||
public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn public(&self) -> PublicKey {
|
|
||||||
PublicKey(self.public)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> [u8; 32] {
|
|
||||||
self.inner.to_bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign(&self, digest: SigHash) -> Signature {
|
|
||||||
let ecdsa = ECDSA::<Deterministic<Sha256>>::default();
|
|
||||||
|
|
||||||
ecdsa.sign(&self.inner, &digest.into_inner())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxRefund encsigning explanation:
|
|
||||||
//
|
|
||||||
// A and B, are the Bitcoin Public Keys which go on the joint output for
|
|
||||||
// TxLock_Bitcoin. S_a and S_b, are the Monero Public Keys which go on the
|
|
||||||
// joint output for TxLock_Monero
|
|
||||||
|
|
||||||
// tx_refund: multisig(A, B), published by bob
|
|
||||||
// bob can produce sig on B for tx_refund using b
|
|
||||||
// alice sends over an encrypted signature on A for tx_refund using a encrypted
|
|
||||||
// with S_b we want to leak s_b
|
|
||||||
|
|
||||||
// produced (by Alice) encsig - published (by Bob) sig = s_b (it's not really
|
|
||||||
// subtraction, it's recover)
|
|
||||||
|
|
||||||
// self = a, Y = S_b, digest = tx_refund
|
|
||||||
pub fn encsign(&self, Y: PublicKey, digest: SigHash) -> EncryptedSignature {
|
|
||||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
|
||||||
|
|
||||||
adaptor.encrypted_sign(&self.inner, &Y.0, &digest.into_inner())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct PublicKey(Point);
|
|
||||||
|
|
||||||
impl From<PublicKey> for Point {
|
|
||||||
fn from(from: PublicKey) -> Self {
|
|
||||||
from.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Scalar> for SecretKey {
|
|
||||||
fn from(scalar: Scalar) -> Self {
|
|
||||||
let ecdsa = ECDSA::<()>::default();
|
|
||||||
let public = ecdsa.verification_key_for(&scalar);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
inner: scalar,
|
|
||||||
public,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<SecretKey> for Scalar {
|
|
||||||
fn from(sk: SecretKey) -> Self {
|
|
||||||
sk.inner
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Scalar> for PublicKey {
|
|
||||||
fn from(scalar: Scalar) -> Self {
|
|
||||||
let ecdsa = ECDSA::<()>::default();
|
|
||||||
PublicKey(ecdsa.verification_key_for(&scalar))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn verify_sig(
|
|
||||||
verification_key: &PublicKey,
|
|
||||||
transaction_sighash: &SigHash,
|
|
||||||
sig: &Signature,
|
|
||||||
) -> Result<()> {
|
|
||||||
let ecdsa = ECDSA::verify_only();
|
|
||||||
|
|
||||||
if ecdsa.verify(&verification_key.0, &transaction_sighash.into_inner(), &sig) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!(InvalidSignature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, thiserror::Error)]
|
|
||||||
#[error("signature is invalid")]
|
|
||||||
pub struct InvalidSignature;
|
|
||||||
|
|
||||||
pub fn verify_encsig(
|
|
||||||
verification_key: PublicKey,
|
|
||||||
encryption_key: PublicKey,
|
|
||||||
digest: &SigHash,
|
|
||||||
encsig: &EncryptedSignature,
|
|
||||||
) -> Result<()> {
|
|
||||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
|
||||||
|
|
||||||
if adaptor.verify_encrypted_signature(
|
|
||||||
&verification_key.0,
|
|
||||||
&encryption_key.0,
|
|
||||||
&digest.into_inner(),
|
|
||||||
&encsig,
|
|
||||||
) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
bail!(InvalidEncryptedSignature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, thiserror::Error)]
|
|
||||||
#[error("encrypted signature is invalid")]
|
|
||||||
pub struct InvalidEncryptedSignature;
|
|
||||||
|
|
||||||
pub fn build_shared_output_descriptor(A: Point, B: Point) -> Descriptor<bitcoin::PublicKey> {
|
|
||||||
const MINISCRIPT_TEMPLATE: &str = "c:and_v(v:pk(A),pk_k(B))";
|
|
||||||
|
|
||||||
// NOTE: This shouldn't be a source of error, but maybe it is
|
|
||||||
let A = ToHex::to_hex(&secp256k1::PublicKey::from(A));
|
|
||||||
let B = ToHex::to_hex(&secp256k1::PublicKey::from(B));
|
|
||||||
|
|
||||||
let miniscript = MINISCRIPT_TEMPLATE.replace("A", &A).replace("B", &B);
|
|
||||||
|
|
||||||
let miniscript = miniscript::Miniscript::<bitcoin::PublicKey, Segwitv0>::from_str(&miniscript)
|
|
||||||
.expect("a valid miniscript");
|
|
||||||
|
|
||||||
Descriptor::Wsh(miniscript)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait BuildTxLockPsbt {
|
|
||||||
async fn build_tx_lock_psbt(
|
|
||||||
&self,
|
|
||||||
output_address: Address,
|
|
||||||
output_amount: Amount,
|
|
||||||
) -> Result<PartiallySignedTransaction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait SignTxLock {
|
|
||||||
async fn sign_tx_lock(&self, tx_lock: TxLock) -> Result<Transaction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait BroadcastSignedTransaction {
|
|
||||||
async fn broadcast_signed_transaction(&self, transaction: Transaction) -> Result<Txid>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait WatchForRawTransaction {
|
|
||||||
async fn watch_for_raw_transaction(&self, txid: Txid) -> Transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait WaitForTransactionFinality {
|
|
||||||
async fn wait_for_transaction_finality(&self, txid: Txid, config: Config) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait GetBlockHeight {
|
|
||||||
async fn get_block_height(&self) -> BlockHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait TransactionBlockHeight {
|
|
||||||
async fn transaction_block_height(&self, txid: Txid) -> BlockHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait WaitForBlockHeight {
|
|
||||||
async fn wait_for_block_height(&self, height: BlockHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait GetRawTransaction {
|
|
||||||
async fn get_raw_transaction(&self, txid: Txid) -> Result<Transaction>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
pub trait Network {
|
|
||||||
fn get_network(&self) -> bitcoin::Network;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
|
|
||||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
|
||||||
|
|
||||||
let s = adaptor
|
|
||||||
.recover_decryption_key(&S.0, &sig, &encsig)
|
|
||||||
.map(SecretKey::from)
|
|
||||||
.ok_or_else(|| anyhow!("secret recovery failure"))?;
|
|
||||||
|
|
||||||
Ok(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn poll_until_block_height_is_gte<B>(client: &B, target: BlockHeight)
|
|
||||||
where
|
|
||||||
B: GetBlockHeight,
|
|
||||||
{
|
|
||||||
while client.get_block_height().await < target {
|
|
||||||
tokio::time::delay_for(std::time::Duration::from_secs(1)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn current_epoch<W>(
|
|
||||||
bitcoin_wallet: &W,
|
|
||||||
cancel_timelock: Timelock,
|
|
||||||
punish_timelock: Timelock,
|
|
||||||
lock_tx_id: ::bitcoin::Txid,
|
|
||||||
) -> anyhow::Result<ExpiredTimelocks>
|
|
||||||
where
|
|
||||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
|
||||||
{
|
|
||||||
let current_block_height = bitcoin_wallet.get_block_height().await;
|
|
||||||
let lock_tx_height = bitcoin_wallet.transaction_block_height(lock_tx_id).await;
|
|
||||||
let cancel_timelock_height = lock_tx_height + cancel_timelock;
|
|
||||||
let punish_timelock_height = cancel_timelock_height + punish_timelock;
|
|
||||||
|
|
||||||
match (
|
|
||||||
current_block_height < cancel_timelock_height,
|
|
||||||
current_block_height < punish_timelock_height,
|
|
||||||
) {
|
|
||||||
(true, _) => Ok(ExpiredTimelocks::None),
|
|
||||||
(false, true) => Ok(ExpiredTimelocks::Cancel),
|
|
||||||
(false, false) => Ok(ExpiredTimelocks::Punish),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn wait_for_cancel_timelock_to_expire<W>(
|
|
||||||
bitcoin_wallet: &W,
|
|
||||||
cancel_timelock: Timelock,
|
|
||||||
lock_tx_id: ::bitcoin::Txid,
|
|
||||||
) -> Result<()>
|
|
||||||
where
|
|
||||||
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
|
||||||
{
|
|
||||||
let tx_lock_height = bitcoin_wallet.transaction_block_height(lock_tx_id).await;
|
|
||||||
|
|
||||||
poll_until_block_height_is_gte(bitcoin_wallet, tx_lock_height + cancel_timelock).await;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::ops::Add;
|
|
||||||
|
|
||||||
/// Represent a timelock, expressed in relative block height as defined in
|
|
||||||
/// [BIP68](https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki).
|
|
||||||
/// E.g. The timelock expires 10 blocks after the reference transaction is
|
|
||||||
/// mined.
|
|
||||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct Timelock(u32);
|
|
||||||
|
|
||||||
impl Timelock {
|
|
||||||
pub const fn new(number_of_blocks: u32) -> Self {
|
|
||||||
Self(number_of_blocks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Timelock> for u32 {
|
|
||||||
fn from(timelock: Timelock) -> Self {
|
|
||||||
timelock.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represent a block height, or block number, expressed in absolute block
|
|
||||||
/// count. E.g. The transaction was included in block #655123, 655123 block
|
|
||||||
/// after the genesis block.
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)]
|
|
||||||
#[serde(transparent)]
|
|
||||||
pub struct BlockHeight(u32);
|
|
||||||
|
|
||||||
impl From<BlockHeight> for u32 {
|
|
||||||
fn from(height: BlockHeight) -> Self {
|
|
||||||
height.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockHeight {
|
|
||||||
pub const fn new(block_height: u32) -> Self {
|
|
||||||
Self(block_height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<Timelock> for BlockHeight {
|
|
||||||
type Output = BlockHeight;
|
|
||||||
|
|
||||||
fn add(self, rhs: Timelock) -> Self::Output {
|
|
||||||
BlockHeight(self.0 + rhs.0)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user