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

Let the coordinator open single-funded DLC channels #2541

Merged
merged 1 commit into from
May 16, 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
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ resolver = "2"
# We are using our own fork of `rust-dlc` at least until we can drop all the LN-DLC features. Also,
# `p2pderivatives/rust-dlc#master` is missing certain patches that can only be found in the LN-DLC
# branch.
dlc-manager = { git = "https://github.com/get10101/rust-dlc", rev = "8d9920d" }
dlc-messages = { git = "https://github.com/get10101/rust-dlc", rev = "8d9920d" }
dlc = { git = "https://github.com/get10101/rust-dlc", rev = "8d9920d" }
p2pd-oracle-client = { git = "https://github.com/get10101/rust-dlc", rev = "8d9920d" }
dlc-trie = { git = "https://github.com/get10101/rust-dlc", rev = "8d9920d" }
dlc-manager = { git = "https://github.com/get10101/rust-dlc", rev = "2545d6e" }
dlc-messages = { git = "https://github.com/get10101/rust-dlc", rev = "2545d6e" }
dlc = { git = "https://github.com/get10101/rust-dlc", rev = "2545d6e" }
p2pd-oracle-client = { git = "https://github.com/get10101/rust-dlc", rev = "2545d6e" }
dlc-trie = { git = "https://github.com/get10101/rust-dlc", rev = "2545d6e" }

# We should usually track the `p2pderivatives/split-tx-experiment[-10101]` branch. For now we depend
# on a special fork which removes a panic in `rust-lightning`.
Expand Down
62 changes: 58 additions & 4 deletions coordinator/src/trade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub mod websocket;

