breez_sdk_spark/token_conversion/models.rs
1use flashnet::{BTC_ASSET_ADDRESS, Pool};
2use serde::{Deserialize, Serialize};
3
4use crate::SdkError;
5
6/// Default maximum slippage for conversions in basis points (0.1%)
7pub const DEFAULT_CONVERSION_MAX_SLIPPAGE_BPS: u32 = 10;
8/// Default timeout for conversion operations in seconds
9pub const DEFAULT_CONVERSION_TIMEOUT_SECS: u32 = 30;
10/// Default integrator pubkey used when executing conversions
11pub const DEFAULT_INTEGRATOR_PUBKEY: &str =
12 "037e26d9d62e0b3df2d3e66805f61de2a33914465297abf76817296a92ac3f2379";
13/// Default integrator fee BPS used when simulating/executing conversions
14pub const DEFAULT_INTEGRATOR_FEE_BPS: u32 = 5;
15
16/// Response from estimating a conversion, used when preparing a payment that requires conversion
17#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
18#[derive(Debug, Clone, Serialize)]
19pub struct ConversionEstimate {
20 /// The conversion options used for the estimate
21 pub options: ConversionOptions,
22 /// The estimated amount to be received from the conversion
23 /// Denominated in satoshis if converting from Bitcoin, otherwise in the token base units.
24 pub amount: u128,
25 /// The fee estimated for the conversion
26 /// Denominated in satoshis if converting from Bitcoin, otherwise in the token base units.
27 pub fee: u128,
28}
29
30/// The purpose of the conversion, which is used to provide context for the conversion
31/// if its related to an ongoing payment or a self-transfer.
32#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
34pub enum ConversionPurpose {
35 /// Conversion is associated with an ongoing payment
36 OngoingPayment {
37 /// The payment request of the ongoing payment
38 payment_request: String,
39 },
40 /// Conversion is for self-transfer
41 SelfTransfer,
42 /// Conversion triggered automatically
43 AutoConversion,
44}
45
46/// Specifies how to determine the conversion amount.
47#[derive(Debug, Clone)]
48pub(crate) enum ConversionAmount {
49 /// Specify the minimum output amount - the input will be calculated.
50 /// Used for payment conversions where we know the required output.
51 MinAmountOut(u128),
52 /// Specify the exact input amount - used for auto-conversion where we know the sats balance.
53 AmountIn(u128),
54}
55
56/// The status of the conversion
57#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
59pub enum ConversionStatus {
60 /// The conversion was successful
61 Completed,
62 /// The conversion failed and no refund was made yet, which requires action by the SDK to
63 /// perform the refund. This can happen if there was a failure during the conversion process.
64 RefundNeeded,
65 /// The conversion failed and a refund was made
66 Refunded,
67}
68
69#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
70#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
71pub struct ConversionInfo {
72 /// The pool id associated with the conversion
73 pub pool_id: String,
74 /// The conversion id shared by both sides of the conversion
75 pub conversion_id: String,
76 /// The status of the conversion
77 pub status: ConversionStatus,
78 /// The fee paid for the conversion
79 /// Denominated in satoshis if converting from Bitcoin, otherwise in the token base units.
80 pub fee: Option<u128>,
81 /// The purpose of the conversion
82 pub purpose: Option<ConversionPurpose>,
83}
84
85pub(crate) struct TokenConversionPool {
86 pub(crate) asset_in_address: String,
87 pub(crate) asset_out_address: String,
88 pub(crate) pool: Pool,
89}
90
91pub(crate) struct TokenConversionResponse {
92 /// The sent payment id for the conversion
93 pub(crate) sent_payment_id: String,
94 /// The received payment id for the conversion
95 pub(crate) received_payment_id: String,
96}
97
98/// Options for conversion when fulfilling a payment. When set, the SDK will
99/// perform a conversion before fulfilling the payment. If not set, the payment
100/// will only be fulfilled if the wallet has sufficient balance of the required asset.
101#[derive(Debug, Clone, Serialize)]
102#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
103pub struct ConversionOptions {
104 /// The type of conversion to perform when fulfilling the payment
105 pub conversion_type: ConversionType,
106 /// The optional maximum slippage in basis points (1/100 of a percent) allowed when
107 /// a conversion is needed to fulfill the payment. Defaults to 10 bps (0.1%) if not set.
108 /// The conversion will fail if the actual amount received is less than
109 /// `estimated_amount * (1 - max_slippage_bps / 10_000)`.
110 #[cfg_attr(feature = "uniffi", uniffi(default = None))]
111 pub max_slippage_bps: Option<u32>,
112 /// The optional timeout in seconds to wait for the conversion to complete
113 /// when fulfilling the payment. This timeout only concerns waiting for the received
114 /// payment of the conversion. If the timeout is reached before the conversion
115 /// is complete, the payment will fail. Defaults to 30 seconds if not set.
116 #[cfg_attr(feature = "uniffi", uniffi(default = None))]
117 pub completion_timeout_secs: Option<u32>,
118}
119
120#[derive(Debug, Clone, Serialize, PartialEq)]
121#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
122pub enum ConversionType {
123 /// Converting from Bitcoin to a token
124 FromBitcoin,
125 /// Converting from a token to Bitcoin
126 ToBitcoin { from_token_identifier: String },
127}
128
129impl ConversionType {
130 /// Returns the asset addresses for the conversion type
131 ///
132 /// # Arguments
133 ///
134 /// * `token_identifier` - The token identifier when converting from Bitcoin to a token
135 ///
136 /// # Returns
137 ///
138 /// Result containing:
139 /// * (String, String): A tuple containing the asset in address and asset out address
140 /// * `SdkError`: If the token identifier is required but not provided
141 pub(crate) fn as_asset_addresses(
142 &self,
143 token_identifier: Option<&String>,
144 ) -> Result<(String, String), SdkError> {
145 Ok(match self {
146 ConversionType::FromBitcoin => (
147 BTC_ASSET_ADDRESS.to_string(),
148 token_identifier
149 .ok_or(SdkError::InvalidInput(
150 "Token identifier is required for from Bitcoin conversion".to_string(),
151 ))?
152 .clone(),
153 ),
154 ConversionType::ToBitcoin {
155 from_token_identifier,
156 } => (from_token_identifier.clone(), BTC_ASSET_ADDRESS.to_string()),
157 })
158 }
159}
160
161#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
162pub struct FetchConversionLimitsRequest {
163 /// The type of conversion, either from or to Bitcoin.
164 pub conversion_type: ConversionType,
165 /// The token identifier when converting to a token.
166 #[cfg_attr(feature = "uniffi", uniffi(default = None))]
167 pub token_identifier: Option<String>,
168}
169
170#[derive(Debug, Clone, Serialize)]
171#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
172pub struct FetchConversionLimitsResponse {
173 /// The minimum amount to be converted.
174 /// Denominated in satoshis if converting from Bitcoin, otherwise in the token base units.
175 pub min_from_amount: Option<u128>,
176 /// The minimum amount to be received from the conversion.
177 /// Denominated in satoshis if converting to Bitcoin, otherwise in the token base units.
178 pub min_to_amount: Option<u128>,
179}