common: adds basic function for rgb
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
parent
7598ba2aee
commit
9548429b62
|
@ -11,3 +11,4 @@ log = "0.4.20"
|
|||
anyhow = "1.0.79"
|
||||
serde = "1.0.159"
|
||||
serde_json = "1.0.95"
|
||||
rgb-common = { path = "../rgb-common" }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use rgb_common::anyhow;
|
||||
|
||||
mod plugin;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
|
|
|
@ -6,6 +6,8 @@ use serde_json as json;
|
|||
use clightningrpc_plugin::{commands::RPCCommand, plugin::Plugin};
|
||||
use clightningrpc_plugin_macros::plugin;
|
||||
|
||||
use rgb_common::anyhow;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct State;
|
||||
|
||||
|
|
|
@ -4,3 +4,27 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
|
||||
bitcoin = { version = "0.29.0", default-features = false, features = ["secp-recovery"] }
|
||||
lightning = "0.0.118"
|
||||
|
||||
amplify = "=4.5.0"
|
||||
base64 = "0.13.0"
|
||||
bp-core = "=0.10.11"
|
||||
commit_verify = "=0.10.6"
|
||||
futures = "0.3"
|
||||
hex = "0.4"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["json", "blocking"] }
|
||||
rgb-contracts = { version = "=0.10.2", features = ["electrum"] }
|
||||
rgb_core = { package = "rgb-core", version = "=0.10.8" }
|
||||
rgb-lib = { git = "https://github.com/RGB-Tools/rgb-lib", branch = "rln_v0.10" }
|
||||
rgb-std = "=0.10.9"
|
||||
rgb-wallet = "=0.10.9"
|
||||
serde = { version = "^1.0", features = ["derive"] }
|
||||
serde_json = "^1.0"
|
||||
strict_encoding = "=2.6.1"
|
||||
tokio = { version = "1.36", features = ["macros", "rt-multi-thread"] }
|
||||
|
||||
# Fixing dependencies resolution :/
|
||||
amplify_num = "=0.5.1"
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
//! A module to provide RGB functionality
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use bitcoin::OutPoint as BtcOutPoint;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use bp::seals::txout::CloseMethod;
|
||||
use rgb_core::ContractId;
|
||||
|
||||
use crate::ldk;
|
||||
use crate::proxy;
|
||||
use crate::std::persistence::ConsignerError::Reveal;
|
||||
|
||||
use ldk::ln::PaymentHash;
|
||||
|
||||
/// RGB channel info
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct RgbInfo {
|
||||
/// Channel contract ID
|
||||
pub contract_id: ContractId,
|
||||
/// Channel RGB local amount
|
||||
pub local_rgb_amount: u64,
|
||||
/// Channel RGB remote amount
|
||||
pub remote_rgb_amount: u64,
|
||||
}
|
||||
|
||||
/// RGB payment info
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct RgbPaymentInfo {
|
||||
/// RGB contract ID
|
||||
pub contract_id: ContractId,
|
||||
/// RGB payment amount
|
||||
pub amount: u64,
|
||||
/// RGB local amount
|
||||
pub local_rgb_amount: u64,
|
||||
/// RGB remote amount
|
||||
pub remote_rgb_amount: u64,
|
||||
}
|
||||
|
||||
/// Get RgbPaymentInfo file
|
||||
pub fn get_rgb_payment_info(payment_hash: &PaymentHash, ldk_data_dir: &PathBuf) -> RgbPaymentInfo {
|
||||
let rgb_payment_info_path = ldk_data_dir.join(hex::encode(payment_hash.0));
|
||||
parse_rgb_payment_info(&rgb_payment_info_path)
|
||||
}
|
||||
|
||||
/// Parse RgbPaymentInfo
|
||||
pub fn parse_rgb_payment_info(rgb_payment_info_path: &PathBuf) -> RgbPaymentInfo {
|
||||
let serialized_info =
|
||||
fs::read_to_string(&rgb_payment_info_path).expect("valid rgb payment info");
|
||||
serde_json::from_str(&serialized_info).expect("valid rgb info file")
|
||||
}
|
||||
|
||||
/// Get RgbInfo file
|
||||
pub fn get_rgb_channel_info(
|
||||
channel_id: &[u8; 32],
|
||||
ldk_data_dir: &PathBuf,
|
||||
) -> anyhow::Result<(RgbInfo, PathBuf)> {
|
||||
let info_file_path = ldk_data_dir.join(hex::encode(channel_id));
|
||||
let serialized_info = fs::read_to_string(&info_file_path)?;
|
||||
let info: RgbInfo = serde_json::from_str(&serialized_info)?;
|
||||
Ok((info, info_file_path))
|
||||
}
|
||||
|
||||
/// Write RgbInfo file
|
||||
pub fn write_rgb_channel_info(path: &PathBuf, rgb_info: &RgbInfo) {
|
||||
let serialized_info = serde_json::to_string(&rgb_info).expect("valid rgb info");
|
||||
fs::write(path, serialized_info).expect("able to write")
|
||||
}
|
||||
|
||||
/// Rename RgbInfo file to channel_id
|
||||
pub(crate) fn rename_rgbinfo_file(
|
||||
channel_id: &[u8; 32],
|
||||
temporary_channel_id: &[u8; 32],
|
||||
ldk_data_dir: &PathBuf,
|
||||
) {
|
||||
let temporary_channel_id_path = ldk_data_dir.join(hex::encode(temporary_channel_id));
|
||||
let channel_id_path = ldk_data_dir.join(hex::encode(channel_id));
|
||||
fs::rename(temporary_channel_id_path, channel_id_path).expect("rename ok");
|
||||
}
|
||||
|
||||
/// Update RGB channel amount
|
||||
pub(crate) fn update_rgb_channel_amount(
|
||||
channel_id: &[u8; 32],
|
||||
rgb_offered_htlc: u64,
|
||||
rgb_received_htlc: u64,
|
||||
ldk_data_dir: &PathBuf,
|
||||
) -> anyhow::Result<()> {
|
||||
let (mut rgb_info, info_file_path) = get_rgb_channel_info(channel_id, ldk_data_dir)?;
|
||||
|
||||
if rgb_offered_htlc > rgb_received_htlc {
|
||||
let spent = rgb_offered_htlc - rgb_received_htlc;
|
||||
rgb_info.local_rgb_amount -= spent;
|
||||
rgb_info.remote_rgb_amount += spent;
|
||||
} else {
|
||||
let received = rgb_received_htlc - rgb_offered_htlc;
|
||||
rgb_info.local_rgb_amount += received;
|
||||
rgb_info.remote_rgb_amount -= received;
|
||||
}
|
||||
|
||||
write_rgb_channel_info(&info_file_path, &rgb_info);
|
||||
Ok(())
|
||||
}
|
|
@ -1 +1,16 @@
|
|||
mod comm;
|
||||
mod proxy;
|
||||
mod rgb_manager;
|
||||
|
||||
use lightning as ldk;
|
||||
use reqwest::blocking::Client as BlockingClient;
|
||||
|
||||
pub use anyhow;
|
||||
// Re-exporting RGB dependencies under a single module.
|
||||
pub use rgb;
|
||||
pub use rgb::interface::rgb20 as asset20;
|
||||
pub use rgb_core as core;
|
||||
pub use rgb_lib as lib;
|
||||
pub use rgb_manager::RGBManager;
|
||||
pub use rgbstd as std;
|
||||
pub use rgbwallet as wallet;
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
//! A module for operating an RGB HTTP JSON-RPC proxy
|
||||
|
||||
use amplify::s;
|
||||
use reqwest::header::CONTENT_TYPE;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::task;
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::BlockingClient;
|
||||
|
||||
const JSON: &str = "application/json";
|
||||
const PROXY_TIMEOUT: u8 = 90;
|
||||
|
||||
/// JSON-RPC Error
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct JsonRpcError {
|
||||
pub(crate) code: i64,
|
||||
message: String,
|
||||
}
|
||||
|
||||
/// JSON-RPC request
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct JsonRpcRequest<P> {
|
||||
method: String,
|
||||
jsonrpc: String,
|
||||
id: Option<String>,
|
||||
params: Option<P>,
|
||||
}
|
||||
|
||||
/// JSON-RPC response
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct JsonRpcResponse<R> {
|
||||
id: Option<String>,
|
||||
pub(crate) result: Option<R>,
|
||||
pub(crate) error: Option<JsonRpcError>,
|
||||
}
|
||||
|
||||
/// Blinded UTXO parameter
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct BlindedUtxoParam {
|
||||
blinded_utxo: String,
|
||||
}
|
||||
|
||||
pub(crate) fn get_blocking_client() -> BlockingClient {
|
||||
BlockingClient::builder()
|
||||
.timeout(Duration::from_secs(PROXY_TIMEOUT as u64))
|
||||
.build()
|
||||
.expect("valid proxy")
|
||||
}
|
||||
|
||||
pub(crate) fn get_consignment(
|
||||
url: &str,
|
||||
consignment_id: String,
|
||||
) -> Result<JsonRpcResponse<String>, reqwest::Error> {
|
||||
task::block_in_place(|| {
|
||||
let body = JsonRpcRequest {
|
||||
method: s!("consignment.get"),
|
||||
jsonrpc: s!("2.0"),
|
||||
id: None,
|
||||
params: Some(BlindedUtxoParam {
|
||||
blinded_utxo: consignment_id,
|
||||
}),
|
||||
};
|
||||
get_blocking_client()
|
||||
.post(url)
|
||||
.header(CONTENT_TYPE, JSON)
|
||||
.json(&body)
|
||||
.send()?
|
||||
.json::<JsonRpcResponse<String>>()
|
||||
})
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//! RGB Manager
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::lib::wallet::{DatabaseType, Wallet, WalletData};
|
||||
use crate::lib::BitcoinNetwork;
|
||||
use crate::proxy;
|
||||
|
||||
pub struct RGBManager {
|
||||
proxy_client: Arc<crate::BlockingClient>,
|
||||
wallet: Arc<Mutex<Wallet>>,
|
||||
}
|
||||
|
||||
impl RGBManager {
|
||||
pub fn init(root_dir: &str, pubkey: &str, network: &str) -> anyhow::Result<Self> {
|
||||
let client = proxy::get_blocking_client();
|
||||
let wallet = Wallet::new(WalletData {
|
||||
data_dir: root_dir.to_owned(),
|
||||
bitcoin_network: BitcoinNetwork::from_str(network)?,
|
||||
database_type: DatabaseType::Sqlite,
|
||||
max_allocations_per_utxo: 11,
|
||||
pubkey: pubkey.to_owned(),
|
||||
mnemonic: None,
|
||||
vanilla_keychain: None,
|
||||
})?;
|
||||
// FIXME: go online
|
||||
// FIXME: setting up the correct proxy client URL
|
||||
Ok(Self {
|
||||
proxy_client: Arc::new(client),
|
||||
wallet: Arc::new(Mutex::new(wallet)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn wallet(&self) -> Arc<Mutex<Wallet>> {
|
||||
self.wallet.clone()
|
||||
}
|
||||
|
||||
pub fn proxy_client(&self) -> Arc<crate::BlockingClient> {
|
||||
self.proxy_client.clone()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue