Skip to content

Commit

Permalink
feat: allow custom payment metadata inside SDK storage
Browse files Browse the repository at this point in the history
Allows the user to specify and filter for external metadata in SDK payments
  • Loading branch information
hydra-yse authored Jan 12, 2024
1 parent 2073bf4 commit e914fbe
Show file tree
Hide file tree
Showing 21 changed files with 563 additions and 81 deletions.
12 changes: 11 additions & 1 deletion libs/sdk-bindings/src/breez_sdk.udl
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ enum PaymentTypeFilter {
"ClosedChannel",
};

dictionary MetadataFilter {
string json_path;
string json_value;
};

enum PaymentStatus {
"Pending",
"Complete",
Expand All @@ -221,10 +226,12 @@ dictionary Payment {
string? error;
string? description;
PaymentDetails details;
string? metadata;
};

dictionary ListPaymentsRequest {
sequence<PaymentTypeFilter>? filters = null;
sequence<MetadataFilter>? metadata_filters = null;
i64? from_timestamp = null;
i64? to_timestamp = null;
boolean? include_failures = null;
Expand Down Expand Up @@ -771,11 +778,14 @@ interface BlockingBreezServices {
[Throws=SdkError]
void backup();

[Throws=SdkError]
sequence<Payment> list_payments(ListPaymentsRequest req);

[Throws=SdkError]
Payment? payment_by_hash(string hash);

[Throws=SdkError]
sequence<Payment> list_payments(ListPaymentsRequest req);
void set_payment_metadata(string hash, string metadata);

[Throws=SdkError]
RedeemOnchainFundsResponse redeem_onchain_funds(RedeemOnchainFundsRequest req);
Expand Down
24 changes: 14 additions & 10 deletions libs/sdk-bindings/src/uniffi_binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ use breez_sdk_core::{
LnUrlPayRequest, LnUrlPayRequestData, LnUrlPayResult, LnUrlPaySuccessData,
LnUrlWithdrawRequest, LnUrlWithdrawRequestData, LnUrlWithdrawResult, LnUrlWithdrawSuccessData,
LocaleOverrides, LocalizedName, LogEntry, LogStream, LspInformation,
MaxReverseSwapAmountResponse, MessageSuccessActionData, MetadataItem, Network, NodeConfig,
NodeCredentials, NodeState, OpenChannelFeeRequest, OpenChannelFeeResponse, OpeningFeeParams,
OpeningFeeParamsMenu, Payment, PaymentDetails, PaymentFailedData, PaymentStatus, PaymentType,
PaymentTypeFilter, PrepareRedeemOnchainFundsRequest, PrepareRedeemOnchainFundsResponse,
PrepareRefundRequest, PrepareRefundResponse, Rate, ReceiveOnchainRequest,
ReceivePaymentRequest, ReceivePaymentResponse, RecommendedFees, RedeemOnchainFundsRequest,
RedeemOnchainFundsResponse, RefundRequest, RefundResponse, ReportIssueRequest,
ReportPaymentFailureDetails, ReverseSwapFeesRequest, ReverseSwapInfo, ReverseSwapPairInfo,
ReverseSwapStatus, RouteHint, RouteHintHop, SendOnchainRequest, SendOnchainResponse,
SendPaymentRequest, SendPaymentResponse, SendSpontaneousPaymentRequest,
MaxReverseSwapAmountResponse, MessageSuccessActionData, MetadataFilter, MetadataItem, Network,
NodeConfig, NodeCredentials, NodeState, OpenChannelFeeRequest, OpenChannelFeeResponse,
OpeningFeeParams, OpeningFeeParamsMenu, Payment, PaymentDetails, PaymentFailedData,
PaymentStatus, PaymentType, PaymentTypeFilter, PrepareRedeemOnchainFundsRequest,
PrepareRedeemOnchainFundsResponse, PrepareRefundRequest, PrepareRefundResponse, Rate,
ReceiveOnchainRequest, ReceivePaymentRequest, ReceivePaymentResponse, RecommendedFees,
RedeemOnchainFundsRequest, RedeemOnchainFundsResponse, RefundRequest, RefundResponse,
ReportIssueRequest, ReportPaymentFailureDetails, ReverseSwapFeesRequest, ReverseSwapInfo,
ReverseSwapPairInfo, ReverseSwapStatus, RouteHint, RouteHintHop, SendOnchainRequest,
SendOnchainResponse, SendPaymentRequest, SendPaymentResponse, SendSpontaneousPaymentRequest,
ServiceHealthCheckResponse, SignMessageRequest, SignMessageResponse, StaticBackupRequest,
StaticBackupResponse, SuccessActionProcessed, SwapInfo, SwapStatus, Symbol, TlvEntry,
UnspentTransactionOutput, UrlSuccessActionData,
Expand Down Expand Up @@ -170,6 +170,10 @@ impl BlockingBreezServices {
rt().block_on(self.breez_services.payment_by_hash(hash))
}

pub fn set_payment_metadata(&self, hash: String, metadata: String) -> SdkResult<()> {
rt().block_on(self.breez_services.set_payment_metadata(hash, metadata))
}

pub fn pay_lnurl(&self, req: LnUrlPayRequest) -> Result<LnUrlPayResult, LnUrlPayError> {
rt().block_on(self.breez_services.lnurl_pay(req))
}
Expand Down
13 changes: 13 additions & 0 deletions libs/sdk-core/src/breez_services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,13 @@ impl BreezServices {
Ok(self.persister.get_payment_by_hash(&hash)?)
}

/// Set the external metadata of a payment as a valid JSON string
pub async fn set_payment_metadata(&self, hash: String, metadata: String) -> SdkResult<()> {
Ok(self
.persister
.set_payment_external_metadata(hash, metadata)?)
}

/// Redeem on-chain funds from closed channels to the specified on-chain address, with the given feerate
pub async fn redeem_onchain_funds(
&self,
Expand Down Expand Up @@ -996,6 +1003,7 @@ impl BreezServices {
pending_expiration_block: None,
},
},
metadata: None,
}],
false,
)?;
Expand Down Expand Up @@ -1533,6 +1541,7 @@ impl BreezServices {
},
},
error: None,
metadata: None,
})
}