enum TradeAction {
OpenDlcChannel,
#[allow(dead_code)]
OpenSingleFundedChannel,
OpenPosition {
channel_id: DlcChannelId,
own_payout: u64,
Expand Down Expand Up @@ -98,6 +100,18 @@ pub struct TradeExecutor {
notifier: mpsc::Sender<OrderbookMessage>,
}

/// The funds the trader will need to provide to open a DLC channel with the coordinator.
///
/// We can extend this enum with a `ForTradeCost` variant to denote that the trader has to pay for
/// everything except for transaction fees.
enum TraderRequiredLiquidity {
/// Pay for margin, collateral reserve, order-matching fees and transaction fees.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it may be worthwhile to split this enum up into the individual components like you have mentioned in your comment.

margin, collateral reserve, order-matching fees and transaction fees.

that way we can compose more easily who will pay what.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

obviously not necessary now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had an earlier version with other variants, but they were unused and I did not want to add any more dead code.

ForTradeCostAndTxFees,
/// Do not pay for anything. The trader has probably paid in a different way e.g. using
/// Lightning.
None,
}

impl TradeExecutor {
pub fn new(node: Node, notifier: mpsc::Sender<OrderbookMessage>) -> Self {
Self { node, notifier }
Expand Down Expand Up @@ -212,6 +226,26 @@ impl TradeExecutor {
collateral_reserve_coordinator,
collateral_reserve_trader,
is_stable_order,
TraderRequiredLiquidity::ForTradeCostAndTxFees,
)
.await
.context("Failed to open DLC channel")?;
}
TradeAction::OpenSingleFundedChannel => {
let collateral_reserve_coordinator = params
.coordinator_reserve
.context("Missing coordinator collateral reserve")?;
let collateral_reserve_trader = params
.trader_reserve
.context("Missing trader collateral reserve")?;

self.open_dlc_channel(
&mut connection,
&params.trade_params,
collateral_reserve_coordinator,
collateral_reserve_trader,
is_stable_order,
TraderRequiredLiquidity::None,
)
.await
.context("Failed to open DLC channel")?;
Expand Down Expand Up @@ -270,6 +304,7 @@ impl TradeExecutor {
collateral_reserve_coordinator: Amount,
collateral_reserve_trader: Amount,
stable: bool,
trader_required_utxos: TraderRequiredLiquidity,
) -> Result<()> {
let peer_id = trade_params.pubkey;

Expand Down Expand Up @@ -337,11 +372,29 @@ impl TradeExecutor {
// coordinator.
let event_id = format!("{contract_symbol}{maturity_time}");

let (offer_collateral, accept_collateral, fee_config) = match trader_required_utxos {
TraderRequiredLiquidity::ForTradeCostAndTxFees => (
margin_coordinator + collateral_reserve_coordinator.to_sat(),
margin_trader + collateral_reserve_trader + order_matching_fee,
dlc::FeeConfig::EvenSplit,
),
TraderRequiredLiquidity::None => (
margin_coordinator
+ collateral_reserve_coordinator.to_sat()
+ margin_trader
+ collateral_reserve_trader
// If the trader doesn't bring their own UTXOs, including the order matching fee
// is not strictly necessary, but it's simpler to do so.
+ order_matching_fee,
0,
dlc::FeeConfig::AllOffer,
),
};

let contract_input = ContractInput {
offer_collateral: margin_coordinator + collateral_reserve_coordinator.to_sat(),
// The accept party has do bring additional collateral to pay for the
// `order_matching_fee`.
accept_collateral: margin_trader + collateral_reserve_trader + order_matching_fee,
offer_collateral,

accept_collateral,
fee_rate,
contract_infos: vec![ContractInputInfo {
contract_descriptor,
Expand Down Expand Up @@ -370,6 +423,7 @@ impl TradeExecutor {
contract_input,
trade_params.pubkey,
protocol_id,
fee_config,
)
.await
.context("Could not propose DLC channel")?;
Expand Down
12 changes: 11 additions & 1 deletion crates/tests-e2e/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,17 @@ impl TestSetup {
// Wait for coordinator to open position.
tokio::time::sleep(std::time::Duration::from_secs(10)).await;

setup.bitcoind.mine(NB_CONFIRMATIONS as u16).await.unwrap();
if NB_CONFIRMATIONS == 0 {
// No confirmations are required to get the channel/contract `Confirmed`, but the change
// output won't be added to the on-chain balance until we get one confirmation because
// of https://github.com/get10101/10101/issues/2286.
//
// We need to know about funding transaction change outputs so that we can accurately
// assert on on-chain balance changes after DLC channels are closed on-chain.
setup.bitcoind.mine(1).await.unwrap();
} else {
setup.bitcoind.mine(NB_CONFIRMATIONS as u16).await.unwrap();
}

tokio::time::sleep(std::time::Duration::from_secs(10)).await;

Expand Down
4 changes: 4 additions & 0 deletions crates/xxi-node/src/dlc_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ impl<D: BdkStorage, S: TenTenOneStorage, N> dlc_manager::Wallet for DlcWallet<D,
base_weight_wu: u64,
lock_utxos: bool,
) -> Result<Vec<dlc_manager::Utxo>, dlc_manager::error::Error> {
if amount == 0 {
return Ok(Vec::new());
}

let network = self.on_chain_wallet.network();

let fee_rate = fee_rate.expect("always set by rust-dlc");
Expand Down
7 changes: 5 additions & 2 deletions crates/xxi-node/src/node/dlc_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ impl<D: BdkStorage, S: TenTenOneStorage + 'static, N: LnDlcStorage + Sync + Send
contract_input: ContractInput,
counterparty: PublicKey,
protocol_id: ProtocolId,
fee_config: dlc::FeeConfig,
) -> Result<(ContractId, DlcChannelId)> {
tracing::info!(
trader_id = %counterparty,
Expand Down Expand Up @@ -90,6 +91,7 @@ impl<D: BdkStorage, S: TenTenOneStorage + 'static, N: LnDlcStorage + Sync + Send
let offer_channel = dlc_manager.offer_channel(
&contract_input,
to_secp_pk_29(counterparty),
fee_config,
Some(protocol_id.into()),
)?;

Expand Down Expand Up @@ -122,8 +124,9 @@ impl<D: BdkStorage, S: TenTenOneStorage + 'static, N: LnDlcStorage + Sync + Send

tracing::info!(channel_id = %channel_id_hex, "Accepting DLC channel offer");

let (accept_channel, _channel_id, _contract_id, counter_party) =
self.dlc_manager.accept_channel(channel_id)?;
let (accept_channel, _channel_id, _contract_id, counter_party) = self
.dlc_manager
.accept_channel(channel_id, dlc::FeeConfig::EvenSplit)?;

self.event_handler.publish(NodeEvent::SendDlcMessage {
peer: to_secp_pk_30(counter_party),
Expand Down
1 change: 1 addition & 0 deletions crates/xxi-node/src/tests/dlc_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,7 @@ async fn open_channel_and_position_and_settle_position(
contract_input,
app.info.pubkey,
ProtocolId::new(),
dlc::FeeConfig::EvenSplit,
)
.await
.unwrap();
Expand Down
9 changes: 8 additions & 1 deletion mobile/native/src/dlc/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,14 @@ impl Node {
match self
.inner
.dlc_manager
.accept_channel(&channel_id)
.accept_channel(
&channel_id,
offer
.offer_channel
.fee_config
.map(dlc::FeeConfig::from)
.unwrap_or(dlc::FeeConfig::EvenSplit),
)
.map_err(anyhow::Error::new)
{
Ok((accept_channel, _, _, node_id)) => {
Expand Down
Loading