Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Sync wallet when contract is not confirmed yet. #2570

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion coordinator/src/node/liquidated_positions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ async fn check_if_positions_need_to_get_liquidated(
// liquidation.
match node
.inner
.is_signed_dlc_channel_confirmed_by_trader_id(position.trader)
.check_if_signed_channel_is_confirmed(position.trader)
.await
{
Ok(true) => {
tracing::debug!(trader_id=%position.trader, "Traders dlc channel is confirmed. Continuing with the liquidation");
Expand Down
18 changes: 14 additions & 4 deletions coordinator/src/trade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,8 +804,13 @@ impl TradeExecutor {
trade_params: &TradeParams,
resize_action: ResizeAction,
) -> Result<()> {
if !self.node.inner.is_dlc_channel_confirmed(&dlc_channel_id)? {
bail!("Underlying DLC channel not yet confirmed");
if !self
.node
.inner
.check_if_signed_channel_is_confirmed(position.trader)
.await?
{
bail!("Underlying DLC channel not yet confirmed.");
}

let peer_id = trade_params.pubkey;
Expand Down Expand Up @@ -1045,8 +1050,13 @@ impl TradeExecutor {
trade_params: &TradeParams,
channel_id: DlcChannelId,
) -> Result<()> {
if !self.node.inner.is_dlc_channel_confirmed(&channel_id)? {
bail!("Underlying DLC channel not yet confirmed");
if !self
.node
.inner
.check_if_signed_channel_is_confirmed(position.trader)
.await?
{
bail!("Underlying DLC channel not yet confirmed.");
}

let closing_price = trade_params.average_execution_price();
Expand Down
42 changes: 27 additions & 15 deletions crates/xxi-node/src/node/dlc_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,28 +581,40 @@ impl<D: BdkStorage, S: TenTenOneStorage + 'static, N: LnDlcStorage + Sync + Send
Ok(dlc_channels)
}

pub fn is_signed_dlc_channel_confirmed_by_trader_id(
&self,
trader_id: PublicKey,
) -> Result<bool> {
let signed_channel = self.get_signed_channel_by_trader_id(trader_id)?;
self.is_dlc_channel_confirmed(&signed_channel.channel_id)
/// Checks if the underlying contract of the signed channel has been confirmed. If not a
/// periodic check is run to ensure we are on the latest state and return the corresponding
/// response.
pub async fn check_if_signed_channel_is_confirmed(&self, trader: PublicKey) -> Result<bool> {
let signed_channel = self.get_signed_channel_by_trader_id(trader)?;
if !self.is_dlc_channel_confirmed(&signed_channel.channel_id)? {
self.sync_on_chain_wallet().await?;
spawn_blocking({
let dlc_manager = self.dlc_manager.clone();
move || dlc_manager.periodic_check()
})
.await
.expect("task to complete")?;

return self.is_dlc_channel_confirmed(&signed_channel.channel_id);
}

Ok(true)
}

// TODO: This API could return the number of required confirmations + the number of current
// confirmations.
pub fn is_dlc_channel_confirmed(&self, dlc_channel_id: &DlcChannelId) -> Result<bool> {
fn is_contract_confirmed(&self, contract_id: &ContractId) -> Result<bool> {
let contract = self
.get_contract_by_id(contract_id)?
.context("Could not find contract for signed channel in state Established.")?;
Ok(matches!(contract, Contract::Confirmed { .. }))
}

fn is_dlc_channel_confirmed(&self, dlc_channel_id: &DlcChannelId) -> Result<bool> {
let channel = self.get_dlc_channel_by_id(dlc_channel_id)?;
let confirmed = match channel {
Channel::Signed(signed_channel) => match signed_channel.state {
SignedChannelState::Established {
signed_contract_id, ..
} => {
let contract = self.get_contract_by_id(&signed_contract_id)?.context(
"Could not find contract for signed channel in state Established.",
)?;
matches!(contract, Contract::Confirmed { .. })
}
} => self.is_contract_confirmed(&signed_contract_id)?,
_ => true,
},
Channel::Offered(_)
Expand Down
11 changes: 5 additions & 6 deletions mobile/native/src/dlc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -907,18 +907,17 @@ pub fn delete_dlc_channel(dlc_channel_id: &DlcChannelId) -> Result<()> {
Ok(())
}

pub fn is_dlc_channel_confirmed() -> Result<bool> {
pub async fn check_if_signed_channel_is_confirmed() -> Result<bool> {
let node = match state::try_get_node() {
Some(node) => node,
None => return Ok(false),
};

let dlc_channel = match get_signed_dlc_channel()? {
Some(dlc_channel) => dlc_channel,
None => return Ok(false),
};
let counterparty = config::get_coordinator_info().pubkey;

node.inner.is_dlc_channel_confirmed(&dlc_channel.channel_id)
node.inner
.check_if_signed_channel_is_confirmed(counterparty)
.await
}

pub fn get_fee_rate_for_target(target: ConfirmationTarget) -> FeeRate {
Expand Down
24 changes: 10 additions & 14 deletions mobile/native/src/trade/order/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::db;
use crate::db::get_order_in_filling;
use crate::db::maybe_get_open_orders;
use crate::dlc;
use crate::dlc::is_dlc_channel_confirmed;
use crate::dlc::check_if_signed_channel_is_confirmed;
use crate::event;
use crate::event::BackgroundTask;
use crate::event::EventInternal;
Expand Down Expand Up @@ -42,11 +42,8 @@ pub enum SubmitOrderError {
/// Generic problem related to the storage layer (sqlite, sled).
#[error("Storage failed: {0}")]
Storage(anyhow::Error),
#[error("DLC channel not yet confirmed: has {current_confirmations} confirmations, needs {required_confirmations}")]
UnconfirmedChannel {
current_confirmations: u64,
required_confirmations: u64,
},
#[error("DLC channel not yet confirmed")]
UnconfirmedChannel,
#[error("DLC Channel in invalid state: expected {expected_channel_state}, got {actual_channel_state}")]
InvalidChannelState {
expected_channel_state: String,
Expand Down Expand Up @@ -88,7 +85,7 @@ pub async fn submit_order_internal(
order: Order,
channel_opening_params: Option<ChannelOpeningParams>,
) -> Result<Uuid, SubmitOrderError> {
check_channel_state()?;
check_channel_state().await?;

// Having an order in `Filling` should mean that the subchannel is in the midst of an update.
// Since we currently only support one subchannel per app, it does not make sense to start
Expand Down Expand Up @@ -142,7 +139,7 @@ pub async fn submit_order_internal(
/// 1. Open position, but no channel in state [`SignedChannelState::Established`]
/// 2. Open position and not enough confirmations on the funding txid.
/// 3. No position and a channel which is not in state [`SignedChannelState::Settled`]
fn check_channel_state() -> Result<(), SubmitOrderError> {
async fn check_channel_state() -> Result<(), SubmitOrderError> {
let channel = dlc::get_signed_dlc_channel().map_err(SubmitOrderError::Storage)?;

if position::handler::get_positions()
Expand Down Expand Up @@ -171,12 +168,11 @@ fn check_channel_state() -> Result<(), SubmitOrderError> {
// If we have an open position, we should not allow any further trading until the current
// DLC channel is confirmed on-chain. Otherwise we can run into pesky DLC protocol
// failures.
if !is_dlc_channel_confirmed().map_err(SubmitOrderError::Storage)? {
// TODO: Do not hard-code confirmations.
return Err(SubmitOrderError::UnconfirmedChannel {
current_confirmations: 0,
required_confirmations: 1,
});
if !check_if_signed_channel_is_confirmed()
.await
.map_err(SubmitOrderError::Storage)?
{
return Err(SubmitOrderError::UnconfirmedChannel);
}
} else {
match channel {
Expand Down
3 changes: 1 addition & 2 deletions webapp/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use native::api::WalletHistoryItemType;
use native::calculations::calculate_pnl;
use native::channel_trade_constraints;
use native::dlc;
use native::dlc::is_dlc_channel_confirmed;
use native::trade::order::FailureReason;
use native::trade::order::InvalidSubchannelOffer;
use rust_decimal::prelude::ToPrimitive;
Expand Down Expand Up @@ -358,7 +357,7 @@ pub async fn post_new_order(params: Json<NewOrderParams>) -> Result<Json<OrderId
.try_into()
.context("Could not parse order request")?;

let is_dlc_channel_confirmed = is_dlc_channel_confirmed()?;
let is_dlc_channel_confirmed = dlc::check_if_signed_channel_is_confirmed().await?;

let channel_opening_params = if is_dlc_channel_confirmed {
None
Expand Down
Loading