Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

feat: rpc client implementation #6

Merged
merged 10 commits into from
Jul 22, 2024
134 changes: 98 additions & 36 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion core/lib/via_btc_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ jsonrpsee = { workspace = true, features = [
"client",
"macros",
] }
bitcoin = "0.32.2"
bitcoincore-rpc = "0.19.0"

[dev-dependencies]
bitcoincore-rpc = "0.16.0"
rand = "0.8"
tempfile = "3.3"
63 changes: 63 additions & 0 deletions core/lib/via_btc_client/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,64 @@
use async_trait::async_trait;
use bitcoin::{Address, Network, Txid};
use bitcoin::address::NetworkUnchecked;
use crate::traits::{BitcoinOps, BitcoinRpc};
use crate::types::BitcoinClientResult;

mod rpc_client;
#[allow(unused)]
pub use rpc_client::BitcoinRpcClient;

#[allow(unused)]
pub struct BitcoinClient {
rpc: Box<dyn BitcoinRpc>,
network: Network,
sender_address: Address,
}

#[async_trait]
impl BitcoinOps for BitcoinClient {
async fn new(_rpc_url: &str) -> BitcoinClientResult<Self>
where
Self: Sized,
{
todo!()
}

async fn get_balance(&self, address: &str) -> BitcoinClientResult<u128> {
let address = address.parse::<Address<NetworkUnchecked>>()?;
// TODO: change assume_checked here
let balance = self.rpc.get_balance(&address.assume_checked()).await?;
Ok(balance as u128)
}

async fn broadcast_signed_transaction(
&self,
signed_transaction: &str,
) -> BitcoinClientResult<String> {
let txid = self.rpc.send_raw_transaction(signed_transaction).await?;
Ok(txid.to_string())
}

async fn fetch_utxos(&self, address: &str) -> BitcoinClientResult<Vec<String>> {
steph-rs marked this conversation as resolved.
Show resolved Hide resolved
let address = address.parse::<Address<NetworkUnchecked>>()?;
// TODO: change assume_checked here
let utxos = self.rpc.list_unspent(&address.assume_checked()).await?;
Ok(utxos.iter().map(|utxo| utxo.clone().to_string()).collect())
}

async fn check_tx_confirmation(&self, txid: &str) -> BitcoinClientResult<bool> {
let txid = Txid::from_raw_hash(txid.parse()?);
let _tx = self.rpc.get_transaction(&txid).await?;
todo!()
}

async fn fetch_block_height(&self) -> BitcoinClientResult<u128> {
let height = self.rpc.get_block_count().await?;
Ok(height as u128)
}

async fn fetch_and_parse_block(&self, block_height: u128) -> BitcoinClientResult<&str> {
let _block = self.rpc.get_block(block_height).await?;
todo!()
}
}
55 changes: 55 additions & 0 deletions core/lib/via_btc_client/src/client/rpc_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use async_trait::async_trait;
use bitcoin::{Address, Block, OutPoint, Transaction, Txid};

use crate::traits::BitcoinRpc;
use crate::types::BitcoinRpcResult;
use bitcoincore_rpc::{Auth, Client, RpcApi};

pub struct BitcoinRpcClient {
client: Client,
}

#[allow(unused)]
impl BitcoinRpcClient {
pub fn new(
url: &str,
rpc_user: &str,
rpc_password: &str,
) -> Result<Self, bitcoincore_rpc::Error> {
let auth = Auth::UserPass(rpc_user.to_string(), rpc_password.to_string());
let client = Client::new(url, auth)?;
Ok(Self { client })
}
}

#[allow(unused)]
#[async_trait]
impl BitcoinRpc for BitcoinRpcClient {
async fn get_balance(&self, address: &Address) -> BitcoinRpcResult<u64> {
let unspent = self.client.list_unspent(Some(1), None, Some(&[address]), None, None)?;
let balance = unspent.iter().map(|u| u.amount.to_sat()).sum();
Ok(balance)
}

async fn send_raw_transaction(&self, tx_hex: &str) -> BitcoinRpcResult<Txid> {
self.client.send_raw_transaction(tx_hex).map_err(|e| e.into())
}

async fn list_unspent(&self, address: &Address) -> BitcoinRpcResult<Vec<OutPoint>> {
let unspent = self.client.list_unspent(Some(1), None, Some(&[address]), None, None)?;
Ok(unspent.into_iter().map(|u| OutPoint {vout: u.vout, txid: u.txid}).collect())
}

async fn get_transaction(&self, txid: &Txid) -> BitcoinRpcResult<Transaction> {
self.client.get_raw_transaction(txid, None).map_err(|e| e.into())
}

async fn get_block_count(&self) -> BitcoinRpcResult<u64> {
self.client.get_block_count().map_err(|e| e.into())
}

async fn get_block(&self, block_height: u128) -> BitcoinRpcResult<Block> {
let block_hash = self.client.get_block_hash(block_height as u64)?;
self.client.get_block(&block_hash).map_err(|e| e.into())
}
}
Loading
Loading