Expand Down Expand Up @@ -2286,6 +2295,7 @@ pub(crate) mod tests {
pending_expiration_block: None,
},
},
metadata: None,
},
Payment {
id: payment_hash_lnurl_withdraw.to_string(),
Expand All @@ -2312,6 +2322,7 @@ pub(crate) mod tests {
pending_expiration_block: None,
},
},
metadata: None,
},
Payment {
id: payment_hash_with_lnurl_success_action.to_string(),
Expand All @@ -2338,6 +2349,7 @@ pub(crate) mod tests {
pending_expiration_block: None,
},
},
metadata: None,
},
Payment {
id: hex::encode(payment_hash_swap.clone()),
Expand All @@ -2364,6 +2376,7 @@ pub(crate) mod tests {
pending_expiration_block: None,
},
},
metadata: None,
},
];
let node_api = Arc::new(MockNodeAPI::new(dummy_node_state.clone()));
Expand Down
58 changes: 58 additions & 0 deletions libs/sdk-core/src/bridge_generated.io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,15 @@ pub extern "C" fn new_box_autoadd_u64_0(value: u64) -> *mut u64 {
support::new_leak_box_ptr(value)
}

#[no_mangle]
pub extern "C" fn new_list_metadata_filter_0(len: i32) -> *mut wire_list_metadata_filter {
let wrap = wire_list_metadata_filter {
ptr: support::new_leak_vec_ptr(<wire_MetadataFilter>::new_with_null_ptr(), len),
len,
};
support::new_leak_box_ptr(wrap)
}

