Skip to content

Commit

Permalink
Draft payjoin
Browse files Browse the repository at this point in the history
  • Loading branch information
DanGould committed Sep 15, 2024
1 parent 8c5cb11 commit e88ee73
Show file tree
Hide file tree
Showing 29 changed files with 2,290 additions and 579 deletions.
1,608 changes: 1,051 additions & 557 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ tracing = "0.1.40"
tracing-opentelemetry = "0.24.0"
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
serde_with = "3.8.1"
payjoin = { version = "0.20.0", features = ["base64", "receive", "v2", "io"] }
electrum-client = "0.18.0"
reqwest = { version = "0.12.5", default-features = false, features = ["json", "rustls-tls"] }
hyper = { version = "0.14", features = ["full"] }
hyper-rustls = { version = "0.24", optional = true }
async-trait = "0.1.80"
base64 = "0.22.1"
tempfile = "3.10.1"
Expand All @@ -57,7 +60,12 @@ tonic_lnd = { version = "0.2.0", package="fedimint-tonic-lnd", features = ["ligh

[dev-dependencies]
serial_test = "*"
payjoin = { version = "0.20.0", features = ["send", "v2", "io"] }

[build-dependencies]
protobuf-src = { version = "1.1.0" }
tonic-build = { version = "0.11.0", features = ["prost"] }


[patch.crates-io.payjoin]
path = "../payjoin/payjoin"
5 changes: 5 additions & 0 deletions dev/payjoin-cli/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bitcoind_rpcuser = "rpcuser"
bitcoind_rpcpass = "rpcpassword"
bitcoind_rpchost = "http://bitcoind:18443/wallet/payjoin"
pj_endpoint = "https://payjo.in"
ohttp_relay = "https://pj.bobspacebkk.com"
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ services:
- otel-agent
- fulcrum
- mempool
- payjoin-cli
postgres:
image: postgres:14.1
environment:
Expand Down Expand Up @@ -85,6 +86,15 @@ services:
command:
- |
bitcoind -connect=bitcoind:18444
payjoin-cli:
image: dangould/payjoin-cli:latest
volumes:
- ${HOST_PROJECT_PATH:-.}/dev/payjoin-cli/config.toml:/config.toml
depends_on: [ bitcoind ]
entrypoint: [ "/bin/sh", "-c" ]
command:
- |
tail -f /dev/null
lnd:
image: lightninglabs/lnd:v0.15.4-beta
volumes:
Expand Down
5 changes: 5 additions & 0 deletions proto/api/bria.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ service BriaService {
rpc GetWalletBalanceSummary (GetWalletBalanceSummaryRequest) returns (GetWalletBalanceSummaryResponse) {}

rpc NewAddress (NewAddressRequest) returns (NewAddressResponse) {}
rpc NewUri (NewAddressRequest) returns (NewUriResponse) {}
rpc UpdateAddress (UpdateAddressRequest) returns (UpdateAddressResponse) {}
rpc ListAddresses (ListAddressesRequest) returns (ListAddressesResponse) {}
rpc GetAddress (GetAddressRequest) returns (GetAddressResponse) {}
Expand Down Expand Up @@ -186,6 +187,10 @@ message NewAddressResponse {
string address = 1;
}

message NewUriResponse {
string uri = 1;
}

message UpdateAddressRequest {
string address = 2;
optional string new_external_id = 3;
Expand Down
4 changes: 3 additions & 1 deletion src/address/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ impl Addresses {
account_id: AccountId,
address: String,
) -> Result<WalletAddress, AddressError> {
println!("find address: {:?}", address);
let rows = sqlx::query!(
r#"
SELECT b.id, e.sequence, e.event
Expand All @@ -161,7 +162,7 @@ impl Addresses {
)
.fetch_all(&self.pool)
.await?;

println!("found smth?");
if rows.is_empty() {
return Err(AddressError::AddressNotFound(address));
}
Expand All @@ -170,6 +171,7 @@ impl Addresses {
for row in rows {
events.load_event(row.sequence as usize, row.event)?;
}
println!("event loaded");
Ok(WalletAddress::try_from(events)?)
}

Expand Down
1 change: 1 addition & 0 deletions src/api/server/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ impl From<PayoutQueue> for proto::PayoutQueue {
consolidate_deprecated_keychains: payout_queue.config.consolidate_deprecated_keychains,
cpfp_payouts_after_mins: payout_queue.config.cpfp_payouts_after_mins,
cpfp_payouts_after_blocks: payout_queue.config.cpfp_payouts_after_blocks,
//can_payjoin_preempt: payout_queue.config.can_payjoin_preempt,
force_min_change_sats: payout_queue.config.force_min_change_sats.map(u64::from),
});
proto::PayoutQueue {
Expand Down
36 changes: 36 additions & 0 deletions src/api/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,42 @@ impl BriaService for Bria {
.await
}

async fn new_uri(
&self,
request: Request<NewAddressRequest>,
) -> Result<Response<NewUriResponse>, Status> {
crate::tracing::record_error(|| async move {
extract_tracing(&request);
println!("REQ");

let key = extract_api_token(&request)?;
let profile = self.app.authenticate(key).await?;
let request = request.into_inner();
let NewAddressRequest {
wallet_name,
external_id,
metadata,
} = request;

let (_, uri) = self
.app
.new_uri(
&profile,
wallet_name,
external_id,
metadata
.map(serde_json::to_value)
.transpose()
.map_err(ApplicationError::CouldNotParseIncomingMetadata)?,
)
.await?;
Ok(Response::new(NewUriResponse {
uri: uri.to_string(),
}))
})
.await
}

#[instrument(name = "bria.update_address", skip_all, fields(error, error.level, error.message), err)]
async fn update_address(
&self,
Expand Down
2 changes: 2 additions & 0 deletions src/app/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ pub enum ApplicationError {
CouldNotDecryptKey(chacha20poly1305::Error),
#[error("AddressError - Could not parse the address: {0}")]
CouldNotParseAddress(#[from] bitcoin::AddressError),
#[error("PayjoinSession")]
PayjoinSession(#[from] anyhow::Error),
}

impl From<chacha20poly1305::Error> for ApplicationError {
Expand Down
74 changes: 56 additions & 18 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
mod config;
pub mod error;

use bdk::bitcoin::{address::NetworkChecked, Amount};
use payjoin::receive::v2::SessionInitializer;
use sqlxmq::JobRunnerHandle;
use tracing::instrument;
use url::Url;

use std::collections::HashMap;
use std::{collections::HashMap, str::FromStr};

pub use config::*;
use error::*;

use crate::{
account::balance::AccountBalanceSummary,
address::*,
batch::*,
batch_inclusion::*,
descriptor::*,
fees::{self, *},
job,
ledger::*,
outbox::*,
payout::*,
payout_queue::*,
primitives::*,
profile::*,
signing_session::*,
utxo::*,
wallet::{balance::*, *},
xpub::*,
account::balance::AccountBalanceSummary, address::*, api::proto::payout, batch::*, batch_inclusion::*, descriptor::*, fees::{self, *}, job, ledger::*, outbox::*, payjoin::{config::PayjoinConfig, *}, payout::*, payout_queue::*, primitives::*, profile::*, signing_session::*, utxo::*, wallet::{balance::*, *}, xpub::*
};

#[allow(dead_code)]
Expand All @@ -40,6 +27,7 @@ pub struct App {
payout_queues: PayoutQueues,
payouts: Payouts,
batches: Batches,
// payjoin_sessions: PayjoinSessions,
signing_sessions: SigningSessions,
ledger: Ledger,
utxos: Utxos,
Expand All @@ -48,6 +36,7 @@ pub struct App {
batch_inclusion: BatchInclusion,
pool: sqlx::PgPool,
config: AppConfig,
pj: crate::payjoin::PayjoinReceiver,
}

impl App {
Expand Down Expand Up @@ -97,6 +86,15 @@ impl App {
config.jobs.respawn_all_outbox_handlers_delay,
)
.await?;
let pj = PayjoinReceiver::new(
pool.clone(),
payout_queues.clone(),
PayjoinConfig { listen_port: 8088 },
addresses.clone(),
utxos.clone(),
wallets.clone(),
config.blockchain.network,
);
let app = Self {
outbox,
profiles: Profiles::new(&pool),
Expand All @@ -114,6 +112,7 @@ impl App {
fees_client,
batch_inclusion,
config,
pj,
_runner: runner,
};
crate::profile::migration::profile_event_migration(&app.pool).await?;
Expand Down Expand Up @@ -516,6 +515,45 @@ impl App {
Ok((wallet.id, address))
}

#[instrument(name = "app.new_uri", skip(self), err)]
pub async fn new_uri(
&self,
profile: &Profile,
wallet_name: String,
external_id: Option<String>,
metadata: Option<serde_json::Value>,
) -> Result<(WalletId, String), ApplicationError> {
let wallet = self
.wallets
.find_by_name(profile.account_id, wallet_name)
.await?;
let keychain_wallet = wallet.current_keychain_wallet(&self.pool);
let addr = keychain_wallet.new_external_address().await?;
let address = Address::from(addr.address.clone());
println!("got address: {:?}", addr.address);
let mut builder = NewAddress::builder();
builder
.address(address.clone())
.account_id(profile.account_id)
.wallet_id(wallet.id)
.profile_id(profile.id)
.keychain_id(keychain_wallet.keychain_id)
.kind(bitcoin::KeychainKind::External)
.address_idx(addr.index)
.metadata(metadata);
if let Some(external_id) = external_id {
builder.external_id(external_id);
}
let new_address = builder.build().expect("Couldn't build NewUri");
self.addresses.persist_new_address(new_address).await?;
println!("init payjoin");
let (session, ohttp_keys) = crate::payjoin::init_payjoin_session(payjoin::bitcoin::Address::from_str(&address.to_string()).unwrap().assume_checked(), self.pj.clone(), profile.account_id).await?;
println!("init'd payjoin");
// TODO save session to DB
let uri = session.pj_uri_builder().amount(payjoin::bitcoin::Amount::from_sat(600_000)).build().to_string();
Ok((wallet.id, uri))
}

#[instrument(name = "app.update_address", skip(self), err)]
pub async fn update_address(
&self,
Expand Down
19 changes: 19 additions & 0 deletions src/cli/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,25 @@ impl ApiClient {
output_json(response)
}

pub async fn new_uri(
&self,
wallet: String,
external_id: Option<String>,
metadata: Option<serde_json::Value>,
) -> anyhow::Result<()> {
let request = tonic::Request::new(proto::NewAddressRequest {
wallet_name: wallet,
external_id,
metadata: metadata.map(serde_json::from_value).transpose()?,
});
let response = self
.connect()
.await?
.new_uri(self.inject_auth_token(request)?)
.await?;
output_json(response)
}

pub async fn update_address(
&self,
address: String,
Expand Down
29 changes: 29 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,25 @@ enum Command {
#[clap(short, long, value_parser = parse_json)]
metadata: Option<serde_json::Value>,
},
// Get a new BIP21 URI for a wallet
NewUri {
#[clap(
short,
long,
value_parser,
default_value = "http://localhost:2742",
env = "BRIA_API_URL"
)]
url: Option<Url>,
#[clap(env = "BRIA_API_KEY", default_value = "")]
api_key: String,
#[clap(short, long)]
wallet: String,
#[clap(short, long)]
external_id: Option<String>,
#[clap(short, long, value_parser = parse_json)]
metadata: Option<serde_json::Value>,
},
/// Update address information
UpdateAddress {
#[clap(
Expand Down Expand Up @@ -855,6 +874,16 @@ pub async fn run() -> anyhow::Result<()> {
let client = api_client(cli.bria_home, url, api_key);
client.new_address(wallet, external_id, metadata).await?;
}
Command::NewUri{
url,
api_key,
wallet,
external_id,
metadata,
} => {
let client = api_client(cli.bria_home, url, api_key);
client.new_uri(wallet, external_id, metadata).await?;
}
Command::UpdateAddress {
url,
api_key,
Expand Down
Loading

0 comments on commit e88ee73

Please sign in to comment.