plugin: implementing the open channel functionality
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
parent
c18eceed17
commit
a03f55cafc
|
@ -7,10 +7,10 @@ use std::io;
|
|||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use json::Value;
|
||||
use lightning_signer::bitcoin as vlsbtc;
|
||||
use lightning_signer::signer::derive::KeyDerive;
|
||||
use lightning_signer::signer::derive::NativeKeyDerive;
|
||||
use rgb_common::bitcoin::psbt::PartiallySignedTransaction;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json as json;
|
||||
|
@ -19,15 +19,18 @@ use clightningrpc_common::client::Client;
|
|||
use clightningrpc_plugin::error;
|
||||
use clightningrpc_plugin::errors::PluginError;
|
||||
use clightningrpc_plugin::{commands::RPCCommand, plugin::Plugin};
|
||||
use clightningrpc_plugin_macros::plugin;
|
||||
use clightningrpc_plugin_macros::{plugin, rpc_method};
|
||||
|
||||
use rgb_common::bitcoin::bip32::ExtendedPrivKey;
|
||||
use rgb_common::bitcoin::consensus::encode::serialize_hex;
|
||||
use rgb_common::bitcoin::consensus::Decodable;
|
||||
use rgb_common::bitcoin::hashes::hex::FromHex;
|
||||
use rgb_common::bitcoin::psbt::PartiallySignedTransaction;
|
||||
use rgb_common::RGBManager;
|
||||
use rgb_common::{anyhow, bitcoin};
|
||||
|
||||
mod walletrpc;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct State {
|
||||
/// The RGB Manager where we ask to do everything
|
||||
|
@ -77,7 +80,9 @@ pub fn build_plugin() -> anyhow::Result<Plugin<State>> {
|
|||
state: State::new(),
|
||||
dynamic: true,
|
||||
notification: [ ],
|
||||
methods: [],
|
||||
methods: [
|
||||
rgb_balance,
|
||||
],
|
||||
hooks: [],
|
||||
};
|
||||
plugin.on_init(on_init);
|
||||
|
@ -86,6 +91,11 @@ pub fn build_plugin() -> anyhow::Result<Plugin<State>> {
|
|||
Ok(plugin)
|
||||
}
|
||||
|
||||
#[rpc_method(rpc_name = "rgbbalances", description = "Return the RGB balance")]
|
||||
pub fn rgb_balance(plugin: &mut Plugin<State>, requet: Value) -> Result<Value, PluginError> {
|
||||
walletrpc::rgb_balance(plugin, requet)
|
||||
}
|
||||
|
||||
fn read_secret(file: fs::File, network: &str) -> anyhow::Result<ExtendedPrivKey> {
|
||||
let buffer = io::BufReader::new(file);
|
||||
let network = vlsbtc::Network::from_str(network)?;
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
//! RGB Wallet RPC methods
|
||||
//!
|
||||
//! Author: Vincenzo Palazzo <vincenzopalazzo@member.fsf.org>
|
||||
use std::str::FromStr;
|
||||
|
||||
use rgb_common::core::ContractId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json as json;
|
||||
use serde_json::Value;
|
||||
|
||||
use clightningrpc_plugin::error;
|
||||
use clightningrpc_plugin::errors::PluginError;
|
||||
use clightningrpc_plugin::plugin::Plugin;
|
||||
|
||||
use rgb_common::lib::wallet::Balance;
|
||||
// TODO this should be hidden inside the common crate
|
||||
use rgb_common::types::RgbInfo;
|
||||
|
||||
use crate::plugin::State;
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct RGBBalanceRequest {
|
||||
asset_id: String,
|
||||
}
|
||||
|
||||
/// Return the balance of an RGB assert
|
||||
pub fn rgb_balance(plugin: &mut Plugin<State>, request: Value) -> Result<Value, PluginError> {
|
||||
let request: RGBBalanceRequest = json::from_value(request).map_err(|err| error!("{err}"))?;
|
||||
let balance = plugin
|
||||
.state
|
||||
.manager()
|
||||
.assert_balance(request.asset_id)
|
||||
.map_err(|err| error!("{err}"));
|
||||
Ok(json::to_value(balance)?)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct RGBFundChannelRequest {
|
||||
peer_id: String,
|
||||
amount_msat: String,
|
||||
asset_id: String,
|
||||
}
|
||||
|
||||
/// Opening a RGB channel
|
||||
pub fn fund_rgb_channel(plugin: &mut Plugin<State>, request: Value) -> Result<Value, PluginError> {
|
||||
let request: RGBFundChannelRequest = json::from_value(request)?;
|
||||
|
||||
// check if the asset id is valit
|
||||
let contract_id = ContractId::from_str(&request.asset_id).map_err(|err| error!("{err}"))?;
|
||||
|
||||
let assert_balance: Balance = plugin
|
||||
.state
|
||||
.call(
|
||||
"rpcbalance",
|
||||
RGBBalanceRequest {
|
||||
asset_id: request.asset_id.clone(),
|
||||
},
|
||||
)
|
||||
.map_err(|err| error!("{err}"))?;
|
||||
|
||||
// FIXME: Check if we are connected with the peer otherwise connect to them
|
||||
|
||||
// FIXME: we need the magic of core lightning here
|
||||
let balance = request
|
||||
.amount_msat
|
||||
.parse::<u64>()
|
||||
.map_err(|err| error!("{err}"))?;
|
||||
|
||||
if balance < assert_balance.spendable {
|
||||
return Err(error!(
|
||||
"Balance avaialbe `{}` is not enough to open a channel of `{}` capacity",
|
||||
assert_balance.spendable, balance
|
||||
));
|
||||
}
|
||||
|
||||
let fundchannel: json::Value = plugin
|
||||
.state
|
||||
.call("fundchannel", json::json!({}))
|
||||
.map_err(|err| error!("{err}"))?;
|
||||
let channel_id = fundchannel["channel_id"].to_string();
|
||||
log::info!("RGB channel id `{channel_id}` created");
|
||||
|
||||
let info = RgbInfo {
|
||||
channel_id,
|
||||
contract_id,
|
||||
local_rgb_amount: balance,
|
||||
// FIXME: Check that we are not opening a dual funding channel with
|
||||
// liquidity ads
|
||||
remote_rgb_amount: 0,
|
||||
};
|
||||
|
||||
plugin
|
||||
.state
|
||||
.manager()
|
||||
.add_rgb_info(&info, true)
|
||||
.map_err(|err| error!("{err}"))?;
|
||||
Ok(json::json!({
|
||||
"info": fundchannel,
|
||||
"rgb_info": info,
|
||||
}))
|
||||
}
|
|
@ -32,9 +32,9 @@ use crate::types::RgbInfo;
|
|||
|
||||
pub struct Wallet {
|
||||
path: String,
|
||||
network: BitcoinNetwork,
|
||||
wallet: Arc<Mutex<RgbWallet>>,
|
||||
online_wallet: Option<Online>,
|
||||
pub network: BitcoinNetwork,
|
||||
pub wallet: Arc<Mutex<RgbWallet>>,
|
||||
pub online_wallet: Option<Online>,
|
||||
}
|
||||
|
||||
impl Wallet {
|
||||
|
|
|
@ -3,7 +3,7 @@ mod internal_wallet;
|
|||
mod proxy;
|
||||
mod rgb_manager;
|
||||
mod rgb_storage;
|
||||
mod types;
|
||||
pub mod types;
|
||||
|
||||
use lightning as ldk;
|
||||
use reqwest::blocking::Client as BlockingClient;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
//! RGB Manager
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use bitcoin::bip32::ExtendedPrivKey;
|
||||
use rgb_lib::wallet::Balance;
|
||||
use rgb_lib::wallet::Recipient;
|
||||
use rgb_lib::wallet::RecipientData;
|
||||
use rgb_lib::ScriptBuf;
|
||||
|
@ -16,6 +16,7 @@ use crate::proxy;
|
|||
use crate::rgb_storage as store;
|
||||
use crate::rgb_storage::RGBStorage;
|
||||
use crate::types;
|
||||
use crate::types::RgbInfo;
|
||||
|
||||
/// Static blinding costant (will be removed in the future)
|
||||
/// See https://github.com/RGB-Tools/rust-lightning/blob/80497c4086beea490b56e5b8413b7f6d86f2c042/lightning/src/rgb_utils/mod.rs#L53
|
||||
|
@ -61,6 +62,20 @@ impl RGBManager {
|
|||
self.consignment_proxy.clone()
|
||||
}
|
||||
|
||||
pub fn assert_balance(&self, asset_id: String) -> anyhow::Result<Balance> {
|
||||
let balance = self
|
||||
.wallet
|
||||
.wallet
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get_asset_balance(asset_id)?;
|
||||
Ok(balance)
|
||||
}
|
||||
|
||||
pub fn add_rgb_info(&self, info: &RgbInfo, pending: bool) -> anyhow::Result<()> {
|
||||
self.storage.write_rgb_info(&info.channel_id, pending, info)
|
||||
}
|
||||
|
||||
/// Modify the funding transaction before sign it with the node signer.
|
||||
pub fn handle_onfunding_tx(
|
||||
&self,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! RGB Storage interface
|
||||
use std::collections::HashMap;
|
||||
use std::{cell::RefCell, collections::HashMap};
|
||||
|
||||
use crate::types::RgbInfo;
|
||||
|
||||
|
@ -14,10 +14,17 @@ pub trait RGBStorage {
|
|||
fn get_rgb_channel_info_pending(&self, channel_id: &str) -> anyhow::Result<RgbInfo>;
|
||||
|
||||
fn is_channel_rgb(&self, channel_id: &str, is_pending: bool) -> anyhow::Result<bool>;
|
||||
|
||||
fn write_rgb_info(
|
||||
&self,
|
||||
channel_id: &str,
|
||||
is_pending: bool,
|
||||
info: &RgbInfo,
|
||||
) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
pub struct InMemoryStorage {
|
||||
inner: HashMap<String, String>,
|
||||
inner: RefCell<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl InMemoryStorage {
|
||||
|
@ -33,14 +40,14 @@ impl InMemoryStorage {
|
|||
impl RGBStorage for InMemoryStorage {
|
||||
fn new() -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
inner: HashMap::new(),
|
||||
inner: RefCell::new(HashMap::new()),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_rgb_channel_info(&self, channel_id: &str) -> anyhow::Result<RgbInfo> {
|
||||
let key = self.derive_channel_db_key(channel_id, false)?;
|
||||
let value = self
|
||||
.inner
|
||||
let map = self.inner.borrow();
|
||||
let value = map
|
||||
.get(&key)
|
||||
.ok_or(anyhow::anyhow!("rgb channel with key `{key}` is not found"))?;
|
||||
let info: RgbInfo = serde_json::from_str(&value)?;
|
||||
|
@ -49,8 +56,8 @@ impl RGBStorage for InMemoryStorage {
|
|||
|
||||
fn get_rgb_channel_info_pending(&self, channel_id: &str) -> anyhow::Result<RgbInfo> {
|
||||
let key = self.derive_channel_db_key(channel_id, true)?;
|
||||
let value = self
|
||||
.inner
|
||||
let map = self.inner.borrow();
|
||||
let value = map
|
||||
.get(&key)
|
||||
.ok_or(anyhow::anyhow!("rgb channel with key `{key}` is not found"))?;
|
||||
let info: RgbInfo = serde_json::from_str(&value)?;
|
||||
|
@ -59,6 +66,20 @@ impl RGBStorage for InMemoryStorage {
|
|||
|
||||
fn is_channel_rgb(&self, channel_id: &str, is_pending: bool) -> anyhow::Result<bool> {
|
||||
let key = self.derive_channel_db_key(channel_id, is_pending)?;
|
||||
Ok(self.inner.contains_key(&key))
|
||||
let map = self.inner.borrow();
|
||||
Ok(map.contains_key(&key))
|
||||
}
|
||||
|
||||
fn write_rgb_info(
|
||||
&self,
|
||||
channel_id: &str,
|
||||
is_pending: bool,
|
||||
info: &RgbInfo,
|
||||
) -> anyhow::Result<()> {
|
||||
let key = self.derive_channel_db_key(channel_id, is_pending)?;
|
||||
// FIXME: we need a lock before production
|
||||
let mut map = self.inner.borrow_mut();
|
||||
map.insert(key, serde_json::to_string(info)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use crate::std::contract::ContractId;
|
|||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct RgbInfo {
|
||||
/// Channel_id
|
||||
#[serde(skip)]
|
||||
pub channel_id: String,
|
||||
/// Channel contract ID
|
||||
pub contract_id: ContractId,
|
||||
|
|
Loading…
Reference in New Issue