Skip to content

Commit

Permalink
Merge pull request #3 from wbobeirne/wo/channel-api
Browse files Browse the repository at this point in the history
  • Loading branch information
benthecarman authored Sep 11, 2023
2 parents 1288715 + ae1de6d commit 9dd2824
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 5 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
```
# MutinyNet Faucet API

1. Copy `.env.sample` to `.env.local` and fill it out with bitcoind and lnd connection info
2. Run `cargo build && cargo start`

## Endpoint examples

```sh
curl -X POST \
http://localhost:3001/api/onchain \
-H 'Content-Type: application/json' \
-d '{"sats":10000,"address":"bcrt1..."}'
```

```
```sh
curl -X POST \
http://localhost:3001/api/lightning \
-H 'Content-Type: application/json' \
-d '{"bolt11": "..."}'
```

```
```sh
curl -X POST \
http://localhost:3001/api/bolt11 \
-H 'Content-Type: application/json' \
-d '{"amount_sats": 1234}'
```
```

```sh
curl -X POST \
http://localhost:3001/api/channel \
-H 'Content-Type: application/json' \
-d '{"capacity": 2468,"push_amount": 1234,"pubkey":"023...","host":"127.0.0.1:9735"}'
```
80 changes: 80 additions & 0 deletions src/channel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use serde::{Deserialize, Serialize};

use std::sync::{Arc, Mutex};
use tonic_openssl_lnd::lnrpc::{self, channel_point};

use crate::{AppState, MAX_SEND_AMOUNT};

#[derive(Clone, Deserialize)]
pub struct ChannelRequest {
capacity: i64,
push_amount: i64,
pubkey: String,
host: Option<String>,
}

#[derive(Clone, Serialize)]
pub struct ChannelResponse {
pub txid: String,
}

pub async fn open_channel(
state: Arc<Mutex<AppState>>,
payload: ChannelRequest,
) -> anyhow::Result<String> {
if payload.capacity > MAX_SEND_AMOUNT.try_into().unwrap() {
anyhow::bail!("max capacity is 10,000,000");
}
if payload.push_amount < 0 {
anyhow::bail!("push_amount must be positive");
}
if payload.push_amount > payload.capacity {
anyhow::bail!("push_amount must be less than or equal to capacity");
}

let node_pubkey_result = hex::decode(payload.pubkey.clone());
let node_pubkey = match node_pubkey_result {
Ok(pubkey) => pubkey,
Err(e) => anyhow::bail!("invalid pubkey: {}", e),
};

let channel_point = {
let mut lightning_client = state
.clone()
.lock()
.map_err(|_| anyhow::anyhow!("failed to get lock"))?
.lightning_client
.clone();

if let Some(host) = payload.host {
lightning_client
.connect_peer(lnrpc::ConnectPeerRequest {
addr: Some(lnrpc::LightningAddress {
pubkey: payload.pubkey.clone(),
host,
}),
..Default::default()
})
.await
.ok();
}

lightning_client
.open_channel_sync(lnrpc::OpenChannelRequest {
node_pubkey,
local_funding_amount: payload.capacity,
push_sat: payload.push_amount,
..Default::default()
})
.await?
.into_inner()
};

let txid = match channel_point.funding_txid {
Some(channel_point::FundingTxid::FundingTxidBytes(bytes)) => hex::encode(bytes),
Some(channel_point::FundingTxid::FundingTxidStr(string)) => string,
None => anyhow::bail!("failed to open channel"),
};

Ok(txid)
}
13 changes: 13 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ use tonic_openssl_lnd::LndLightningClient;
use tower_http::cors::{Any, CorsLayer};

mod bolt11;
mod channel;
mod lightning;
mod onchain;
mod setup;

use bolt11::{request_bolt11, Bolt11Request, Bolt11Response};
use channel::{open_channel, ChannelRequest, ChannelResponse};
use lightning::{pay_lightning, LightningRequest, LightningResponse};
use onchain::{pay_onchain, OnchainRequest, OnchainResponse};
use setup::setup;
Expand Down Expand Up @@ -57,6 +59,7 @@ async fn main() -> anyhow::Result<()> {
.route("/api/onchain", post(onchain_handler))
.route("/api/lightning", post(lightning_handler))
.route("/api/bolt11", post(bolt11_handler))
.route("/api/channel", post(channel_handler))
.with_state(state)
.layer(
CorsLayer::new()
Expand Down Expand Up @@ -105,6 +108,16 @@ async fn bolt11_handler(
Ok(Json(Bolt11Response { bolt11 }))
}

#[axum::debug_handler]
async fn channel_handler(
State(state): State<SharedState>,
Json(payload): Json<ChannelRequest>,
) -> Result<Json<ChannelResponse>, AppError> {
let txid = open_channel(state.clone(), payload.clone()).await?;

Ok(Json(ChannelResponse { txid }))
}

// Make our own error that wraps `anyhow::Error`.
struct AppError(anyhow::Error);

Expand Down
2 changes: 1 addition & 1 deletion src/onchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub async fn pay_onchain(
payload: OnchainRequest,
) -> anyhow::Result<String> {
if payload.sats > MAX_SEND_AMOUNT {
anyhow::bail!("max amount is 1,000,000");
anyhow::bail!("max amount is 10,000,000");
}

let txid = {
Expand Down

0 comments on commit 9dd2824

Please sign in to comment.