Skip to content

Commit

Permalink
Save payment fee in database
Browse files Browse the repository at this point in the history
  • Loading branch information
da-kami committed Jul 17, 2023
1 parent 3a1a93a commit 404dfa1
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 18 deletions.
23 changes: 20 additions & 3 deletions coordinator/src/bin/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use anyhow::Result;
use coordinator::cli::Opts;
use coordinator::db;
use coordinator::logger;
use coordinator::metrics::collect_metrics;
use coordinator::metrics;
use coordinator::metrics::init_meter;
use coordinator::node::connection;
use coordinator::node::storage::NodeStorage;
Expand All @@ -17,6 +17,8 @@ use coordinator::settings::Settings;
use diesel::r2d2;
use diesel::r2d2::ConnectionManager;
use diesel::PgConnection;
use hex::FromHex;
use lightning::ln::PaymentHash;
use ln_dlc_node::seed::Bip39Seed;
use rand::thread_rng;
use rand::RngCore;
Expand Down Expand Up @@ -135,7 +137,7 @@ async fn main() -> Result<()> {
async move {
loop {
let node = node.clone();
spawn_blocking(move || collect_metrics(node))
spawn_blocking(move || metrics::collect(node))
.await
.expect("To spawn blocking thread");
tokio::time::sleep(PROCESS_PROMETHEUS_METRICS).await;
Expand Down Expand Up @@ -218,8 +220,23 @@ async fn main() -> Result<()> {
}
};

// Upon collab closing an expired position we cannot charge a fee using an
// invoice. This dummy hash exists in the database to
// represent zero-amount invoices.
let zero_amount_payment_hash_dummy = PaymentHash(
<[u8; 32]>::from_hex(
"6f9b8c95c2ba7b1857b19f975372308161fedf50feb78a252200135a41875210",
)
.expect("static payment hash to decode"),
);

match node
.close_position(position, closing_price, channel_id)
.close_position(
position,
closing_price,
channel_id,
zero_amount_payment_hash_dummy,
)
.await
{
Ok(_) => tracing::info!(
Expand Down
25 changes: 25 additions & 0 deletions coordinator/src/db/trades.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ use crate::orderbook::db::custom_types::Direction;
use crate::schema::trades;
use anyhow::Result;
use autometrics::autometrics;
use bitcoin::hashes::hex::ToHex;
use bitcoin::secp256k1::PublicKey;
use diesel::prelude::*;
use hex::FromHex;
use lightning::ln::PaymentHash;
use std::str::FromStr;
use time::OffsetDateTime;

Expand All @@ -21,6 +24,7 @@ struct Trade {
direction: Direction,
average_price: f32,
timestamp: OffsetDateTime,
fee_payment_hash: String,
}

#[derive(Insertable, Debug, Clone)]
Expand All @@ -34,6 +38,7 @@ struct NewTrade {
collateral: i64,
direction: Direction,
average_price: f32,
pub fee_payment_hash: String,
}

#[autometrics]
Expand All @@ -48,6 +53,22 @@ pub fn insert(
Ok(trade.into())
}

/// Returns the position by trader pub key
#[autometrics]
pub fn is_payment_hash_registered_as_trade_fee(
conn: &mut PgConnection,
payment_hash: PaymentHash,
) -> QueryResult<bool> {
let payment_hash = payment_hash.0.to_hex();

let trade = trades::table
.filter(trades::fee_payment_hash.eq(payment_hash))
.first::<Trade>(conn)
.optional()?;

Ok(trade.is_some())
}

impl From<crate::trade::models::NewTrade> for NewTrade {
fn from(value: crate::trade::models::NewTrade) -> Self {
NewTrade {
Expand All @@ -59,6 +80,7 @@ impl From<crate::trade::models::NewTrade> for NewTrade {
collateral: value.collateral,
direction: value.direction.into(),
average_price: value.average_price,
fee_payment_hash: value.fee_payment_hash.0.to_hex(),
}
}
}
Expand All @@ -77,6 +99,9 @@ impl From<Trade> for crate::trade::models::Trade {
direction: value.direction.into(),
average_price: value.average_price,
timestamp: value.timestamp,
fee_payment_hash: PaymentHash(
<[u8; 32]>::from_hex(value.fee_payment_hash).expect("payment hash to decode"),
),
}
}
}
2 changes: 1 addition & 1 deletion coordinator/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn init_meter() -> PrometheusExporter {
opentelemetry_prometheus::exporter(controller).init()
}

pub fn collect_metrics(node: Node) {
pub fn collect(node: Node) {
let cx = opentelemetry::Context::current();
position_metrics(&cx, &node);

Expand Down
29 changes: 18 additions & 11 deletions coordinator/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use dlc_manager::payout_curve::RoundingIntervals;
use dlc_manager::ChannelId;
use dlc_messages::Message;
use lightning::ln::channelmanager::ChannelDetails;
use lightning::ln::PaymentHash;
use lightning_invoice::Invoice;
use ln_dlc_node::node;
use ln_dlc_node::node::dlc_message_name;
Expand Down Expand Up @@ -124,20 +125,15 @@ impl Node {

#[autometrics]
pub async fn trade(&self, trade_params: &TradeParams) -> Result<Invoice> {
let invoice = self.fee_invoice_taker(trade_params).await?;
let _fee_payment_hash = invoice.payment_hash();

// TODO: Save this invoice in the coordinator database
// The identifier is the payment hash
// Potentially safe the order id as meta data
let (fee_payment_hash, invoice) = self.fee_invoice_taker(trade_params).await?;

match self.decide_trade_action(&trade_params.pubkey)? {
TradeAction::Open => {
ensure!(
self.settings.read().await.allow_opening_positions,
"Opening positions is disabled"
);
self.open_position(trade_params).await?
self.open_position(trade_params, fee_payment_hash).await?
}
TradeAction::Close(channel_id) => {
let peer_id = trade_params.pubkey;
Expand All @@ -154,7 +150,7 @@ impl Node {
None => bail!("Failed to find open position : {}", trade_params.pubkey),
};

self.close_position(&position, closing_price, channel_id)
self.close_position(&position, closing_price, channel_id, fee_payment_hash)
.await?
}
};
Expand All @@ -163,7 +159,11 @@ impl Node {
}

#[autometrics]
async fn open_position(&self, trade_params: &TradeParams) -> Result<()> {
async fn open_position(
&self,
trade_params: &TradeParams,
fee_payment_hash: PaymentHash,
) -> Result<()> {
let peer_id = trade_params.pubkey;
tracing::info!(%peer_id, ?trade_params, "Opening position");

Expand Down Expand Up @@ -218,11 +218,15 @@ impl Node {
// into the database doesn't, it is more likely to succeed in the new order.
// FIXME: Note, we should not create a shadow representation (position) of the DLC struct,
// but rather imply the state from the DLC.
self.persist_position_and_trade(trade_params)
self.persist_position_and_trade(trade_params, fee_payment_hash)
}

// Creates a position and a trade from the trade params
fn persist_position_and_trade(&self, trade_params: &TradeParams) -> Result<()> {
fn persist_position_and_trade(
&self,
trade_params: &TradeParams,
fee_payment_hash: PaymentHash,
) -> Result<()> {
let liquidation_price = liquidation_price(trade_params);
let margin_coordinator = margin_coordinator(trade_params);

Expand Down Expand Up @@ -258,6 +262,7 @@ impl Node {
collateral: new_position.collateral,
direction: new_position.direction,
average_price: average_entry_price,
fee_payment_hash,
},
)?;

Expand All @@ -270,6 +275,7 @@ impl Node {
position: &Position,
closing_price: Decimal,
channel_id: ChannelId,
fee_payment_hash: PaymentHash,
) -> Result<()> {
let opening_price = Decimal::try_from(position.average_entry_price)?;

Expand Down Expand Up @@ -309,6 +315,7 @@ impl Node {
collateral: position.collateral,
direction: position.direction.opposite(),
average_price: closing_price.to_f32().expect("To fit into f32"),
fee_payment_hash,
},
)?;

Expand Down
23 changes: 21 additions & 2 deletions coordinator/src/node/order_matching_fee.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
use crate::db;
use crate::node::Node;
use anyhow::Context;
use anyhow::Result;
use bitcoin::secp256k1::ThirtyTwoByteHash;
use coordinator_commons::TradeParams;
use lightning::ln::PaymentHash;
use lightning_invoice::Invoice;
use ln_dlc_node::PaymentInfo;
use orderbook_commons::order_matching_fee_taker;
use orderbook_commons::FEE_INVOICE_DESCRIPTION_PREFIX_TAKER;

/// How long the fee invoice will last for.
const INVOICE_EXPIRY: u32 = 3600;

impl Node {
pub async fn fee_invoice_taker(&self, trade_params: &TradeParams) -> Result<Invoice> {
pub async fn fee_invoice_taker(
&self,
trade_params: &TradeParams,
) -> Result<(PaymentHash, Invoice)> {
let order_id = trade_params.filled_with.order_id;
let description = format!("{FEE_INVOICE_DESCRIPTION_PREFIX_TAKER}{order_id}");

Expand All @@ -19,6 +27,17 @@ impl Node {
)
.to_sat();

self.inner.create_invoice(fee, description, INVOICE_EXPIRY)
let invoice = self
.inner
.create_invoice(fee, description, INVOICE_EXPIRY)?;

let fee_payment_hash = PaymentHash((*invoice.payment_hash()).into_32());
let fee_payment_info = PaymentInfo::from(invoice.clone());
let mut conn = self.pool.get()?;

db::payments::insert((fee_payment_hash, fee_payment_info), &mut conn)
.context("Failed to insert payment into database")?;

Ok((fee_payment_hash, invoice))
}
}
1 change: 1 addition & 0 deletions coordinator/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ diesel::table! {
direction -> DirectionType,
average_price -> Float4,
timestamp -> Timestamptz,
fee_payment_hash -> Text,
}
}

Expand Down
3 changes: 3 additions & 0 deletions coordinator/src/trade/models.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bitcoin::secp256k1::PublicKey;
use lightning::ln::PaymentHash;
use time::OffsetDateTime;
use trade::ContractSymbol;
use trade::Direction;
Expand All @@ -13,6 +14,7 @@ pub struct NewTrade {
pub collateral: i64,
pub direction: Direction,
pub average_price: f32,
pub fee_payment_hash: PaymentHash,
}

#[derive(Debug)]
Expand All @@ -27,4 +29,5 @@ pub struct Trade {
pub direction: Direction,
pub average_price: f32,
pub timestamp: OffsetDateTime,
pub fee_payment_hash: PaymentHash,
}
22 changes: 21 additions & 1 deletion crates/ln-dlc-node/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::ln::TracingLogger;
use crate::node::SubChannelManager;
use bitcoin::hashes::hex::ToHex;
use bitcoin::secp256k1::PublicKey;
use dlc_custom_signer::CustomKeysManager;
use dlc_custom_signer::CustomSigner;
Expand All @@ -15,6 +16,8 @@ use lightning::routing::gossip::P2PGossipSync;
use lightning::routing::router::DefaultRouter;
use lightning::routing::scoring::ProbabilisticScorer;
use lightning::routing::utxo::UtxoLookup;
use lightning_invoice::Invoice;
use lightning_invoice::InvoiceDescription;
use lightning_net_tokio::SocketDescriptor;
use lightning_persister::FilesystemPersister;
use ln_dlc_wallet::LnDlcWallet;
Expand Down Expand Up @@ -85,7 +88,7 @@ type RequestedScid = u64;
type FakeChannelPaymentRequests = Arc<Mutex<HashMap<RequestedScid, PublicKey>>>;
type PendingInterceptedHtlcs = Arc<Mutex<HashMap<PublicKey, (InterceptId, u64)>>>;

#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct PaymentInfo {
pub preimage: Option<PaymentPreimage>,
pub secret: Option<PaymentSecret>,
Expand Down Expand Up @@ -114,3 +117,20 @@ impl MillisatAmount {
self.0
}
}

impl From<Invoice> for PaymentInfo {
fn from(value: Invoice) -> Self {
Self {
preimage: None,
secret: Some(*value.payment_secret()),
status: HTLCStatus::Pending,
amt_msat: MillisatAmount(value.amount_milli_satoshis()),
flow: PaymentFlow::Inbound,
timestamp: OffsetDateTime::from(value.timestamp()),
description: match value.description() {
InvoiceDescription::Direct(direct) => direct.to_string(),
InvoiceDescription::Hash(hash) => hash.0.to_hex(),
},
}
}
}

0 comments on commit 404dfa1

Please sign in to comment.