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

Hookup database to tx items #29

Merged
merged 3 commits 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
4 changes: 2 additions & 2 deletions migrations/2024-05-13-234832_create_config/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ CREATE TABLE on_chain_receives
operation_id TEXT PRIMARY KEY NOT NULL,
fedimint_id TEXT NOT NULL REFERENCES fedimint (id),
address TEXT NOT NULL,
amount_sats BIGINT NOT NULL,
fee_sats BIGINT NOT NULL,
amount_sats BIGINT,
fee_sats BIGINT,
txid TEXT,
status INTEGER NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
Expand Down
3 changes: 3 additions & 0 deletions src/bridge.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::components::TransactionItem;
use bitcoin::{Address, Txid};
use fedimint_core::api::InviteCode;
use fedimint_core::Amount;
Expand Down Expand Up @@ -37,6 +38,8 @@ pub enum CoreUIMsg {
ReceiveSuccess(ReceiveSuccessMsg),
ReceiveFailed(String),
BalanceUpdated(Amount),
// todo probably want a way to incrementally add items to the history
TransactionHistoryUpdated(Vec<TransactionItem>),
AddFederationFailed(String),
AddFederationSuccess,
Unlocking,
Expand Down
8 changes: 4 additions & 4 deletions src/components/transaction_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ pub enum TransactionDirection {

#[derive(Debug, Clone, Copy)]
pub struct TransactionItem {
kind: TransactionItemKind,
amount: u64,
direction: TransactionDirection,
timestamp: u64,
pub kind: TransactionItemKind,
pub amount: u64,
pub direction: TransactionDirection,
pub timestamp: u64,
}

impl TransactionItem {
Expand Down
109 changes: 92 additions & 17 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use fedimint_core::api::InviteCode;
use fedimint_core::config::FederationId;
use fedimint_core::Amount;
use fedimint_ln_client::{LightningClientModule, PayType};
use fedimint_ln_common::config::FeeToAmount;
use fedimint_ln_common::lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
use fedimint_wallet_client::WalletClientModule;
use std::collections::HashMap;
Expand Down Expand Up @@ -42,7 +43,6 @@ use crate::{
const PEG_IN_TIMEOUT_YEAR: Duration = Duration::from_secs(86400 * 365);

struct HarborCore {
balance: Amount,
network: Network,
mnemonic: Mnemonic,
tx: Sender<Message>,
Expand All @@ -62,7 +62,16 @@ impl HarborCore {

// Sends updates to the UI to refelect the initial state
async fn init_ui_state(&self) {
self.msg(CoreUIMsg::BalanceUpdated(self.balance)).await;
let mut balance = Amount::ZERO;
for client in self.clients.read().await.values() {
balance += client.fedimint_client.get_balance().await;
}

self.msg(CoreUIMsg::BalanceUpdated(balance)).await;

let history = self.storage.get_transaction_history().unwrap();
self.msg(CoreUIMsg::TransactionHistoryUpdated(history))
.await;
}

// todo for now just use the first client, but eventually we'll want to have a way to select a client
Expand All @@ -71,6 +80,11 @@ impl HarborCore {
}

async fn send_lightning(&self, invoice: Bolt11Invoice) -> anyhow::Result<()> {
if invoice.amount_milli_satoshis().is_none() {
return Err(anyhow!("Invoice must have an amount"));
}
let amount = Amount::from_msats(invoice.amount_milli_satoshis().expect("must have amount"));

// todo go through all clients and select the first one that has enough balance
let client = self.get_client().await.fedimint_client;
let lightning_module = client.get_first_module::<LightningClientModule>();
Expand All @@ -79,18 +93,44 @@ impl HarborCore {
.await
.ok_or(anyhow!("Internal error: No gateway found for federation"))?;

let fees = gateway.fees.to_amount(&amount);

log::info!("Sending lightning invoice: {invoice}, paying fees: {fees}");

let outgoing = lightning_module
.pay_bolt11_invoice(Some(gateway), invoice, ())
.pay_bolt11_invoice(Some(gateway), invoice.clone(), ())
.await?;

self.storage.create_lightning_payment(
outgoing.payment_type.operation_id(),
client.federation_id(),
invoice,
amount,
fees,
)?;

match outgoing.payment_type {
PayType::Internal(op_id) => {
let sub = lightning_module.subscribe_internal_pay(op_id).await?;
spawn_internal_payment_subscription(self.tx.clone(), client.clone(), sub).await;
spawn_internal_payment_subscription(
self.tx.clone(),
client.clone(),
self.storage.clone(),
op_id,
sub,
)
.await;
}
PayType::Lightning(op_id) => {
let sub = lightning_module.subscribe_ln_pay(op_id).await?;
spawn_invoice_payment_subscription(self.tx.clone(), client.clone(), sub).await;
spawn_invoice_payment_subscription(
self.tx.clone(),
client.clone(),
self.storage.clone(),
op_id,
sub,
)
.await;
}
}

Expand All @@ -108,7 +148,7 @@ impl HarborCore {
.ok_or(anyhow!("Internal error: No gateway found for federation"))?;

let desc = Description::new(String::new()).expect("empty string is valid");
let (op_id, invoice, _) = lightning_module
let (op_id, invoice, preimage) = lightning_module
.create_bolt11_invoice(
amount,
Bolt11InvoiceDescription::Direct(&desc),
Expand All @@ -118,11 +158,27 @@ impl HarborCore {
)
.await?;

println!("{}", invoice);
log::info!("Invoice created: {invoice}");

self.storage.create_ln_receive(
op_id,
client.federation_id(),
invoice.clone(),
amount,
Amount::ZERO, // todo one day there will be receive fees
preimage,
)?;

// Create subscription to operation if it exists
if let Ok(subscription) = lightning_module.subscribe_ln_receive(op_id).await {
spawn_invoice_receive_subscription(self.tx.clone(), client.clone(), subscription).await;
spawn_invoice_receive_subscription(
self.tx.clone(),
client.clone(),
self.storage.clone(),
op_id,
subscription,
)
.await;
} else {
error!("Could not create subscription to lightning receive");
}
Expand All @@ -141,12 +197,27 @@ impl HarborCore {
let fees = onchain.get_withdraw_fees(address.clone(), amount).await?;

let op_id = onchain
.withdraw(address, bitcoin::Amount::from_sat(sats), fees, ())
.withdraw(address.clone(), bitcoin::Amount::from_sat(sats), fees, ())
.await?;

self.storage.create_onchain_payment(
op_id,
client.federation_id(),
address,
amount.to_sat(),
fees.amount().to_sat(),
)?;

let sub = onchain.subscribe_withdraw_updates(op_id).await?;

spawn_onchain_payment_subscription(self.tx.clone(), client.clone(), sub).await;
spawn_onchain_payment_subscription(
self.tx.clone(),
client.clone(),
self.storage.clone(),
op_id,
sub,
)
.await;

Ok(())
}
Expand All @@ -161,9 +232,19 @@ impl HarborCore {

let (op_id, address) = onchain.get_deposit_address(valid_until, ()).await?;

self.storage
.create_onchain_receive(op_id, client.federation_id(), address.clone())?;

let sub = onchain.subscribe_deposit_updates(op_id).await?;

spawn_onchain_receive_subscription(self.tx.clone(), client.clone(), sub).await;
spawn_onchain_receive_subscription(
self.tx.clone(),
client.clone(),
self.storage.clone(),
op_id,
sub,
)
.await;

Ok(address)
}
Expand Down Expand Up @@ -268,14 +349,8 @@ pub fn run_core() -> Subscription<Message> {
clients.insert(client.fedimint_client.federation_id(), client);
}

let mut balance = Amount::ZERO;
for client in clients.values() {
balance += client.fedimint_client.get_balance().await;
}

let core = HarborCore {
storage: db.clone(),
balance,
tx: tx.clone(),
mnemonic,
network,
Expand Down
Loading