Skip to content

Commit

Permalink
feat: phoenixd ln backend
Browse files Browse the repository at this point in the history
  • Loading branch information
thesimplekid committed Aug 29, 2024
1 parent 8ee5f62 commit cc5efd9
Show file tree
Hide file tree
Showing 17 changed files with 456 additions and 17 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ jobs:
-p cdk-sqlite,
-p cdk-axum,
-p cdk-cln,
-p cdk-fake-wallet,
-p cdk-phoenixd,
-p cdk-strike,
-p cdk-lnbits
-p cdk-integration-tests,
-p cdk-fake-wallet,
--bin cdk-cli,
--bin cdk-mintd,
]
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ cdk-sqlite = { version = "0.3", path = "./crates/cdk-sqlite", default-features =
cdk-redb = { version = "0.3", path = "./crates/cdk-redb", default-features = false }
cdk-cln = { version = "0.3", path = "./crates/cdk-cln", default-features = false }
cdk-lnbits = { version = "0.3", path = "./crates/cdk-lnbits", default-features = false }
cdk-phoenixd = { version = "0.3", path = "./crates/cdk-phoenixd", default-features = false }
cdk-axum = { version = "0.3", path = "./crates/cdk-axum", default-features = false }
cdk-fake-wallet = { version = "0.3", path = "./crates/cdk-fake-wallet", default-features = false }
cdk-strike = { version = "0.3", path = "./crates/cdk-strike", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion crates/cdk-axum/src/router_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ pub async fn get_melt_bolt11_quote(
payload.request.to_string(),
payload.unit,
payment_quote.amount,
payment_quote.fee.into(),
payment_quote.fee,
unix_time() + state.quote_ttl,
payment_quote.request_lookup_id,
)
Expand Down
5 changes: 3 additions & 2 deletions crates/cdk-cln/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub struct Cln {
}

impl Cln {
/// Create new ['Cln]
/// Create new [`Cln`]
pub async fn new(
rpc_socket: PathBuf,
fee_reserve: FeeReserve,
Expand Down Expand Up @@ -144,7 +144,8 @@ impl MintLightning for Cln {
Ok(PaymentQuoteResponse {
request_lookup_id: melt_quote_request.request.payment_hash().to_string(),
amount,
fee,
fee: fee.into(),
state: MeltQuoteState::Unpaid,
})
}

Expand Down
3 changes: 2 additions & 1 deletion crates/cdk-fake-wallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ impl MintLightning for FakeWallet {
Ok(PaymentQuoteResponse {
request_lookup_id: melt_quote_request.request.payment_hash().to_string(),
amount,
fee,
fee: fee.into(),
state: MeltQuoteState::Unpaid,
})
}

Expand Down
3 changes: 2 additions & 1 deletion crates/cdk-lnbits/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ impl MintLightning for LNbits {
Ok(PaymentQuoteResponse {
request_lookup_id: melt_quote_request.request.payment_hash().to_string(),
amount,
fee,
fee: fee.into(),
state: MeltQuoteState::Unpaid,
})
}

Expand Down
2 changes: 2 additions & 0 deletions crates/cdk-mintd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cdk-redb = { workspace = true, default-features = false, features = ["mint"] }
cdk-sqlite = { workspace = true, default-features = false, features = ["mint"] }
cdk-cln = { workspace = true, default-features = false }
cdk-lnbits = { workspace = true, default-features = false }
cdk-phoenixd = { workspace = true, default-features = false }
cdk-fake-wallet = { workspace = true, default-features = false }
cdk-strike.workspace = true
cdk-axum = { workspace = true, default-features = false }
Expand All @@ -31,3 +32,4 @@ bip39.workspace = true
tower-http = { version = "0.5.2", features = ["cors"] }
lightning-invoice.workspace = true
home.workspace = true
url.workspace = true
4 changes: 4 additions & 0 deletions crates/cdk-mintd/example.config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ ln_backend = "cln"
# admin_api_key = ""
# invoice_api_key = ""
# lnbits_api = ""

# [phoenixd]
# api_password = ""
# api_url = ""
11 changes: 9 additions & 2 deletions crates/cdk-mintd/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ pub enum LnBackend {
Strike,
LNbits,
FakeWallet,
// Greenlight,
// Ldk,
Phoenixd,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
Expand Down Expand Up @@ -53,6 +52,12 @@ pub struct Cln {
pub rpc_path: PathBuf,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Phoenixd {
pub api_password: String,
pub api_url: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FakeWallet {
pub supported_units: Vec<CurrencyUnit>,
Expand Down Expand Up @@ -87,6 +92,7 @@ pub struct Settings {
pub cln: Option<Cln>,
pub strike: Option<Strike>,
pub lnbits: Option<LNbits>,
pub phoenixd: Option<Phoenixd>,
pub fake_wallet: Option<FakeWallet>,
pub database: Database,
}
Expand Down Expand Up @@ -152,6 +158,7 @@ impl Settings {
LnBackend::Cln => assert!(settings.cln.is_some()),
LnBackend::Strike => assert!(settings.strike.is_some()),
LnBackend::LNbits => assert!(settings.lnbits.is_some()),
LnBackend::Phoenixd => assert!(settings.phoenixd.is_some()),
LnBackend::FakeWallet => (),
}

Expand Down
61 changes: 56 additions & 5 deletions crates/cdk-mintd/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;

use anyhow::{anyhow, Result};
use anyhow::{anyhow, bail, Result};
use axum::Router;
use bip39::Mnemonic;
use cdk::cdk_database::{self, MintDatabase};
Expand All @@ -24,6 +24,7 @@ use cdk_axum::LnKey;
use cdk_cln::Cln;
use cdk_fake_wallet::FakeWallet;
use cdk_lnbits::LNbits;
use cdk_phoenixd::Phoenixd;
use cdk_redb::MintRedbDatabase;
use cdk_sqlite::MintSqliteDatabase;
use cdk_strike::Strike;
Expand All @@ -34,6 +35,7 @@ use futures::StreamExt;
use tokio::sync::Mutex;
use tower_http::cors::CorsLayer;
use tracing_subscriber::EnvFilter;
use url::Url;

mod cli;
mod config;
Expand Down Expand Up @@ -84,8 +86,8 @@ async fn main() -> anyhow::Result<()> {

let mut contact_info: Option<Vec<ContactInfo>> = None;

if let Some(nostr_contact) = settings.mint_info.contact_nostr_public_key {
let nostr_contact = ContactInfo::new("nostr".to_string(), nostr_contact);
if let Some(nostr_contact) = &settings.mint_info.contact_nostr_public_key {
let nostr_contact = ContactInfo::new("nostr".to_string(), nostr_contact.to_string());

contact_info = match contact_info {
Some(mut vec) => {
Expand All @@ -96,8 +98,8 @@ async fn main() -> anyhow::Result<()> {
};
}

if let Some(email_contact) = settings.mint_info.contact_email {
let email_contact = ContactInfo::new("email".to_string(), email_contact);
if let Some(email_contact) = &settings.mint_info.contact_email {
let email_contact = ContactInfo::new("email".to_string(), email_contact.to_string());

contact_info = match contact_info {
Some(mut vec) => {
Expand Down Expand Up @@ -232,6 +234,55 @@ async fn main() -> anyhow::Result<()> {
ln_backends.insert(ln_key, Arc::new(lnbits));

supported_units.insert(unit, (input_fee_ppk, 64));
vec![router]
}
LnBackend::Phoenixd => {
let api_password = settings
.clone()
.phoenixd
.expect("Checked at config load")
.api_password;

let api_url = settings
.clone()
.phoenixd
.expect("Checked at config load")
.api_url;

if fee_reserve.percent_fee_reserve < 0.04 {
bail!("Fee reserve is too low needs to be at least 0.02");
}

let webhook_endpoint = "/webhook/phoenixd";

let mint_url = Url::parse(&settings.info.url)?;

let webhook_url = mint_url.join(webhook_endpoint)?.to_string();

let (sender, receiver) = tokio::sync::mpsc::channel(8);

let phoenixd = Phoenixd::new(
api_password.to_string(),
api_url.to_string(),
MintMeltSettings::default(),
MintMeltSettings::default(),
fee_reserve,
Arc::new(Mutex::new(Some(receiver))),
webhook_url,
)?;

let router = phoenixd
.create_invoice_webhook(webhook_endpoint, sender)
.await?;

supported_units.insert(CurrencyUnit::Sat, (input_fee_ppk, 64));
ln_backends.insert(
LnKey {
unit: CurrencyUnit::Sat,
method: PaymentMethod::Bolt11,
},
Arc::new(phoenixd),
);

vec![router]
}
Expand Down
24 changes: 24 additions & 0 deletions crates/cdk-phoenixd/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "cdk-phoenixd"
version = { workspace = true }
edition = "2021"
authors = ["CDK Developers"]
homepage.workspace = true
repository.workspace = true
rust-version.workspace = true # MSRV
license.workspace = true
description = "CDK ln backend for phoenixd"

[dependencies]
async-trait.workspace = true
anyhow.workspace = true
axum.workspace = true
bitcoin.workspace = true
cdk = { workspace = true, default-features = false, features = ["mint"] }
futures.workspace = true
tokio.workspace = true
tracing.workspace = true
thiserror.workspace = true
phoenixd-rs = "0.2.0"
# phoenixd-rs = { path = "../../../../phoenixd-rs" }
uuid.workspace = true
46 changes: 46 additions & 0 deletions crates/cdk-phoenixd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# cdk-phoenixd

## Run phoenixd

The `phoenixd` node is included in the cdk and needs to be run separately.
Get started here: [Phoenixd Server Documentation](https://phoenix.acinq.co/server/get-started)

## Start Phoenixd

By default, `phoenixd` will run with auto-liquidity enabled. While this simplifies channel management, it makes fees non-deterministic, which is not recommended for most scenarios. However, it is necessary to start with auto-liquidity enabled in order to open a channel and get started.

Start the node with auto-liquidity enabled as documented by [Phoenixd](https://phoenix.acinq.co/server/get-started):
```sh
./phoenixd
```

> **Note:** By default the `auto-liquidity` will open a channel of 2m sats depending on the size of mint you plan to run you may want to increase this by setting the `--auto-liquidity` flag to `5m` or `10m`.
## Open Channel

Once the node is running, create an invoice using the phoenixd-cli to fund your node. A portion of this deposit will go to ACINQ as a fee for the provided liquidity, and a portion will cover the mining fee. These two fees cannot be refunded or withdrawn from the node. More on fees can be found [here](https://phoenix.acinq.co/server/auto-liquidity#fees). The remainder will stay as the node balance and can be withdrawn later.
```sh
./phoenix-cli createinvoice \
--description "Fund Node" \
--amountSat xxxxx
```

> **Note:** The amount above should be set depending on the size of the mint you would like to run as it will determine the size of the channel and amount of liquidity.
## Check Channel state

After paying the invoice view that a channal has been opened.
```sh
./phoenix-cli listchannels
```

## Restart Phoenixd without `auto-liquidity`

Now that the node has a channel, it is recommended to stop the node and restart it without auto-liquidity. This will prevent phoenixd from opening new channels and incurring additional fees.
```sh
./phoenixd --auto-liquidity off
```

## Start cashu-mintd

Once the node is running following the [cashu-mintd](../cdk-mintd/README.md) to start the mint. by default the `api_url` will be `http://127.0.0.1:9740` and the `api_password` can be found in `~/.phoenix/phoenix.conf` these will need to be set in the `cdk-mintd` config file.
26 changes: 26 additions & 0 deletions crates/cdk-phoenixd/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! Error for phoenixd ln backend
use thiserror::Error;

/// Phoenixd Error
#[derive(Debug, Error)]
pub enum Error {
/// Invoice amount not defined
#[error("Unknown invoice amount")]
UnknownInvoiceAmount,
/// Unknown invoice
#[error("Unknown invoice")]
UnknownInvoice,
/// Unsupported unit
#[error("Unit Unsupported")]
UnsupportedUnit,
/// Anyhow error
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
}

impl From<Error> for cdk::cdk_lightning::Error {
fn from(e: Error) -> Self {
Self::Lightning(Box::new(e))
}
}
Loading

0 comments on commit cc5efd9

Please sign in to comment.