mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2024-10-01 01:45:40 -04:00
Merge #225
225: Asb refund reload main wallet r=da-kami a=da-kami Fixes #211 Please review by commit and read the commit messages. Co-authored-by: Daniel Karzel <daniel@comit.network>
This commit is contained in:
commit
74352ee136
137
Cargo.lock
generated
137
Cargo.lock
generated
@ -614,6 +614,22 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a89e2ae426ea83155dccf10c0fa6b1463ef6d5fcb44cee0b224a408fa640a62"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b"
|
||||
|
||||
[[package]]
|
||||
name = "cpuid-bool"
|
||||
version = "0.1.2"
|
||||
@ -994,6 +1010,21 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.0.0"
|
||||
@ -1984,6 +2015,24 @@ dependencies = [
|
||||
"unsigned-varint 0.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8d96b2e1c8da3957d58100b09f102c6d9cfdfced01b7ec5a8974044bb09dbd4"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb-connect"
|
||||
version = "1.0.2"
|
||||
@ -2126,6 +2175,39 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"foreign-types",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6"
|
||||
dependencies = [
|
||||
"autocfg 1.0.1",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parity-multiaddr"
|
||||
version = "0.11.0"
|
||||
@ -2266,6 +2348,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "2.0.2"
|
||||
@ -2870,6 +2958,16 @@ version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@ -2928,6 +3026,29 @@ dependencies = [
|
||||
"subtle 2.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
@ -3581,6 +3702,16 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.2"
|
||||
@ -3863,6 +3994,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
|
||||
|
||||
[[package]]
|
||||
name = "vec-arena"
|
||||
version = "1.0.0"
|
||||
|
@ -268,14 +268,8 @@ impl Client {
|
||||
address: &str,
|
||||
spend_key: &str,
|
||||
view_key: &str,
|
||||
restore_height: Option<u32>,
|
||||
restore_height: u32,
|
||||
) -> Result<GenerateFromKeys> {
|
||||
let restore_height = if let Some(restore_height) = restore_height {
|
||||
restore_height
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let params = GenerateFromKeysParams {
|
||||
restore_height,
|
||||
filename: view_key.into(),
|
||||
|
@ -156,7 +156,11 @@ async fn init_wallets(
|
||||
bitcoin_balance
|
||||
);
|
||||
|
||||
let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url.clone(), MONERO_NETWORK);
|
||||
let monero_wallet = monero::Wallet::new(
|
||||
config.monero.wallet_rpc_url.clone(),
|
||||
MONERO_NETWORK,
|
||||
DEFAULT_WALLET_NAME.to_string(),
|
||||
);
|
||||
|
||||
// Setup the Monero wallet
|
||||
let open_wallet_response = monero_wallet.open_wallet(DEFAULT_WALLET_NAME).await;
|
||||
@ -177,7 +181,7 @@ async fn init_wallets(
|
||||
|
||||
let balance = monero_wallet.get_balance().await?;
|
||||
if balance == Amount::ZERO {
|
||||
let deposit_address = monero_wallet.inner.get_address(0).await?.address;
|
||||
let deposit_address = monero_wallet.get_main_address().await?;
|
||||
warn!(
|
||||
"The Monero balance is 0, make sure to deposit funds at: {}",
|
||||
deposit_address
|
||||
|
@ -289,7 +289,11 @@ async fn init_wallets(
|
||||
bitcoin_balance
|
||||
);
|
||||
|
||||
let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url.clone(), monero_network);
|
||||
let monero_wallet = monero::Wallet::new(
|
||||
config.monero.wallet_rpc_url.clone(),
|
||||
monero_network,
|
||||
MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME.to_string(),
|
||||
);
|
||||
|
||||
// Setup the temporary Monero wallet necessary for monitoring the blockchain
|
||||
let open_monitoring_wallet_response = monero_wallet
|
||||
@ -316,7 +320,7 @@ async fn init_wallets(
|
||||
);
|
||||
}
|
||||
|
||||
let _test_wallet_connection = monero_wallet.inner.block_height().await?;
|
||||
let _test_wallet_connection = monero_wallet.block_height().await?;
|
||||
info!("The Monero wallet RPC is set up correctly!");
|
||||
|
||||
Ok((bitcoin_wallet, monero_wallet))
|
||||
|
@ -6,6 +6,7 @@ use crate::{
|
||||
};
|
||||
use ::bitcoin::hashes::core::fmt::Display;
|
||||
use libp2p::PeerId;
|
||||
use monero_rpc::wallet::BlockHeight;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// Large enum variant is fine because this is only used for database
|
||||
@ -23,15 +24,29 @@ pub enum Alice {
|
||||
#[serde(with = "crate::serde_peer_id")]
|
||||
bob_peer_id: PeerId,
|
||||
},
|
||||
XmrLocked(alice::State3),
|
||||
XmrLocked {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: alice::State3,
|
||||
},
|
||||
EncSigLearned {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
encrypted_signature: EncryptedSignature,
|
||||
state3: alice::State3,
|
||||
},
|
||||
CancelTimelockExpired(alice::State3),
|
||||
BtcCancelled(alice::State3),
|
||||
BtcPunishable(alice::State3),
|
||||
CancelTimelockExpired {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: alice::State3,
|
||||
},
|
||||
BtcCancelled {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: alice::State3,
|
||||
},
|
||||
BtcPunishable {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: alice::State3,
|
||||
},
|
||||
BtcRefunded {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: alice::State3,
|
||||
#[serde(with = "monero_private_key")]
|
||||
spend_key: monero::PrivateKey,
|
||||
@ -53,7 +68,6 @@ impl From<&AliceState> for Alice {
|
||||
AliceState::Started {
|
||||
state3,
|
||||
bob_peer_id,
|
||||
..
|
||||
} => Alice::Started {
|
||||
state3: state3.as_ref().clone(),
|
||||
bob_peer_id: *bob_peer_id,
|
||||
@ -61,32 +75,60 @@ impl From<&AliceState> for Alice {
|
||||
AliceState::BtcLocked {
|
||||
state3,
|
||||
bob_peer_id,
|
||||
..
|
||||
} => Alice::BtcLocked {
|
||||
state3: state3.as_ref().clone(),
|
||||
bob_peer_id: *bob_peer_id,
|
||||
},
|
||||
AliceState::XmrLocked { state3 } => Alice::XmrLocked(state3.as_ref().clone()),
|
||||
AliceState::XmrLocked {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
} => Alice::XmrLocked {
|
||||
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
|
||||
state3: state3.as_ref().clone(),
|
||||
},
|
||||
AliceState::EncSigLearned {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
encrypted_signature,
|
||||
} => Alice::EncSigLearned {
|
||||
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
|
||||
state3: state3.as_ref().clone(),
|
||||
encrypted_signature: *encrypted_signature.clone(),
|
||||
},
|
||||
AliceState::BtcRedeemed => Alice::Done(AliceEndState::BtcRedeemed),
|
||||
AliceState::BtcCancelled { state3, .. } => Alice::BtcCancelled(state3.as_ref().clone()),
|
||||
AliceState::BtcRefunded { spend_key, state3 } => Alice::BtcRefunded {
|
||||
AliceState::BtcCancelled {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
..
|
||||
} => Alice::BtcCancelled {
|
||||
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
|
||||
state3: state3.as_ref().clone(),
|
||||
},
|
||||
AliceState::BtcRefunded {
|
||||
monero_wallet_restore_blockheight,
|
||||
spend_key,
|
||||
state3,
|
||||
} => Alice::BtcRefunded {
|
||||
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
|
||||
spend_key: *spend_key,
|
||||
state3: state3.as_ref().clone(),
|
||||
},
|
||||
AliceState::BtcPunishable { state3, .. } => {
|
||||
Alice::BtcPunishable(state3.as_ref().clone())
|
||||
}
|
||||
AliceState::BtcPunishable {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
..
|
||||
} => Alice::BtcPunishable {
|
||||
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
|
||||
state3: state3.as_ref().clone(),
|
||||
},
|
||||
AliceState::XmrRefunded => Alice::Done(AliceEndState::XmrRefunded),
|
||||
AliceState::CancelTimelockExpired { state3 } => {
|
||||
Alice::CancelTimelockExpired(state3.as_ref().clone())
|
||||
}
|
||||
AliceState::CancelTimelockExpired {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
} => Alice::CancelTimelockExpired {
|
||||
monero_wallet_restore_blockheight: *monero_wallet_restore_blockheight,
|
||||
state3: state3.as_ref().clone(),
|
||||
},
|
||||
AliceState::BtcPunished => Alice::Done(AliceEndState::BtcPunished),
|
||||
AliceState::SafelyAborted => Alice::Done(AliceEndState::SafelyAborted),
|
||||
}
|
||||
@ -110,33 +152,50 @@ impl From<Alice> for AliceState {
|
||||
bob_peer_id,
|
||||
state3: Box::new(state3),
|
||||
},
|
||||
Alice::XmrLocked(state3) => AliceState::XmrLocked {
|
||||
Alice::XmrLocked {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
} => AliceState::XmrLocked {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3: Box::new(state3),
|
||||
},
|
||||
Alice::EncSigLearned {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3: state,
|
||||
encrypted_signature,
|
||||
} => AliceState::EncSigLearned {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3: Box::new(state),
|
||||
encrypted_signature: Box::new(encrypted_signature),
|
||||
},
|
||||
Alice::CancelTimelockExpired(state3) => AliceState::CancelTimelockExpired {
|
||||
Alice::CancelTimelockExpired {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
} => AliceState::CancelTimelockExpired {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3: Box::new(state3),
|
||||
},
|
||||
Alice::BtcCancelled(state) => {
|
||||
Alice::BtcCancelled {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
} => {
|
||||
let tx_cancel = TxCancel::new(
|
||||
&state.tx_lock,
|
||||
state.cancel_timelock,
|
||||
state.a.public(),
|
||||
state.B,
|
||||
&state3.tx_lock,
|
||||
state3.cancel_timelock,
|
||||
state3.a.public(),
|
||||
state3.B,
|
||||
);
|
||||
|
||||
AliceState::BtcCancelled {
|
||||
state3: Box::new(state),
|
||||
monero_wallet_restore_blockheight,
|
||||
state3: Box::new(state3),
|
||||
tx_cancel: Box::new(tx_cancel),
|
||||
}
|
||||
}
|
||||
Alice::BtcPunishable(state3) => {
|
||||
Alice::BtcPunishable {
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
} => {
|
||||
let tx_cancel = TxCancel::new(
|
||||
&state3.tx_lock,
|
||||
state3.cancel_timelock,
|
||||
@ -145,13 +204,17 @@ impl From<Alice> for AliceState {
|
||||
);
|
||||
let tx_refund = TxRefund::new(&tx_cancel, &state3.refund_address);
|
||||
AliceState::BtcPunishable {
|
||||
monero_wallet_restore_blockheight,
|
||||
tx_refund,
|
||||
state3: Box::new(state3),
|
||||
}
|
||||
}
|
||||
Alice::BtcRefunded {
|
||||
state3, spend_key, ..
|
||||
monero_wallet_restore_blockheight,
|
||||
state3,
|
||||
spend_key,
|
||||
} => AliceState::BtcRefunded {
|
||||
monero_wallet_restore_blockheight,
|
||||
spend_key,
|
||||
state3: Box::new(state3),
|
||||
},
|
||||
@ -170,10 +233,10 @@ impl Display for Alice {
|
||||
match self {
|
||||
Alice::Started { .. } => write!(f, "Started"),
|
||||
Alice::BtcLocked { .. } => f.write_str("Bitcoin locked"),
|
||||
Alice::XmrLocked(_) => f.write_str("Monero locked"),
|
||||
Alice::CancelTimelockExpired(_) => f.write_str("Cancel timelock is expired"),
|
||||
Alice::BtcCancelled(_) => f.write_str("Bitcoin cancel transaction published"),
|
||||
Alice::BtcPunishable(_) => f.write_str("Bitcoin punishable"),
|
||||
Alice::XmrLocked { .. } => f.write_str("Monero locked"),
|
||||
Alice::CancelTimelockExpired { .. } => f.write_str("Cancel timelock is expired"),
|
||||
Alice::BtcCancelled { .. } => f.write_str("Bitcoin cancel transaction published"),
|
||||
Alice::BtcPunishable { .. } => f.write_str("Bitcoin punishable"),
|
||||
Alice::BtcRefunded { .. } => f.write_str("Monero refundable"),
|
||||
Alice::Done(end_state) => write!(f, "Done: {}", end_state),
|
||||
Alice::EncSigLearned { .. } => f.write_str("Encrypted signature learned"),
|
||||
|
@ -8,6 +8,8 @@ use crate::bitcoin;
|
||||
use ::bitcoin::hashes::core::fmt::Formatter;
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use monero::Address;
|
||||
use monero_rpc::wallet::{BlockHeight, Refreshed};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use rust_decimal::{
|
||||
prelude::{FromPrimitive, ToPrimitive},
|
||||
@ -214,7 +216,17 @@ pub trait CreateWalletForOutput {
|
||||
&self,
|
||||
private_spend_key: PrivateKey,
|
||||
private_view_key: PrivateViewKey,
|
||||
restore_height: Option<u32>,
|
||||
restore_height: BlockHeight,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait CreateWalletForOutputThenLoadDefaultWallet {
|
||||
async fn create_and_load_wallet_for_output_then_load_default_wallet(
|
||||
&self,
|
||||
private_spend_key: PrivateKey,
|
||||
private_view_key: PrivateViewKey,
|
||||
restore_height: BlockHeight,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
@ -228,6 +240,21 @@ pub trait CreateWallet {
|
||||
async fn create_wallet(&self, file_name: &str) -> Result<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait WalletBlockHeight {
|
||||
async fn block_height(&self) -> Result<BlockHeight>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait GetAddress {
|
||||
async fn get_main_address(&self) -> Result<Address>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Refresh {
|
||||
async fn refresh(&self) -> Result<Refreshed>;
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq)]
|
||||
#[error("Overflow, cannot convert {0} to u64")]
|
||||
pub struct OverflowError(pub String);
|
||||
|
@ -1,41 +1,73 @@
|
||||
use crate::monero::{
|
||||
Amount, CreateWallet, CreateWalletForOutput, InsufficientFunds, OpenWallet, PrivateViewKey,
|
||||
PublicViewKey, Transfer, TransferProof, TxHash, WatchForTransfer,
|
||||
Amount, CreateWallet, CreateWalletForOutput, CreateWalletForOutputThenLoadDefaultWallet,
|
||||
InsufficientFunds, OpenWallet, PrivateViewKey, PublicViewKey, Transfer, TransferProof, TxHash,
|
||||
WatchForTransfer,
|
||||
};
|
||||
use ::monero::{Address, Network, PrivateKey, PublicKey};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use backoff::{backoff::Constant as ConstantBackoff, future::retry};
|
||||
use bitcoin::hashes::core::sync::atomic::AtomicU32;
|
||||
use monero_rpc::wallet;
|
||||
use monero_rpc::{
|
||||
wallet,
|
||||
wallet::{BlockHeight, Refreshed},
|
||||
};
|
||||
use std::{
|
||||
str::FromStr,
|
||||
sync::{atomic::Ordering, Arc},
|
||||
time::Duration,
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::info;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Wallet {
|
||||
pub inner: wallet::Client,
|
||||
pub network: Network,
|
||||
inner: Mutex<wallet::Client>,
|
||||
network: Network,
|
||||
default_wallet_name: String,
|
||||
}
|
||||
|
||||
impl Wallet {
|
||||
pub fn new(url: Url, network: Network) -> Self {
|
||||
pub fn new(url: Url, network: Network, default_wallet_name: String) -> Self {
|
||||
Self {
|
||||
inner: wallet::Client::new(url),
|
||||
inner: Mutex::new(wallet::Client::new(url)),
|
||||
network,
|
||||
default_wallet_name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_client(
|
||||
client: wallet::Client,
|
||||
network: Network,
|
||||
default_wallet_name: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: Mutex::new(client),
|
||||
network,
|
||||
default_wallet_name,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the balance of the primary account.
|
||||
pub async fn get_balance(&self) -> Result<Amount> {
|
||||
let amount = self.inner.get_balance(0).await?;
|
||||
let amount = self.inner.lock().await.get_balance(0).await?;
|
||||
|
||||
Ok(Amount::from_piconero(amount))
|
||||
}
|
||||
|
||||
pub async fn block_height(&self) -> Result<BlockHeight> {
|
||||
self.inner.lock().await.block_height().await
|
||||
}
|
||||
|
||||
pub async fn get_main_address(&self) -> Result<Address> {
|
||||
let address = self.inner.lock().await.get_address(0).await?;
|
||||
Ok(Address::from_str(address.address.as_str())?)
|
||||
}
|
||||
|
||||
pub async fn refresh(&self) -> Result<Refreshed> {
|
||||
self.inner.lock().await.refresh().await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@ -51,6 +83,8 @@ impl Transfer for Wallet {
|
||||
|
||||
let res = self
|
||||
.inner
|
||||
.lock()
|
||||
.await
|
||||
.transfer(0, amount.as_piconero(), &destination_address.to_string())
|
||||
.await?;
|
||||
|
||||
@ -73,7 +107,7 @@ impl CreateWalletForOutput for Wallet {
|
||||
&self,
|
||||
private_spend_key: PrivateKey,
|
||||
private_view_key: PrivateViewKey,
|
||||
restore_height: Option<u32>,
|
||||
restore_height: BlockHeight,
|
||||
) -> Result<()> {
|
||||
let public_spend_key = PublicKey::from_private_key(&private_spend_key);
|
||||
let public_view_key = PublicKey::from_private_key(&private_view_key.into());
|
||||
@ -82,11 +116,13 @@ impl CreateWalletForOutput for Wallet {
|
||||
|
||||
let _ = self
|
||||
.inner
|
||||
.lock()
|
||||
.await
|
||||
.generate_from_keys(
|
||||
&address.to_string(),
|
||||
&private_spend_key.to_string(),
|
||||
&PrivateKey::from(private_view_key).to_string(),
|
||||
restore_height,
|
||||
restore_height.height,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -94,10 +130,42 @@ impl CreateWalletForOutput for Wallet {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl CreateWalletForOutputThenLoadDefaultWallet for Wallet {
|
||||
async fn create_and_load_wallet_for_output_then_load_default_wallet(
|
||||
&self,
|
||||
private_spend_key: PrivateKey,
|
||||
private_view_key: PrivateViewKey,
|
||||
restore_height: BlockHeight,
|
||||
) -> Result<()> {
|
||||
let public_spend_key = PublicKey::from_private_key(&private_spend_key);
|
||||
let public_view_key = PublicKey::from_private_key(&private_view_key.into());
|
||||
|
||||
let address = Address::standard(self.network, public_spend_key, public_view_key);
|
||||
|
||||
let wallet = self.inner.lock().await;
|
||||
|
||||
let _ = wallet
|
||||
.generate_from_keys(
|
||||
&address.to_string(),
|
||||
&private_spend_key.to_string(),
|
||||
&PrivateKey::from(private_view_key).to_string(),
|
||||
restore_height.height,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let _ = wallet
|
||||
.open_wallet(self.default_wallet_name.as_str())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl OpenWallet for Wallet {
|
||||
async fn open_wallet(&self, file_name: &str) -> Result<()> {
|
||||
self.inner.open_wallet(file_name).await?;
|
||||
self.inner.lock().await.open_wallet(file_name).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -105,7 +173,7 @@ impl OpenWallet for Wallet {
|
||||
#[async_trait]
|
||||
impl CreateWallet for Wallet {
|
||||
async fn create_wallet(&self, file_name: &str) -> Result<()> {
|
||||
self.inner.create_wallet(file_name).await?;
|
||||
self.inner.lock().await.create_wallet(file_name).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -129,7 +197,6 @@ impl WatchForTransfer for Wallet {
|
||||
}
|
||||
|
||||
let address = Address::standard(self.network, public_spend_key, public_view_key.into());
|
||||
let wallet = self.inner.clone();
|
||||
|
||||
let confirmations = Arc::new(AtomicU32::new(0u32));
|
||||
|
||||
@ -137,7 +204,10 @@ impl WatchForTransfer for Wallet {
|
||||
// NOTE: Currently, this is conflicting IO errors with the transaction not being
|
||||
// in the blockchain yet, or not having enough confirmations on it. All these
|
||||
// errors warrant a retry, but the strategy should probably differ per case
|
||||
let proof = wallet
|
||||
let proof = self
|
||||
.inner
|
||||
.lock()
|
||||
.await
|
||||
.check_tx_key(
|
||||
&String::from(transfer_proof.tx_hash()),
|
||||
&transfer_proof.tx_key().to_string(),
|
||||
|
@ -7,22 +7,17 @@ use crate::{
|
||||
},
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
monero_ext::ScalarExt,
|
||||
protocol::{
|
||||
alice::{Message1, Message3, TransferProof},
|
||||
bob::{EncryptedSignature, Message0, Message2, Message4},
|
||||
alice::{Message1, Message3},
|
||||
bob::{Message0, Message2, Message4},
|
||||
CROSS_CURVE_PROOF_SYSTEM,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
nonce::Deterministic,
|
||||
};
|
||||
use libp2p::PeerId;
|
||||
use monero_rpc::wallet::BlockHeight;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha256;
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
use std::fmt;
|
||||
|
||||
@ -37,27 +32,33 @@ pub enum AliceState {
|
||||
state3: Box<State3>,
|
||||
},
|
||||
XmrLocked {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
EncSigLearned {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
encrypted_signature: Box<bitcoin::EncryptedSignature>,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
BtcRedeemed,
|
||||
BtcCancelled {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
tx_cancel: Box<TxCancel>,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
BtcRefunded {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
spend_key: monero::PrivateKey,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
BtcPunishable {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
tx_refund: TxRefund,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
XmrRefunded,
|
||||
CancelTimelockExpired {
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
state3: Box<State3>,
|
||||
},
|
||||
BtcPunished,
|
||||
@ -349,191 +350,3 @@ impl State3 {
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct State4 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
xmr: monero::Amount,
|
||||
cancel_timelock: CancelTimelock,
|
||||
punish_timelock: PunishTimelock,
|
||||
refund_address: bitcoin::Address,
|
||||
redeem_address: bitcoin::Address,
|
||||
punish_address: bitcoin::Address,
|
||||
tx_lock: bitcoin::TxLock,
|
||||
tx_punish_sig_bob: bitcoin::Signature,
|
||||
tx_cancel_sig_bob: bitcoin::Signature,
|
||||
}
|
||||
|
||||
impl State4 {
|
||||
pub async fn lock_xmr<W>(self, monero_wallet: &W) -> Result<State5>
|
||||
where
|
||||
W: monero::Transfer,
|
||||
{
|
||||
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a });
|
||||
let S_b = self.S_b_monero;
|
||||
|
||||
let (tx_lock_proof, fee) = monero_wallet
|
||||
.transfer(S_a + S_b, self.v.public(), self.xmr)
|
||||
.await?;
|
||||
|
||||
Ok(State5 {
|
||||
a: self.a,
|
||||
B: self.B,
|
||||
s_a: self.s_a,
|
||||
S_b_monero: self.S_b_monero,
|
||||
S_b_bitcoin: self.S_b_bitcoin,
|
||||
v: self.v,
|
||||
cancel_timelock: self.cancel_timelock,
|
||||
punish_timelock: self.punish_timelock,
|
||||
refund_address: self.refund_address,
|
||||
redeem_address: self.redeem_address,
|
||||
punish_address: self.punish_address,
|
||||
tx_lock: self.tx_lock,
|
||||
tx_lock_proof,
|
||||
tx_punish_sig_bob: self.tx_punish_sig_bob,
|
||||
tx_cancel_sig_bob: self.tx_cancel_sig_bob,
|
||||
lock_xmr_fee: fee,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn punish<W: bitcoin::BroadcastSignedTransaction>(
|
||||
&self,
|
||||
bitcoin_wallet: &W,
|
||||
) -> Result<()> {
|
||||
let tx_cancel =
|
||||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
||||
let tx_punish =
|
||||
bitcoin::TxPunish::new(&tx_cancel, &self.punish_address, self.punish_timelock);
|
||||
|
||||
{
|
||||
let sig_a = self.a.sign(tx_cancel.digest());
|
||||
let sig_b = self.tx_cancel_sig_bob.clone();
|
||||
|
||||
let signed_tx_cancel = tx_cancel.clone().add_signatures(
|
||||
&self.tx_lock,
|
||||
(self.a.public(), sig_a),
|
||||
(self.B, sig_b),
|
||||
)?;
|
||||
|
||||
let _ = bitcoin_wallet
|
||||
.broadcast_signed_transaction(signed_tx_cancel)
|
||||
.await?;
|
||||
}
|
||||
|
||||
{
|
||||
let sig_a = self.a.sign(tx_punish.digest());
|
||||
let sig_b = self.tx_punish_sig_bob.clone();
|
||||
|
||||
let signed_tx_punish =
|
||||
tx_punish.add_signatures(&tx_cancel, (self.a.public(), sig_a), (self.B, sig_b))?;
|
||||
|
||||
let _ = bitcoin_wallet
|
||||
.broadcast_signed_transaction(signed_tx_punish)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct State5 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
cancel_timelock: CancelTimelock,
|
||||
punish_timelock: PunishTimelock,
|
||||
refund_address: bitcoin::Address,
|
||||
redeem_address: bitcoin::Address,
|
||||
punish_address: bitcoin::Address,
|
||||
tx_lock: bitcoin::TxLock,
|
||||
tx_lock_proof: monero::TransferProof,
|
||||
|
||||
tx_punish_sig_bob: bitcoin::Signature,
|
||||
|
||||
tx_cancel_sig_bob: bitcoin::Signature,
|
||||
lock_xmr_fee: monero::Amount,
|
||||
}
|
||||
|
||||
impl State5 {
|
||||
pub fn next_message(&self) -> TransferProof {
|
||||
TransferProof {
|
||||
tx_lock_proof: self.tx_lock_proof.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive(self, msg: EncryptedSignature) -> State6 {
|
||||
State6 {
|
||||
a: self.a,
|
||||
B: self.B,
|
||||
s_a: self.s_a,
|
||||
S_b_monero: self.S_b_monero,
|
||||
S_b_bitcoin: self.S_b_bitcoin,
|
||||
v: self.v,
|
||||
cancel_timelock: self.cancel_timelock,
|
||||
punish_timelock: self.punish_timelock,
|
||||
refund_address: self.refund_address,
|
||||
redeem_address: self.redeem_address,
|
||||
punish_address: self.punish_address,
|
||||
tx_lock: self.tx_lock,
|
||||
tx_punish_sig_bob: self.tx_punish_sig_bob,
|
||||
tx_redeem_encsig: msg.tx_redeem_encsig,
|
||||
lock_xmr_fee: self.lock_xmr_fee,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct State6 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
cancel_timelock: CancelTimelock,
|
||||
punish_timelock: PunishTimelock,
|
||||
refund_address: bitcoin::Address,
|
||||
redeem_address: bitcoin::Address,
|
||||
punish_address: bitcoin::Address,
|
||||
tx_lock: bitcoin::TxLock,
|
||||
|
||||
tx_punish_sig_bob: bitcoin::Signature,
|
||||
tx_redeem_encsig: bitcoin::EncryptedSignature,
|
||||
lock_xmr_fee: monero::Amount,
|
||||
}
|
||||
|
||||
impl State6 {
|
||||
pub async fn redeem_btc<W: bitcoin::BroadcastSignedTransaction>(
|
||||
&self,
|
||||
bitcoin_wallet: &W,
|
||||
) -> Result<()> {
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
||||
let tx_redeem = bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address);
|
||||
|
||||
let sig_a = self.a.sign(tx_redeem.digest());
|
||||
let sig_b =
|
||||
adaptor.decrypt_signature(&self.s_a.to_secpfun_scalar(), self.tx_redeem_encsig.clone());
|
||||
|
||||
let sig_tx_redeem =
|
||||
tx_redeem.add_signatures(&self.tx_lock, (self.a.public(), sig_a), (self.B, sig_b))?;
|
||||
bitcoin_wallet
|
||||
.broadcast_signed_transaction(sig_tx_redeem)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lock_xmr_fee(&self) -> monero::Amount {
|
||||
self.lock_xmr_fee
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
database::Database,
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
monero::CreateWalletForOutput,
|
||||
monero::CreateWalletForOutputThenLoadDefaultWallet,
|
||||
monero_ext::ScalarExt,
|
||||
protocol::{
|
||||
alice,
|
||||
@ -127,6 +127,10 @@ async fn run_until_internal(
|
||||
bob_peer_id,
|
||||
state3,
|
||||
} => {
|
||||
// Record the current monero wallet block height so we don't have to scan from
|
||||
// block 0 for scenarios where we create a refund wallet.
|
||||
let monero_wallet_restore_blockheight = monero_wallet.block_height().await?;
|
||||
|
||||
lock_xmr(
|
||||
bob_peer_id,
|
||||
*state3.clone(),
|
||||
@ -135,7 +139,10 @@ async fn run_until_internal(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let state = AliceState::XmrLocked { state3 };
|
||||
let state = AliceState::XmrLocked {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
};
|
||||
|
||||
let db_state = (&state).into();
|
||||
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
|
||||
@ -152,7 +159,10 @@ async fn run_until_internal(
|
||||
)
|
||||
.await
|
||||
}
|
||||
AliceState::XmrLocked { state3 } => {
|
||||
AliceState::XmrLocked {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let state = match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? {
|
||||
ExpiredTimelocks::None => {
|
||||
let wait_for_enc_sig =
|
||||
@ -165,14 +175,21 @@ async fn run_until_internal(
|
||||
pin_mut!(cancel_timelock_expires);
|
||||
|
||||
match select(cancel_timelock_expires, wait_for_enc_sig).await {
|
||||
Either::Left(_) => AliceState::CancelTimelockExpired { state3 },
|
||||
Either::Left(_) => AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
},
|
||||
Either::Right((enc_sig, _)) => AliceState::EncSigLearned {
|
||||
state3,
|
||||
encrypted_signature: Box::new(enc_sig?),
|
||||
monero_wallet_restore_blockheight,
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => AliceState::CancelTimelockExpired { state3 },
|
||||
_ => AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
},
|
||||
};
|
||||
|
||||
let db_state = (&state).into();
|
||||
@ -193,6 +210,7 @@ async fn run_until_internal(
|
||||
AliceState::EncSigLearned {
|
||||
state3,
|
||||
encrypted_signature,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let state = match state3.expired_timelocks(bitcoin_wallet.as_ref()).await? {
|
||||
ExpiredTimelocks::None => {
|
||||
@ -228,7 +246,10 @@ async fn run_until_internal(
|
||||
)
|
||||
.await?;
|
||||
|
||||
AliceState::CancelTimelockExpired { state3 }
|
||||
AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,11 +259,17 @@ async fn run_until_internal(
|
||||
.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref())
|
||||
.await?;
|
||||
|
||||
AliceState::CancelTimelockExpired { state3 }
|
||||
AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => AliceState::CancelTimelockExpired { state3 },
|
||||
}
|
||||
_ => AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
},
|
||||
};
|
||||
|
||||
let db_state = (&state).into();
|
||||
@ -260,7 +287,10 @@ async fn run_until_internal(
|
||||
)
|
||||
.await
|
||||
}
|
||||
AliceState::CancelTimelockExpired { state3 } => {
|
||||
AliceState::CancelTimelockExpired {
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let tx_cancel = publish_cancel_transaction(
|
||||
state3.tx_lock.clone(),
|
||||
state3.a.clone(),
|
||||
@ -274,6 +304,7 @@ async fn run_until_internal(
|
||||
let state = AliceState::BtcCancelled {
|
||||
state3,
|
||||
tx_cancel: Box::new(tx_cancel),
|
||||
monero_wallet_restore_blockheight,
|
||||
};
|
||||
let db_state = (&state).into();
|
||||
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
|
||||
@ -290,7 +321,11 @@ async fn run_until_internal(
|
||||
)
|
||||
.await
|
||||
}
|
||||
AliceState::BtcCancelled { state3, tx_cancel } => {
|
||||
AliceState::BtcCancelled {
|
||||
state3,
|
||||
tx_cancel,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let tx_cancel_height = bitcoin_wallet
|
||||
.transaction_block_height(tx_cancel.txid())
|
||||
.await?;
|
||||
@ -307,7 +342,11 @@ async fn run_until_internal(
|
||||
// TODO(Franck): Review error handling
|
||||
match published_refund_tx {
|
||||
None => {
|
||||
let state = AliceState::BtcPunishable { tx_refund, state3 };
|
||||
let state = AliceState::BtcPunishable {
|
||||
tx_refund,
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
};
|
||||
let db_state = (&state).into();
|
||||
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
|
||||
.await?;
|
||||
@ -333,7 +372,11 @@ async fn run_until_internal(
|
||||
state3.S_b_bitcoin,
|
||||
)?;
|
||||
|
||||
let state = AliceState::BtcRefunded { spend_key, state3 };
|
||||
let state = AliceState::BtcRefunded {
|
||||
spend_key,
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
};
|
||||
let db_state = (&state).into();
|
||||
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
|
||||
.await?;
|
||||
@ -351,11 +394,19 @@ async fn run_until_internal(
|
||||
}
|
||||
}
|
||||
}
|
||||
AliceState::BtcRefunded { spend_key, state3 } => {
|
||||
AliceState::BtcRefunded {
|
||||
spend_key,
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let view_key = state3.v;
|
||||
|
||||
monero_wallet
|
||||
.create_and_load_wallet_for_output(spend_key, view_key, None)
|
||||
.create_and_load_wallet_for_output_then_load_default_wallet(
|
||||
spend_key,
|
||||
view_key,
|
||||
monero_wallet_restore_blockheight,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let state = AliceState::XmrRefunded;
|
||||
@ -364,7 +415,11 @@ async fn run_until_internal(
|
||||
.await?;
|
||||
Ok(state)
|
||||
}
|
||||
AliceState::BtcPunishable { tx_refund, state3 } => {
|
||||
AliceState::BtcPunishable {
|
||||
tx_refund,
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
} => {
|
||||
let signed_tx_punish = build_bitcoin_punish_transaction(
|
||||
&state3.tx_lock,
|
||||
state3.cancel_timelock,
|
||||
@ -395,7 +450,11 @@ async fn run_until_internal(
|
||||
state3.a.clone(),
|
||||
state3.S_b_bitcoin,
|
||||
)?;
|
||||
let state = AliceState::BtcRefunded { spend_key, state3 };
|
||||
let state = AliceState::BtcRefunded {
|
||||
spend_key,
|
||||
state3,
|
||||
monero_wallet_restore_blockheight,
|
||||
};
|
||||
let db_state = (&state).into();
|
||||
db.insert_latest_state(swap_id, database::Swap::Alice(db_state))
|
||||
.await?;
|
||||
|
@ -23,8 +23,8 @@ pub async fn cancel(
|
||||
force: bool,
|
||||
) -> Result<Result<(Txid, BobState), CancelError>> {
|
||||
let state4 = match state {
|
||||
BobState::BtcLocked(state3) => state3.state4(),
|
||||
BobState::XmrLockProofReceived { state, .. } => state.state4(),
|
||||
BobState::BtcLocked(state3) => state3.cancel(),
|
||||
BobState::XmrLockProofReceived { state, .. } => state.cancel(),
|
||||
BobState::XmrLocked(state4) => state4,
|
||||
BobState::EncSigSent(state4) => state4,
|
||||
BobState::CancelTimelockExpired(state4) => state4,
|
||||
|
@ -22,8 +22,8 @@ pub async fn refund(
|
||||
) -> Result<Result<BobState, SwapNotCancelledYet>> {
|
||||
let state4 = if force {
|
||||
match state {
|
||||
BobState::BtcLocked(state3) => state3.state4(),
|
||||
BobState::XmrLockProofReceived { state, .. } => state.state4(),
|
||||
BobState::BtcLocked(state3) => state3.cancel(),
|
||||
BobState::XmrLockProofReceived { state, .. } => state.cancel(),
|
||||
BobState::XmrLocked(state4) => state4,
|
||||
BobState::EncSigSent(state4) => state4,
|
||||
BobState::CancelTimelockExpired(state4) => state4,
|
||||
|
@ -328,7 +328,7 @@ impl State3 {
|
||||
self,
|
||||
xmr_wallet: &W,
|
||||
transfer_proof: TransferProof,
|
||||
monero_wallet_restore_blockheight: u32,
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
) -> Result<Result<State4, InsufficientFunds>>
|
||||
where
|
||||
W: monero::WatchForTransfer,
|
||||
@ -379,7 +379,7 @@ impl State3 {
|
||||
.await
|
||||
}
|
||||
|
||||
pub fn state4(&self) -> State4 {
|
||||
pub fn cancel(&self) -> State4 {
|
||||
State4 {
|
||||
A: self.A,
|
||||
b: self.b.clone(),
|
||||
@ -393,7 +393,9 @@ impl State3 {
|
||||
tx_lock: self.tx_lock.clone(),
|
||||
tx_cancel_sig_a: self.tx_cancel_sig_a.clone(),
|
||||
tx_refund_encsig: self.tx_refund_encsig.clone(),
|
||||
monero_wallet_restore_blockheight: 0u32,
|
||||
// For cancel scenarios the monero wallet rescan blockchain height is irrelevant for
|
||||
// Bob, because Bob's cancel can only lead to refunding on Bitcoin
|
||||
monero_wallet_restore_blockheight: BlockHeight { height: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,7 +431,7 @@ pub struct State4 {
|
||||
tx_lock: bitcoin::TxLock,
|
||||
tx_cancel_sig_a: Signature,
|
||||
tx_refund_encsig: bitcoin::EncryptedSignature,
|
||||
monero_wallet_restore_blockheight: u32,
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
}
|
||||
|
||||
impl State4 {
|
||||
@ -589,7 +591,7 @@ pub struct State5 {
|
||||
s_b: monero::Scalar,
|
||||
v: monero::PrivateViewKey,
|
||||
tx_lock: bitcoin::TxLock,
|
||||
monero_wallet_restore_blockheight: u32,
|
||||
monero_wallet_restore_blockheight: BlockHeight,
|
||||
}
|
||||
|
||||
impl State5 {
|
||||
@ -604,11 +606,7 @@ impl State5 {
|
||||
// NOTE: This actually generates and opens a new wallet, closing the currently
|
||||
// open one.
|
||||
monero_wallet
|
||||
.create_and_load_wallet_for_output(
|
||||
s,
|
||||
self.v,
|
||||
Some(self.monero_wallet_restore_blockheight),
|
||||
)
|
||||
.create_and_load_wallet_for_output(s, self.v, self.monero_wallet_restore_blockheight)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
@ -129,11 +129,7 @@ async fn run_until_internal(
|
||||
|
||||
// Record the current monero wallet block height so we don't have to scan from
|
||||
// block 0 once we create the redeem wallet.
|
||||
// TODO: This can be optimized further by extracting the block height when
|
||||
// tx-lock was included. However, scanning a few more blocks won't do any harm
|
||||
// and is simpler.
|
||||
let monero_wallet_restore_blockheight =
|
||||
monero_wallet.inner.block_height().await?;
|
||||
let monero_wallet_restore_blockheight = monero_wallet.block_height().await?;
|
||||
|
||||
select! {
|
||||
transfer_proof = transfer_proof_watcher => {
|
||||
@ -145,12 +141,12 @@ async fn run_until_internal(
|
||||
}
|
||||
},
|
||||
_ = cancel_timelock_expires => {
|
||||
let state4 = state3.state4();
|
||||
let state4 = state3.cancel();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let state4 = state3.state4();
|
||||
let state4 = state3.cancel();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
};
|
||||
let db_state = state.clone().into();
|
||||
@ -180,7 +176,7 @@ async fn run_until_internal(
|
||||
let xmr_lock_watcher = state.clone().watch_for_lock_xmr(
|
||||
monero_wallet.as_ref(),
|
||||
lock_transfer_proof,
|
||||
monero_wallet_restore_blockheight.height,
|
||||
monero_wallet_restore_blockheight,
|
||||
);
|
||||
let cancel_timelock_expires =
|
||||
state.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref());
|
||||
@ -192,18 +188,18 @@ async fn run_until_internal(
|
||||
Err(InsufficientFunds {..}) => {
|
||||
info!("The other party has locked insufficient Monero funds! Waiting for refund...");
|
||||
state.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref()).await?;
|
||||
let state4 = state.state4();
|
||||
let state4 = state.cancel();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
},
|
||||
}
|
||||
},
|
||||
_ = cancel_timelock_expires => {
|
||||
let state4 = state.state4();
|
||||
let state4 = state.cancel();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let state4 = state.state4();
|
||||
let state4 = state.cancel();
|
||||
BobState::CancelTimelockExpired(state4)
|
||||
};
|
||||
|
||||
|
@ -168,12 +168,7 @@ impl TestContext {
|
||||
assert_eq!(btc_balance_after_swap, self.alice_starting_balances.btc);
|
||||
|
||||
// Ensure that Alice's balance is refreshed as we use a newly created wallet
|
||||
self.alice_monero_wallet
|
||||
.as_ref()
|
||||
.inner
|
||||
.refresh()
|
||||
.await
|
||||
.unwrap();
|
||||
self.alice_monero_wallet.as_ref().refresh().await.unwrap();
|
||||
let xmr_balance_after_swap = self
|
||||
.alice_monero_wallet
|
||||
.as_ref()
|
||||
@ -232,12 +227,7 @@ impl TestContext {
|
||||
);
|
||||
|
||||
// Ensure that Bob's balance is refreshed as we use a newly created wallet
|
||||
self.bob_monero_wallet
|
||||
.as_ref()
|
||||
.inner
|
||||
.refresh()
|
||||
.await
|
||||
.unwrap();
|
||||
self.bob_monero_wallet.as_ref().refresh().await.unwrap();
|
||||
let xmr_balance_after_swap = self.bob_monero_wallet.as_ref().get_balance().await.unwrap();
|
||||
assert_eq!(
|
||||
xmr_balance_after_swap,
|
||||
@ -594,10 +584,11 @@ async fn init_test_wallets(
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let xmr_wallet = swap::monero::Wallet {
|
||||
inner: monero.wallet(name).unwrap().client(),
|
||||
network: monero::Network::default(),
|
||||
};
|
||||
let xmr_wallet = swap::monero::Wallet::new_with_client(
|
||||
monero.wallet(name).unwrap().client(),
|
||||
monero::Network::default(),
|
||||
"irrelevant_for_tests".to_string(),
|
||||
);
|
||||
|
||||
let electrum_rpc_url = {
|
||||
let input = format!("tcp://@localhost:{}", electrum_rpc_port);
|
||||
|
Loading…
Reference in New Issue
Block a user