diff --git a/Cargo.lock b/Cargo.lock index f7326e1..be12484 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,7 +475,7 @@ dependencies = [ [[package]] name = "bitkitcore" -version = "0.1.55" +version = "0.1.56" dependencies = [ "android_logger", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 7394d8a..7507210 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitkitcore" -version = "0.1.55" +version = "0.1.56" edition = "2021" [lib] diff --git a/Package.swift b/Package.swift index f7a62a2..e3e0808 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.1.55" -let checksum = "273da44b44f6f47ee60471af771594f4103bdd4405b6b2f68ff5359d5a0eaf5a" +let tag = "v0.1.56" +let checksum = "6b3b2e2138f80bde3a3cbbf21f11bb194fef7299a8eebff5175c10632fc80eff" let url = "https://github.com/synonymdev/bitkit-core/releases/download/\(tag)/BitkitCore.xcframework.zip" let package = Package( diff --git a/bindings/android/gradle.properties b/bindings/android/gradle.properties index b250e08..37cce97 100644 --- a/bindings/android/gradle.properties +++ b/bindings/android/gradle.properties @@ -3,4 +3,4 @@ android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official group=com.synonym -version=0.1.55 +version=0.1.56 diff --git a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so index 82b917e..77a6803 100755 Binary files a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libpubky_app_specs-90a3a8b6be1a7a22.so b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libpubky_app_specs-90a3a8b6be1a7a22.so new file mode 100755 index 0000000..2856ba2 Binary files /dev/null and b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libpubky_app_specs-90a3a8b6be1a7a22.so differ diff --git a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so index ca524d9..c2c10b6 100755 Binary files a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libpubky_app_specs-a5b33175be180155.so b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libpubky_app_specs-a5b33175be180155.so new file mode 100755 index 0000000..9df27c8 Binary files /dev/null and b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libpubky_app_specs-a5b33175be180155.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so index 4e84767..693ebe3 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86/libpubky_app_specs-6691cf4f97b9d92f.so b/bindings/android/lib/src/main/jniLibs/x86/libpubky_app_specs-6691cf4f97b9d92f.so new file mode 100755 index 0000000..d08e98c Binary files /dev/null and b/bindings/android/lib/src/main/jniLibs/x86/libpubky_app_specs-6691cf4f97b9d92f.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so index caa9196..9c9bd9f 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86_64/libpubky_app_specs-4ad86c877f377f40.so b/bindings/android/lib/src/main/jniLibs/x86_64/libpubky_app_specs-4ad86c877f377f40.so new file mode 100755 index 0000000..8f8f793 Binary files /dev/null and b/bindings/android/lib/src/main/jniLibs/x86_64/libpubky_app_specs-4ad86c877f377f40.so differ diff --git a/bindings/ios/BitkitCore.xcframework.zip b/bindings/ios/BitkitCore.xcframework.zip index 5cb60c1..5377165 100644 Binary files a/bindings/ios/BitkitCore.xcframework.zip and b/bindings/ios/BitkitCore.xcframework.zip differ diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a index e1f3684..31b558a 100644 Binary files a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a and b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/libbitkitcore.a differ diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a b/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a index 9a78996..f9b2cae 100644 Binary files a/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a and b/bindings/ios/BitkitCore.xcframework/ios-arm64/libbitkitcore.a differ diff --git a/bindings/python/bitkitcore/libbitkitcore.dylib b/bindings/python/bitkitcore/libbitkitcore.dylib index da11ccc..ad6108a 100755 Binary files a/bindings/python/bitkitcore/libbitkitcore.dylib and b/bindings/python/bitkitcore/libbitkitcore.dylib differ diff --git a/src/modules/scanner/implementation.rs b/src/modules/scanner/implementation.rs index 6d7e091..72e47a1 100644 --- a/src/modules/scanner/implementation.rs +++ b/src/modules/scanner/implementation.rs @@ -266,7 +266,8 @@ impl Scanner { Bolt11Invoice::from_str(invoice_str).map_err(|_| DecodingError::InvalidFormat)?; let network = NetworkType::from(bolt11_invoice.network()); - let amount_satoshis: u64 = bolt11_invoice.amount_milli_satoshis().unwrap_or(0) / 1000u64; + let amount_msat: u64 = bolt11_invoice.amount_milli_satoshis().unwrap_or(0); + let amount_satoshis: u64 = amount_msat.div_ceil(1000); let is_expired = bolt11_invoice.is_expired(); let timestamp = DateTime::::from_timestamp( diff --git a/src/modules/scanner/tests.rs b/src/modules/scanner/tests.rs index f9576b1..ea18f1f 100644 --- a/src/modules/scanner/tests.rs +++ b/src/modules/scanner/tests.rs @@ -2,6 +2,31 @@ mod tests { use crate::{DecodingError, Scanner}; + /// Helper to create a signed BOLT11 invoice string with a specific msat amount. + fn create_test_invoice_with_msat(amount_msat: u64) -> String { + use bitcoin::hashes::Hash; + use bitcoin::secp256k1::{Secp256k1, SecretKey}; + use lightning_invoice::{Currency, InvoiceBuilder}; + + let secp = Secp256k1::new(); + let secret_key = SecretKey::from_slice(&[0xab; 32]).unwrap(); + + let payment_hash = [0u8; 32]; + let payment_secret = [0u8; 32]; + + let invoice = InvoiceBuilder::new(Currency::Bitcoin) + .amount_milli_satoshis(amount_msat) + .description("test invoice".to_string()) + .payment_hash(bitcoin::hashes::sha256::Hash::from_byte_array(payment_hash)) + .payment_secret(lightning_invoice::PaymentSecret(payment_secret)) + .current_timestamp() + .min_final_cltv_expiry_delta(144) + .build_signed(|hash| secp.sign_ecdsa_recoverable(hash, &secret_key)) + .unwrap(); + + invoice.to_string() + } + #[tokio::test] async fn test_lightning_invoice_decode() { let invoice = "lightning:lnbc543210n1pnjdrvfpp5s720f4z6wzvjwpdnrlpffgct375l46yu9c6cpe7gdvvdfay47cnsdqqcqzzsxqrrsssp53uty4kfw8k3wmw4ga802udavz7e64tc7dmaz2cmtkj9srfxaq3ps9p4gqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqysgqwl2tdhzm9e6mtedt7a4263yw7dqxehdwjnjk23r4g8tuppk6rs994f6scunwsev3w207tjldwkpdt32rcegzphgk05c0lctv8he7smgqyfn5xq".to_string(); @@ -231,4 +256,51 @@ mod tests { _ => assert!(false, "Should be an OnChain invoice"), } } + + /// Helper to decode a test invoice and return amount_satoshis. + async fn decode_invoice_sats(amount_msat: u64) -> u64 { + let bolt11 = create_test_invoice_with_msat(amount_msat); + match Scanner::decode(bolt11).await.unwrap() { + Scanner::Lightning { invoice } => invoice.amount_satoshis, + _ => panic!("Should be a Lightning invoice"), + } + } + + #[tokio::test] + async fn test_lightning_invoice_sub_satoshi_amount_rounds_up() { + // 18557538 msat = 18557.538 sats, must round up to avoid underpayment + assert_eq!(decode_invoice_sats(18557538).await, 18558); + } + + #[tokio::test] + async fn test_lightning_invoice_sub_satoshi_remainders() { + // Remainder > 500: 222538 msat = 222.538 sats + assert_eq!(decode_invoice_sats(222538).await, 223); + + // Remainder < 500: 222222 msat = 222.222 sats + assert_eq!(decode_invoice_sats(222222).await, 223); + + // Remainder = 500: 500500 msat = 500.500 sats + assert_eq!(decode_invoice_sats(500500).await, 501); + } + + #[tokio::test] + async fn test_lightning_invoice_exact_sat_amount() { + assert_eq!(decode_invoice_sats(3500000).await, 3500); + } + + #[tokio::test] + async fn test_lightning_invoice_msat_boundary_amounts() { + // 1 msat (smallest non-zero) + assert_eq!(decode_invoice_sats(1).await, 1); + + // 999 msat (just under 1 sat) + assert_eq!(decode_invoice_sats(999).await, 1); + + // 1000 msat (exactly 1 sat) + assert_eq!(decode_invoice_sats(1000).await, 1); + + // 1001 msat (just over 1 sat) + assert_eq!(decode_invoice_sats(1001).await, 2); + } }