Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ tower-http = "0.6.6"
tower-service = "0.3.3"
tracing = "0.1.41"
tracing-subscriber = "0.3.19"
tsify-next = "0.5.5"
tsify-next = {version = "0.5.5", default-features = false}
uniffi = "0.28.3"
uuid = { version = "1.17.0", features = ["v7", "v4"] }
wasm-bindgen = "0.2.100"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ kotlin {
implementation("com.squareup.okio:okio:3.6.0")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
api("com.ionspin.kotlin:bignum:0.3.10")
}
}

Expand Down
16 changes: 16 additions & 0 deletions crates/breez-sdk/bindings/langs/swift/Package.resolved

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

5 changes: 4 additions & 1 deletion crates/breez-sdk/bindings/langs/swift/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ let package = Package(
products: [
.library(name: "BreezSdkSpark", targets: ["breez_sdk_sparkFFI", "BreezSdkSpark"]),
],
dependencies: [
.package(url: "https://github.com/attaswift/BigInt.git", from: "5.4.0")
],
targets: [
.binaryTarget(name: "breez_sdk_sparkFFI", path: "./breez_sdk_sparkFFI.xcframework"),
.target(name: "BreezSdkSpark", dependencies: ["breez_sdk_sparkFFI"]),
.target(name: "BreezSdkSpark", dependencies: ["breez_sdk_sparkFFI", "BigInt"]),
]
)
13 changes: 6 additions & 7 deletions crates/breez-sdk/cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub enum Command {
/// Optional amount to pay. By default is denominated in sats.
/// If a token identifier is provided, the amount will be denominated in the token base units.
#[arg(short = 'a', long)]
amount: Option<u64>,
amount: Option<u128>,

/// Optional token identifier. May only be provided if the payment request is a spark address.
#[arg(short = 't', long)]
Expand Down Expand Up @@ -310,12 +310,11 @@ pub(crate) async fn execute_command(
let payment_options =
read_payment_options(prepare_response.payment_method.clone(), rl)?;

let send_payment_response = sdk
.send_payment(SendPaymentRequest {
prepare_response,
options: payment_options,
})
.await?;
let send_payment_response = Box::pin(sdk.send_payment(SendPaymentRequest {
prepare_response,
options: payment_options,
}))
.await?;

print_value(&send_payment_response)?;
Ok(true)
Expand Down
26 changes: 25 additions & 1 deletion crates/breez-sdk/common/src/input/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ pub enum SparkAddressPaymentType {
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct TokensPaymentDetails {
pub token_identifier: Option<String>,
pub amount: Option<u64>,
pub amount: Option<u128>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -307,3 +307,27 @@ pub struct SilentPaymentAddressDetails {
pub network: BitcoinNetwork,
pub source: PaymentRequestSource,
}

// Uniffi bindings have issues if multiple crates define the same custom type. This is a workaround.
#[allow(unused_imports)]
use u128 as common_u128;

#[cfg(feature = "uniffi")]
uniffi::custom_type!(common_u128, String);

#[cfg(feature = "uniffi")]
impl crate::UniffiCustomTypeConverter for u128 {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> ::uniffi::Result<Self>
where
Self: ::std::marker::Sized,
{
val.parse::<u128>()
.map_err(uniffi::deps::anyhow::Error::msg)
}

fn from_custom(obj: Self) -> Self::Builtin {
obj.to_string()
}
}
6 changes: 6 additions & 0 deletions crates/breez-sdk/common/uniffi.kotlin-multiplatform.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ kotlin_multiplatform = true
kotlin_targets = ["jvm", "android", "native"]
kotlin_target_version = "1.9.21"
disable_java_cleaner = true

[custom_types.common_u128]
type_name = "BigInteger"
imports = [ "com.ionspin.kotlin.bignum.integer.BigInteger" ]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an issue using java.math.BigInteger in kotlin multiplatform?

Copy link
Collaborator Author

@danielgranhao danielgranhao Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC it isn't available on native Kotlin (only in JVM envs) so we can't use it in multiplatform kotlin

into_custom = "BigInteger.parseString({}, 10)"
from_custom = "{}.toString(10)"
32 changes: 32 additions & 0 deletions crates/breez-sdk/common/uniffi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,40 @@ kotlin_targets = ["jvm"]
kotlin_target_version = "1.9.21"
disable_java_cleaner = true

# Kotlin custom types
[custom_types.common_u128]
type_name = "BigInteger"
imports = [ "java.math.BigInteger" ]
into_custom = "BigInteger({})"
from_custom = "{}.toString()"

# https://mozilla.github.io/uniffi-rs/swift/configuration.html
[bindings.swift]
ffi_module_name = "breez_sdk_sparkFFI"
ffi_module_filename = "breez_sdk_commonFFI"
cdylib_name = "breez_sdk_spark_bindings"

[bindings.swift.custom_types.common_u128]
type_name = "BigUInt"
imports = [ "BigInt" ]
into_custom = "BigUInt(stringLiteral: {})"
from_custom = "{}.description"

[bindings.python.custom_types.CommonU128]
type_name = "int"
into_custom = "int({})"
from_custom = "str({})"

[bindings.typescript.customTypes.common_u128]
typeName = "bigint"
intoCustom = "BigInt({})"
fromCustom = "{}.toString()"

[bindings.go.custom_types.common_u128]
type_name = "*big.Int"
imports = [ "math/big" ]
into_custom = """
result, _ := new(big.Int).SetString({}, 10)
return result
"""
from_custom = "{}.String()"
14 changes: 7 additions & 7 deletions crates/breez-sdk/core/src/models/adaptors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl TryFrom<WalletTransfer> for Payment {
TransferStatus::Expired | TransferStatus::Returned => PaymentStatus::Failed,
_ => PaymentStatus::Pending,
};
let (fees_sat, mut amount_sat): (u64, u64) = match transfer.clone().user_request {
let (fees_sat, mut amount_sat) = match transfer.clone().user_request {
Some(user_request) => match user_request {
SspUserRequest::LightningSendRequest(r) => {
// TODO: if we have the preimage it is not pending. This is a workaround
Expand Down Expand Up @@ -137,8 +137,8 @@ impl TryFrom<WalletTransfer> for Payment {
id: transfer.id.to_string(),
payment_type,
status,
amount: amount_sat,
fees: fees_sat,
amount: amount_sat.into(),
fees: fees_sat.into(),
timestamp: match transfer.created_at.map(|t| t.duration_since(UNIX_EPOCH)) {
Some(Ok(duration)) => duration.as_secs(),
_ => 0,
Expand All @@ -152,7 +152,7 @@ impl TryFrom<WalletTransfer> for Payment {
impl Payment {
pub fn from_lightning(
payment: LightningSendPayment,
amount_sat: u64,
amount_sat: u128,
transfer_id: String,
) -> Result<Self, SdkError> {
let mut status = match payment.status {
Expand Down Expand Up @@ -185,7 +185,7 @@ impl Payment {
payment_type: PaymentType::Send,
status,
amount: amount_sat,
fees: payment.fee_sat,
fees: payment.fee_sat.into(),
timestamp: payment.created_at.cast_unsigned(),
method: PaymentMethod::Lightning,
details: Some(details),
Expand Down Expand Up @@ -214,7 +214,7 @@ impl From<Fee> for spark_wallet::Fee {
impl From<spark_wallet::TokenBalance> for TokenBalance {
fn from(value: spark_wallet::TokenBalance) -> Self {
Self {
balance: value.balance.try_into().unwrap_or_default(), // balance will be changed to u128 or similar
balance: value.balance,
token_metadata: value.token_metadata.into(),
}
}
Expand All @@ -228,7 +228,7 @@ impl From<spark_wallet::TokenMetadata> for TokenMetadata {
name: value.name,
ticker: value.ticker,
decimals: value.decimals,
max_supply: value.max_supply.try_into().unwrap_or_default(), // max_supply will be changed to u128 or similar
max_supply: value.max_supply,
is_freezable: value.is_freezable,
}
}
Expand Down
34 changes: 27 additions & 7 deletions crates/breez-sdk/core/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ pub struct Payment {
/// Status of the payment
pub status: PaymentStatus,
/// Amount in satoshis
pub amount: u64,
pub amount: u128,
/// Fee paid in satoshis
pub fees: u64,
pub fees: u128,
/// Timestamp of when the payment was created
pub timestamp: u64,
/// Method of payment. Sometimes the payment details is empty so this field
Expand All @@ -158,6 +158,26 @@ pub struct Payment {
pub details: Option<PaymentDetails>,
}

#[cfg(feature = "uniffi")]
uniffi::custom_type!(u128, String);

#[cfg(feature = "uniffi")]
impl crate::UniffiCustomTypeConverter for u128 {
type Builtin = String;

fn into_custom(val: Self::Builtin) -> ::uniffi::Result<Self>
where
Self: ::std::marker::Sized,
{
val.parse::<u128>()
.map_err(uniffi::deps::anyhow::Error::msg)
}

fn from_custom(obj: Self) -> Self::Builtin {
obj.to_string()
}
}

// TODO: fix large enum variant lint - may be done by boxing lnurl_pay_info but that requires
// some changes to the wasm bindgen macro
#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -358,7 +378,7 @@ pub struct GetInfoResponse {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct TokenBalance {
pub balance: u64,
pub balance: u128,
pub token_metadata: TokenMetadata,
}

Expand All @@ -372,7 +392,7 @@ pub struct TokenMetadata {
pub ticker: String,
/// Number of decimals the token uses
pub decimals: u32,
pub max_supply: u64,
pub max_supply: u128,
pub is_freezable: bool,
}

Expand Down Expand Up @@ -413,7 +433,7 @@ pub enum SendPaymentMethod {
address: String,
/// Fee to pay for the transaction
/// Denominated in sats if token identifier is empty, otherwise in the token base units
fee: u64,
fee: u128,
/// The presence of this field indicates that the payment is for a token
/// If empty, it is a Bitcoin payment
token_identifier: Option<String>,
Expand Down Expand Up @@ -539,7 +559,7 @@ pub struct PrepareSendPaymentRequest {
/// Amount to send. By default is denominated in sats.
/// If a token identifier is provided, the amount will be denominated in the token base units.
#[cfg_attr(feature = "uniffi", uniffi(default=None))]
pub amount: Option<u64>,
pub amount: Option<u128>,
/// If provided, the payment will be for a token
/// May only be provided if the payment request is a spark address
#[cfg_attr(feature = "uniffi", uniffi(default=None))]
Expand All @@ -552,7 +572,7 @@ pub struct PrepareSendPaymentResponse {
pub payment_method: SendPaymentMethod,
/// Amount to send. By default is denominated in sats.
/// If a token identifier is provided, the amount will be denominated in the token base units.
pub amount: u64,
pub amount: u128,
/// The presence of this field indicates that the payment is for a token
/// If empty, it is a Bitcoin payment
pub token_identifier: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion crates/breez-sdk/core/src/persist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ pub mod tests {
id: "spark_pmt123".to_string(),
payment_type: PaymentType::Send,
status: PaymentStatus::Completed,
amount: 100_000,
amount: u128::from(u64::MAX).checked_add(100_000).unwrap(),
fees: 1000,
timestamp: 5000,
method: PaymentMethod::Spark,
Expand Down
Loading