#[no_mangle]
pub extern "C" fn new_list_payment_type_filter_0(len: i32) -> *mut wire_list_payment_type_filter {
let wrap = wire_list_payment_type_filter {
Expand Down Expand Up @@ -690,6 +699,15 @@ impl Wire2Api<GreenlightNodeConfig> for wire_GreenlightNodeConfig {
}
}

impl Wire2Api<Vec<MetadataFilter>> for *mut wire_list_metadata_filter {
fn wire2api(self) -> Vec<MetadataFilter> {
let vec = unsafe {
let wrap = support::box_from_leak_ptr(self);
support::vec_from_leak_ptr(wrap.ptr, wrap.len)
};
vec.into_iter().map(Wire2Api::wire2api).collect()
}
}
impl Wire2Api<Vec<PaymentTypeFilter>> for *mut wire_list_payment_type_filter {
fn wire2api(self) -> Vec<PaymentTypeFilter> {
let vec = unsafe {
Expand All @@ -703,6 +721,7 @@ impl Wire2Api<ListPaymentsRequest> for wire_ListPaymentsRequest {
fn wire2api(self) -> ListPaymentsRequest {
ListPaymentsRequest {
filters: self.filters.wire2api(),
metadata_filters: self.metadata_filters.wire2api(),
from_timestamp: self.from_timestamp.wire2api(),
to_timestamp: self.to_timestamp.wire2api(),
include_failures: self.include_failures.wire2api(),
Expand Down Expand Up @@ -772,6 +791,14 @@ impl Wire2Api<LnUrlWithdrawRequestData> for wire_LnUrlWithdrawRequestData {
}
}
}
impl Wire2Api<MetadataFilter> for wire_MetadataFilter {
fn wire2api(self) -> MetadataFilter {
MetadataFilter {
json_path: self.json_path.wire2api(),
json_value: self.json_value.wire2api(),
}
}
}

impl Wire2Api<NodeConfig> for wire_NodeConfig {
fn wire2api(self) -> NodeConfig {
Expand Down Expand Up @@ -995,6 +1022,13 @@ pub struct wire_GreenlightNodeConfig {
invite_code: *mut wire_uint_8_list,
}

#[repr(C)]
#[derive(Clone)]
pub struct wire_list_metadata_filter {
ptr: *mut wire_MetadataFilter,
len: i32,
}

#[repr(C)]
#[derive(Clone)]
pub struct wire_list_payment_type_filter {
Expand All @@ -1006,6 +1040,7 @@ pub struct wire_list_payment_type_filter {
#[derive(Clone)]
pub struct wire_ListPaymentsRequest {
filters: *mut wire_list_payment_type_filter,
metadata_filters: *mut wire_list_metadata_filter,
from_timestamp: *mut i64,
to_timestamp: *mut i64,
include_failures: *mut bool,
Expand Down Expand Up @@ -1067,6 +1102,13 @@ pub struct wire_LnUrlWithdrawRequestData {
max_withdrawable: u64,
}

#[repr(C)]
#[derive(Clone)]
pub struct wire_MetadataFilter {
json_path: *mut wire_uint_8_list,
json_value: *mut wire_uint_8_list,
}

#[repr(C)]
#[derive(Clone)]
pub struct wire_OpenChannelFeeRequest {
Expand Down Expand Up @@ -1332,6 +1374,7 @@ impl NewWithNullPtr for wire_ListPaymentsRequest {
fn new_with_null_ptr() -> Self {
Self {
filters: core::ptr::null_mut(),
metadata_filters: core::ptr::null_mut(),
from_timestamp: core::ptr::null_mut(),
to_timestamp: core::ptr::null_mut(),
include_failures: core::ptr::null_mut(),
Expand Down Expand Up @@ -1434,6 +1477,21 @@ impl Default for wire_LnUrlWithdrawRequestData {
}
}

impl NewWithNullPtr for wire_MetadataFilter {
fn new_with_null_ptr() -> Self {
Self {
json_path: core::ptr::null_mut(),
json_value: core::ptr::null_mut(),
}
}
}

impl Default for wire_MetadataFilter {
fn default() -> Self {
Self::new_with_null_ptr()
}
}

impl Default for wire_NodeConfig {
fn default() -> Self {
Self::new_with_null_ptr()
Expand Down
2 changes: 2 additions & 0 deletions libs/sdk-core/src/bridge_generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ use crate::models::LnUrlWithdrawResult;
use crate::models::LnUrlWithdrawSuccessData;
use crate::models::LogEntry;
use crate::models::MaxReverseSwapAmountResponse;
use crate::models::MetadataFilter;
use crate::models::Network;
use crate::models::NodeConfig;
use crate::models::NodeCredentials;
Expand Down Expand Up @@ -1665,6 +1666,7 @@ impl support::IntoDart for Payment {
self.error.into_dart(),
self.description.into_dart(),
self.details.into_into_dart().into_dart(),
self.metadata.into_dart(),
]
.into_dart()
}
Expand Down
5 changes: 5 additions & 0 deletions libs/sdk-core/src/greenlight/node_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,7 @@ impl TryFrom<OffChainPayment> for Payment {
pending_expiration_block: None,
},
},
metadata: None,
})
}
// fn from(p: OffChainPayment) -> Self {
Expand Down Expand Up @@ -1568,6 +1569,7 @@ impl TryFrom<gl_client::signer::model::greenlight::Invoice> for Payment {
pending_expiration_block: None,
},
},
metadata: None,
})
}
}
Expand Down Expand Up @@ -1623,6 +1625,7 @@ impl TryFrom<gl_client::signer::model::greenlight::Payment> for Payment {
pending_expiration_block: None,
},
},
metadata: None,
})
}
}
Expand Down Expand Up @@ -1665,6 +1668,7 @@ impl TryFrom<cln::ListinvoicesInvoices> for Payment {
pending_expiration_block: None,
},
},
metadata: None,
})
}
}
Expand Down Expand Up @@ -1730,6 +1734,7 @@ impl TryFrom<cln::ListpaysPays> for Payment {
pending_expiration_block: None,
},
},
metadata: None,
})
}
}
Expand Down
13 changes: 12 additions & 1 deletion libs/sdk-core/src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,15 @@ pub enum PaymentTypeFilter {
ClosedChannel,
}

