mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-03 12:06:17 -04:00
Upgrade CLI for mainnet test
This commit is contained in:
parent
9d564b73bf
commit
03b8e5f52e
16 changed files with 478 additions and 59 deletions
|
@ -20,6 +20,7 @@ genawaiter = "0.99.1"
|
|||
miniscript = { version = "4", features = ["serde"] }
|
||||
monero = { version = "0.9", features = ["serde_support"] }
|
||||
rand = "0.7"
|
||||
rust_decimal = "1.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
sha2 = "0.9"
|
||||
thiserror = "1"
|
||||
|
|
|
@ -15,7 +15,14 @@ pub use bitcoin::{util::psbt::PartiallySignedTransaction, *};
|
|||
pub use ecdsa_fun::{adaptor::EncryptedSignature, fun::Scalar, Signature};
|
||||
pub use transactions::{TxCancel, TxLock, TxPunish, TxRedeem, TxRefund};
|
||||
|
||||
pub const TX_FEE: u64 = 10_000;
|
||||
// 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 {
|
||||
|
@ -212,6 +219,11 @@ 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();
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::bitcoin::{
|
||||
build_shared_output_descriptor, verify_sig, BuildTxLockPsbt, OutPoint, PublicKey, Txid, TX_FEE,
|
||||
build_shared_output_descriptor, verify_sig, BuildTxLockPsbt, Network, OutPoint, PublicKey,
|
||||
Txid, TX_FEE,
|
||||
};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bitcoin::{
|
||||
util::{bip143::SigHashCache, psbt::PartiallySignedTransaction},
|
||||
Address, Amount, Network, SigHash, SigHashType, Transaction, TxIn, TxOut,
|
||||
Address, Amount, SigHash, SigHashType, Transaction, TxIn, TxOut,
|
||||
};
|
||||
use ecdsa_fun::Signature;
|
||||
use miniscript::{Descriptor, NullCtx};
|
||||
|
@ -20,11 +21,11 @@ pub struct TxLock {
|
|||
impl TxLock {
|
||||
pub async fn new<W>(wallet: &W, amount: Amount, A: PublicKey, B: PublicKey) -> Result<Self>
|
||||
where
|
||||
W: BuildTxLockPsbt,
|
||||
W: BuildTxLockPsbt + Network,
|
||||
{
|
||||
let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0);
|
||||
let address = lock_output_descriptor
|
||||
.address(Network::Regtest, NullCtx)
|
||||
.address(wallet.get_network(), NullCtx)
|
||||
.expect("can derive address from descriptor");
|
||||
|
||||
// We construct a psbt for convenience
|
||||
|
|
|
@ -33,7 +33,7 @@ use tracing::error;
|
|||
|
||||
pub mod message;
|
||||
use crate::{
|
||||
bitcoin::{BlockHeight, GetRawTransaction, TransactionBlockHeight},
|
||||
bitcoin::{BlockHeight, GetRawTransaction, Network, TransactionBlockHeight},
|
||||
monero::{CreateWalletForOutput, WatchForTransfer},
|
||||
};
|
||||
use ::bitcoin::{Transaction, Txid};
|
||||
|
@ -267,7 +267,7 @@ where
|
|||
// send to one receive in the correct order.
|
||||
pub async fn next_state<
|
||||
R: RngCore + CryptoRng,
|
||||
B: WatchForRawTransaction + SignTxLock + BuildTxLockPsbt + BroadcastSignedTransaction,
|
||||
B: WatchForRawTransaction + SignTxLock + BuildTxLockPsbt + BroadcastSignedTransaction + Network,
|
||||
M: CreateWalletForOutput + WatchForTransfer,
|
||||
T: SendMessage<Message> + ReceiveMessage<alice::Message>,
|
||||
>(
|
||||
|
@ -401,7 +401,7 @@ impl State0 {
|
|||
|
||||
pub async fn receive<W>(self, wallet: &W, msg: alice::Message0) -> anyhow::Result<State1>
|
||||
where
|
||||
W: BuildTxLockPsbt,
|
||||
W: BuildTxLockPsbt + Network,
|
||||
{
|
||||
msg.dleq_proof_s_a.verify(
|
||||
msg.S_a_bitcoin.clone().into(),
|
||||
|
|
|
@ -9,6 +9,7 @@ pub struct Config {
|
|||
pub monero_max_finality_time: Duration,
|
||||
pub bitcoin_refund_timelock: u32,
|
||||
pub bitcoin_punish_timelock: u32,
|
||||
pub bitcoin_network: ::bitcoin::Network,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
@ -23,6 +24,7 @@ impl Config {
|
|||
* mainnet::MONERO_FINALITY_CONFIRMATIONS,
|
||||
bitcoin_refund_timelock: mainnet::BITCOIN_REFUND_TIMELOCK,
|
||||
bitcoin_punish_timelock: mainnet::BITCOIN_PUNISH_TIMELOCK,
|
||||
bitcoin_network: ::bitcoin::Network::Bitcoin,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,6 +39,7 @@ impl Config {
|
|||
* regtest::MONERO_FINALITY_CONFIRMATIONS,
|
||||
bitcoin_refund_timelock: regtest::BITCOIN_REFUND_TIMELOCK,
|
||||
bitcoin_punish_timelock: regtest::BITCOIN_PUNISH_TIMELOCK,
|
||||
bitcoin_network: ::bitcoin::Network::Regtest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,17 @@ use rand::{CryptoRng, RngCore};
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::{Add, Mul, Sub};
|
||||
|
||||
use bitcoin::hashes::core::fmt::Formatter;
|
||||
pub use curve25519_dalek::scalar::Scalar;
|
||||
pub use monero::*;
|
||||
use rust_decimal::{
|
||||
prelude::{FromPrimitive, ToPrimitive},
|
||||
Decimal,
|
||||
};
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
pub const MIN_CONFIRMATIONS: u32 = 10;
|
||||
pub const PICONERO_OFFSET: u64 = 1_000_000_000_000;
|
||||
|
||||
pub fn random_private_key<R: RngCore + CryptoRng>(rng: &mut R) -> PrivateKey {
|
||||
let scalar = Scalar::random(rng);
|
||||
|
@ -76,9 +83,20 @@ impl Amount {
|
|||
pub fn from_piconero(amount: u64) -> Self {
|
||||
Amount(amount)
|
||||
}
|
||||
|
||||
pub fn as_piconero(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn parse_monero(amount: &str) -> Result<Self> {
|
||||
let decimal = Decimal::from_str(amount)?;
|
||||
let piconeros_dec =
|
||||
decimal.mul(Decimal::from_u64(PICONERO_OFFSET).expect("constant to fit into u64"));
|
||||
let piconeros = piconeros_dec
|
||||
.to_u64()
|
||||
.ok_or_else(|| OverflowError(amount.to_owned()))?;
|
||||
Ok(Amount(piconeros))
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Amount {
|
||||
|
@ -111,6 +129,16 @@ impl From<Amount> for u64 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Display for Amount {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let mut decimal = Decimal::from(self.0);
|
||||
decimal
|
||||
.set_scale(12)
|
||||
.expect("12 is smaller than max precision of 28");
|
||||
write!(f, "{} XMR", decimal)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct TransferProof {
|
||||
tx_hash: TxHash,
|
||||
|
@ -177,3 +205,70 @@ pub trait CreateWalletForOutput {
|
|||
private_view_key: PrivateViewKey,
|
||||
) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq)]
|
||||
#[error("Overflow, cannot convert {0} to u64")]
|
||||
pub struct OverflowError(pub String);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn display_monero_min() {
|
||||
let min_pics = 1;
|
||||
let amount = Amount::from_piconero(min_pics);
|
||||
let monero = amount.to_string();
|
||||
assert_eq!("0.000000000001 XMR", monero);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_monero_one() {
|
||||
let min_pics = 1000000000000;
|
||||
let amount = Amount::from_piconero(min_pics);
|
||||
let monero = amount.to_string();
|
||||
assert_eq!("1.000000000000 XMR", monero);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_monero_max() {
|
||||
let max_pics = 18_446_744_073_709_551_615;
|
||||
let amount = Amount::from_piconero(max_pics);
|
||||
let monero = amount.to_string();
|
||||
assert_eq!("18446744.073709551615 XMR", monero);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_monero_min() {
|
||||
let monero_min = "0.000000000001";
|
||||
let amount = Amount::parse_monero(monero_min).unwrap();
|
||||
let pics = amount.0;
|
||||
assert_eq!(1, pics);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_monero() {
|
||||
let monero = "123";
|
||||
let amount = Amount::parse_monero(monero).unwrap();
|
||||
let pics = amount.0;
|
||||
assert_eq!(123000000000000, pics);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_monero_max() {
|
||||
let monero = "18446744.073709551615";
|
||||
let amount = Amount::parse_monero(monero).unwrap();
|
||||
let pics = amount.0;
|
||||
assert_eq!(18446744073709551615, pics);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_monero_overflows() {
|
||||
let overflow_pics = "18446744.073709551616";
|
||||
let error = Amount::parse_monero(overflow_pics).unwrap_err();
|
||||
assert_eq!(
|
||||
error.downcast_ref::<OverflowError>().unwrap(),
|
||||
&OverflowError(overflow_pics.to_owned())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ use reqwest::Url;
|
|||
use std::time::Duration;
|
||||
use tokio::time;
|
||||
use xmr_btc::bitcoin::{
|
||||
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, SignTxLock, TransactionBlockHeight,
|
||||
TxLock, WatchForRawTransaction,
|
||||
BlockHeight, BroadcastSignedTransaction, BuildTxLockPsbt, Network, SignTxLock,
|
||||
TransactionBlockHeight, TxLock, WatchForRawTransaction,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -162,3 +162,9 @@ impl TransactionBlockHeight for Wallet {
|
|||
.expect("transient errors to be retried")
|
||||
}
|
||||
}
|
||||
|
||||
impl Network for Wallet {
|
||||
fn get_network(&self) -> bitcoin::Network {
|
||||
bitcoin::Network::Regtest
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue