bark-wallet 0.5.0

Wallet library and CLI for the bitcoin Ark protocol built by Second
Documentation
use std::str::FromStr;

use anyhow::Context;
use lightning_invoice::Bolt11Invoice;
use rusqlite::Transaction;

use super::Migration;

pub struct Migration0037 {}

impl Migration for Migration0037 {
	fn name(&self) -> &str {
		"Add settled lightning receive fact table and backfill settled lightning receives"
	}

	fn to_version(&self) -> i64 { 37 }

	fn do_migration(&self, conn: &Transaction) -> anyhow::Result<()> {
		conn.execute(
			"CREATE TABLE bark_settled_lightning_receive (
				payment_hash TEXT PRIMARY KEY,
				preimage     TEXT NOT NULL,
				invoice      TEXT NOT NULL,
				amount_sat   INTEGER NOT NULL,
				settled_at   DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now'))
			)",
			(),
		).context("failed to create bark_settled_lightning_receive table")?;

		let mut stmt = conn.prepare(
			"SELECT payment_hash, preimage, invoice,
				COALESCE(finished_at, created_at) AS settled_at
				FROM bark_pending_lightning_receive
				WHERE preimage_revealed_at IS NOT NULL",
		)?;
		let mut rows = stmt.query([])?;

		while let Some(row) = rows.next()? {
			let invoice = row.get::<_, String>("invoice")?;
			let settled_at = row.get::<_, String>("settled_at")?;
			let payment_hash = row.get::<_, String>("payment_hash")?;
			let preimage = row.get::<_, String>("preimage")?;

			let amount_sat = Bolt11Invoice::from_str(&invoice).ok()
				.and_then(|inv| inv.amount_milli_satoshis())
				.map(|msat| (msat / 1000) as i64)
				.unwrap_or(0);

			conn.execute(
				"INSERT OR IGNORE INTO bark_settled_lightning_receive
					(payment_hash, preimage, invoice, amount_sat, settled_at)
				VALUES (:payment_hash, :preimage, :invoice, :amount_sat, :settled_at)",
				rusqlite::named_params! {
					":payment_hash": payment_hash,
					":preimage": preimage,
					":invoice": invoice,
					":amount_sat": amount_sat,
					":settled_at": settled_at,
				},
			).context("failed to backfill bark_settled_lightning_receive row")?;
		}

		Ok(())
	}
}