/// A metadata filter which can be applied when retrieving the transaction list
pub struct MetadataFilter {
/// Specifies which field to apply the filter on, using the JSON path format
pub json_path: String,
/// Specifies which JSON value to filter for.
/// As such, strings must be wrapped with quotes ("") in order to be properly filtered
pub json_value: String,
}

/// Different types of supported feerates
pub enum FeeratePreset {
Regular,
Expand Down Expand Up @@ -610,7 +619,7 @@ pub enum PaymentStatus {
Failed = 2,
}

/// Represents a payment, including its [PaymentType] and [PaymentDetails].
/// Represents a payment, including its [PaymentType] and [PaymentDetails]
#[derive(PartialEq, Eq, Debug, Clone, Serialize, Deserialize)]
pub struct Payment {
pub id: String,
Expand All @@ -623,6 +632,7 @@ pub struct Payment {
pub error: Option<String>,
pub description: Option<String>,
pub details: PaymentDetails,
pub metadata: Option<String>,
}

/// Represents a payments external information.
Expand All @@ -640,6 +650,7 @@ pub struct PaymentExternalInfo {
#[derive(Default)]
pub struct ListPaymentsRequest {
pub filters: Option<Vec<PaymentTypeFilter>>,
pub metadata_filters: Option<Vec<MetadataFilter>>,
/// Epoch time, in seconds
pub from_timestamp: Option<i64>,
/// Epoch time, in seconds
Expand Down
9 changes: 8 additions & 1 deletion libs/sdk-core/src/persist/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ pub(crate) fn current_migrations() -> Vec<&'static str> {
"SELECT 1;", // Placeholder statement, to avoid that column is added twice (from sync fn below and here)
"ALTER TABLE channels ADD COLUMN alias_local TEXT;",
"ALTER TABLE channels ADD COLUMN alias_remote TEXT;",
"ALTER TABLE channels ADD COLUMN closing_txid TEXT;"
"ALTER TABLE channels ADD COLUMN closing_txid TEXT;",
]
}

Expand Down Expand Up @@ -541,5 +541,12 @@ pub(crate) fn current_sync_migrations() -> Vec<&'static str> {
ALTER TABLE payments_external_info ADD COLUMN attempted_error TEXT;
",
"
CREATE TABLE IF NOT EXISTS payments_metadata (
payment_id TEXT NOT NULL PRIMARY KEY,
metadata TEXT,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
) STRICT;
",
]
}
Loading

0 comments on commit e914fbe

Please sign in to comment.