riftenlabs-indexer/src/db.rs

136 lines
3.6 KiB
Rust
Raw Normal View History

2023-11-29 12:25:04 +01:00
use anyhow::Result;
use bitcoin_hashes::hex::ToHex;
use riftenlabs_defi::cauldron::ParsedContract;
use rusqlite::{params, Connection};
pub fn prepare_tables(conn: &Connection) {
conn.execute(
"CREATE TABLE utxo_funding (
new_utxo_hash TEXT PRIMARY KEY,
timestamp BIGINT,
new_utxo_txid TEXT,
new_utxo_n INT,
sats BIGINT,
token_amount BIGINT,
token_id TEXT
);",
[],
)
.unwrap();
conn.execute(
"CREATE INDEX idx_funding_timestamp ON utxo_funding (timestamp);",
[],
)
.unwrap();
conn.execute(
"CREATE TABLE utxo_spending (
spent_utxo_hash TEXT PRIMARY KEY,
timestamp BIGINT
);",
[],
)
.unwrap();
conn.execute(
"CREATE INDEX idx_spending_timestamp ON utxo_spending (timestamp);",
[],
)
.unwrap();
conn.execute(
"CREATE TABLE cfg_number (
key TEXT PRIMARY KEY,
value INT
)",
[],
)
.unwrap();
}
pub fn config_set(conn: &Connection, key: &str, value: i64) {
let mut stmt = conn
.prepare("INSERT OR REPLACE INTO cfg_number (key, value) VALUES (?, ?)")
.unwrap();
stmt.execute(params![key, value]).unwrap();
}
pub fn config_get(conn: &Connection, key: &str) -> Result<Option<i64>> {
let mut stmt = conn.prepare("SELECT value FROM cfg_number WHERE key = ?")?;
let mut row = stmt.query([key])?;
Ok(row.next()?.map(|r| r.get(0).unwrap()))
}
pub fn insert_utxo_funding(
con: &Connection,
timestamp: u32,
cauldrons: &Vec<ParsedContract>,
) -> Result<()> {
let mut statement = con
.prepare("INSERT OR IGNORE INTO utxo_funding (new_utxo_hash, timestamp, new_utxo_txid, new_utxo_n, sats, token_amount, token_id) VALUES (?, ?, ?, ?, ?, ?, ?)")?;
for c in cauldrons {
if c.new_utxo_hash.is_none() {
continue;
}
statement.execute(params![
c.new_utxo_hash.unwrap().to_hex(),
timestamp,
c.new_utxo_txid.unwrap().to_hex(),
c.new_utxo_n.unwrap(),
c.sats.unwrap(),
c.token_amount.unwrap(),
c.token_id.unwrap().to_hex(),
])?;
}
Ok(())
}
pub fn insert_utxo_spending(
conn: &Connection,
timestamp: u32,
cauldrons: &Vec<ParsedContract>,
) -> Result<()> {
let mut statement = conn.prepare(
"INSERT OR IGNORE INTO utxo_spending (spent_utxo_hash, timestamp) VALUES (?, ?)",
)?;
for c in cauldrons {
statement.execute(params![c.spent_utxo_hash.to_hex(), timestamp])?;
}
Ok(())
}
pub fn get_token_tvl(
connection: &Connection,
max_timestamp: usize,
) -> Result<Vec<(String, u64, u64)>> {
let mut statement = connection.prepare(
"
SELECT
uf.token_id,
SUM(uf.token_amount) AS total_unspent_token_amount,
SUM(uf.sats) AS total_unspent_sats
FROM
utxo_funding uf
LEFT JOIN
utxo_spending us ON uf.new_utxo_hash = us.spent_utxo_hash
WHERE
(us.timestamp IS NULL OR us.timestamp > ?)
AND uf.timestamp <= ?
GROUP BY
uf.token_id",
)?;
let tvl: Vec<(String, u64, u64)> = statement
.query_and_then([max_timestamp, max_timestamp], |row| {
let token_id: String = row.get(0)?;
let token_amount: u64 = row.get(1)?;
let sats: u64 = row.get(2)?;
Ok((token_id, token_amount, sats))
})
.unwrap()
.map(|row: Result<(String, u64, u64)>| row.unwrap())
.collect();
Ok(tvl)
}