diff --git a/CHANGELOG.md b/CHANGELOG.md index c62b5875..cdc06639 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Add `get_activities_tags(wallet_id: Option)` and `get_pre_activity_metadata_list(wallet_id: Option)`, wallet-scoped reads of the two tag-backup tables where `None` returns every scope. Apps backing up a single wallet scope (for example a `trezor:{hash}` hardware wallet) can now name that scope in the call instead of fetching every scope and filtering client-side, so which records leave the device is visible in the FFI call. The unscoped `get_all_activities_tags()` and `get_all_pre_activity_metadata()` are unchanged and now delegate to the scoped versions. + ## 0.5.11 - 2026-08-27 - Add keep consumer rules for JNA types UniFFI needs under R8. diff --git a/Cargo.lock b/Cargo.lock index 891688c0..afb434a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -589,7 +589,7 @@ dependencies = [ [[package]] name = "bitkitcore" -version = "0.5.11" +version = "0.5.12" dependencies = [ "android_logger", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index ae688a52..0e1446fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitkitcore" -version = "0.5.11" +version = "0.5.12" edition = "2021" [lib] diff --git a/Package.swift b/Package.swift index 66a6554c..a5fd87b5 100644 --- a/Package.swift +++ b/Package.swift @@ -3,8 +3,8 @@ import PackageDescription -let tag = "v0.5.11" -let checksum = "dc5653d5f6980c498c0baa3fec675e763eb87040cb92036d97141aa2b5fcdf4d" +let tag = "v0.5.12" +let checksum = "3a107f1f08751f480960f9fa9322ea8f8411e2e2fd8bad97c8bcf0d33c39a19f" let url = "https://github.com/synonymdev/bitkit-core/releases/download/\(tag)/BitkitCore.xcframework.zip" let package = Package( diff --git a/README.md b/README.md index 7df8a2e7..2f03553c 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,10 @@ ```rust fn get_all_unique_tags() -> Result, ActivityError> ``` + - [get_activities_tags](src/modules/activity/README.md#usage-examples): Get activity tags for one wallet scope, or every scope when `wallet_id` is `None` + ```rust + fn get_activities_tags(wallet_id: Option) -> Result, ActivityError> + ``` - [get_activities_by_tag](src/modules/activity/README.md#usage-examples): Get activities with a specific tag and optional wallet scope ```rust fn get_activities_by_tag( @@ -205,6 +209,10 @@ search_by_address: bool ) -> Result, ActivityError> ``` + - [get_pre_activity_metadata_list](src/modules/activity/README.md#usage-examples): Get pending metadata for one wallet scope, or every scope when `wallet_id` is `None` + ```rust + fn get_pre_activity_metadata_list(wallet_id: Option) -> Result, ActivityError> + ``` - [add_pre_activity_metadata_tags](src/modules/activity/README.md#usage-examples): Add tags to pending metadata ```rust fn add_pre_activity_metadata_tags(wallet_id: String, payment_id: String, tags: Vec) -> Result<(), ActivityError> diff --git a/bindings/android/gradle.properties b/bindings/android/gradle.properties index 3df387ee..2394f959 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.5.11 +version=0.5.12 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 2c95c185..1f2e8047 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/armeabi-v7a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so index 54dac774..14ea5bc2 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/x86/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so index 12c5b69e..13033634 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_64/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so index 06dc0aa9..caf1648d 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/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt index 3253fe0e..534b8c1b 100644 --- a/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt +++ b/bindings/android/lib/src/main/kotlin/com/synonym/bitkitcore/bitkitcore.android.kt @@ -1594,6 +1594,10 @@ internal typealias UniffiVTableCallbackInterfaceTrezorUiCallbackUniffiByValue = + + + + @@ -1806,6 +1810,9 @@ internal object IntegrityCheckingUniffiLib : Library { if (uniffi_bitkitcore_checksum_func_get_activities_by_tag() != 16182.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (uniffi_bitkitcore_checksum_func_get_activities_tags() != 33500.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (uniffi_bitkitcore_checksum_func_get_activity_by_id() != 28490.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -1872,6 +1879,9 @@ internal object IntegrityCheckingUniffiLib : Library { if (uniffi_bitkitcore_checksum_func_get_pre_activity_metadata() != 24738.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } + if (uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list() != 37473.toShort()) { + throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + } if (uniffi_bitkitcore_checksum_func_get_supported_hardware_wallets() != 61117.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } @@ -2401,6 +2411,9 @@ internal object IntegrityCheckingUniffiLib : Library { external fun uniffi_bitkitcore_checksum_func_get_activities_by_tag( ): Short @JvmStatic + external fun uniffi_bitkitcore_checksum_func_get_activities_tags( + ): Short + @JvmStatic external fun uniffi_bitkitcore_checksum_func_get_activity_by_id( ): Short @JvmStatic @@ -2467,6 +2480,9 @@ internal object IntegrityCheckingUniffiLib : Library { external fun uniffi_bitkitcore_checksum_func_get_pre_activity_metadata( ): Short @JvmStatic + external fun uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list( + ): Short + @JvmStatic external fun uniffi_bitkitcore_checksum_func_get_supported_hardware_wallets( ): Short @JvmStatic @@ -3346,6 +3362,11 @@ internal object UniffiLib : Library { uniffiCallStatus: UniffiRustCallStatus, ): RustBufferByValue @JvmStatic + external fun uniffi_bitkitcore_fn_func_get_activities_tags( + `walletId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + @JvmStatic external fun uniffi_bitkitcore_fn_func_get_activity_by_id( `walletId`: RustBufferByValue, `activityId`: RustBufferByValue, @@ -3453,6 +3474,11 @@ internal object UniffiLib : Library { uniffiCallStatus: UniffiRustCallStatus, ): RustBufferByValue @JvmStatic + external fun uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list( + `walletId`: RustBufferByValue, + uniffiCallStatus: UniffiRustCallStatus, + ): RustBufferByValue + @JvmStatic external fun uniffi_bitkitcore_fn_func_get_supported_hardware_wallets( uniffiCallStatus: UniffiRustCallStatus, ): RustBufferByValue @@ -16108,6 +16134,19 @@ public fun `getActivitiesByTag`(`walletId`: kotlin.String?, `tag`: kotlin.String }) } +/** + * Activity tags for a single wallet scope, or every scope when `wallet_id` is `None`. + */ +@Throws(ActivityException::class) +public fun `getActivitiesTags`(`walletId`: kotlin.String?): List { + return FfiConverterSequenceTypeActivityTags.lift(uniffiRustCallWithError(ActivityExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.uniffi_bitkitcore_fn_func_get_activities_tags( + FfiConverterOptionalString.lower(`walletId`), + uniffiRustCallStatus, + ) + }) +} + @Throws(ActivityException::class) public fun `getActivityById`(`walletId`: kotlin.String, `activityId`: kotlin.String): Activity? { return FfiConverterOptionalTypeActivity.lift(uniffiRustCallWithError(ActivityExceptionErrorHandler) { uniffiRustCallStatus -> @@ -16388,6 +16427,19 @@ public fun `getPreActivityMetadata`(`walletId`: kotlin.String, `searchKey`: kotl }) } +/** + * Pre-activity metadata for a single wallet scope, or every scope when `wallet_id` is `None`. + */ +@Throws(ActivityException::class) +public fun `getPreActivityMetadataList`(`walletId`: kotlin.String?): List { + return FfiConverterSequenceTypePreActivityMetadata.lift(uniffiRustCallWithError(ActivityExceptionErrorHandler) { uniffiRustCallStatus -> + UniffiLib.uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list( + FfiConverterOptionalString.lower(`walletId`), + uniffiRustCallStatus, + ) + }) +} + /** * The hardware-wallet models supported by Bitkit and their available transports. */ diff --git a/bindings/ios/BitkitCore.xcframework.zip b/bindings/ios/BitkitCore.xcframework.zip index 366f4c19..2f5b4208 100644 Binary files a/bindings/ios/BitkitCore.xcframework.zip and b/bindings/ios/BitkitCore.xcframework.zip differ diff --git a/bindings/ios/BitkitCore.xcframework/Info.plist b/bindings/ios/BitkitCore.xcframework/Info.plist index b7357e03..478a88f3 100644 --- a/bindings/ios/BitkitCore.xcframework/Info.plist +++ b/bindings/ios/BitkitCore.xcframework/Info.plist @@ -10,7 +10,7 @@ HeadersPath Headers LibraryIdentifier - ios-arm64-simulator + ios-arm64 LibraryPath libbitkitcore.a SupportedArchitectures @@ -19,8 +19,6 @@ SupportedPlatform ios - SupportedPlatformVariant - simulator BinaryPath @@ -28,7 +26,7 @@ HeadersPath Headers LibraryIdentifier - ios-arm64 + ios-arm64-simulator LibraryPath libbitkitcore.a SupportedArchitectures @@ -37,6 +35,8 @@ SupportedPlatform ios + SupportedPlatformVariant + simulator CFBundlePackageType diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h index 0d16ac0b..79b2fb22 100644 --- a/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h +++ b/bindings/ios/BitkitCore.xcframework/ios-arm64-simulator/Headers/bitkitcoreFFI.h @@ -849,6 +849,11 @@ RustBuffer uniffi_bitkitcore_fn_func_get_activities(RustBuffer wallet_id, RustBu RustBuffer uniffi_bitkitcore_fn_func_get_activities_by_tag(RustBuffer wallet_id, RustBuffer tag, RustBuffer limit, RustBuffer sort_direction, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITIES_TAGS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITIES_TAGS +RustBuffer uniffi_bitkitcore_fn_func_get_activities_tags(RustBuffer wallet_id, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITY_BY_ID #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITY_BY_ID RustBuffer uniffi_bitkitcore_fn_func_get_activity_by_id(RustBuffer wallet_id, RustBuffer activity_id, RustCallStatus *_Nonnull out_status @@ -966,6 +971,11 @@ uint64_t uniffi_bitkitcore_fn_func_get_payment(RustBuffer payment_id RustBuffer uniffi_bitkitcore_fn_func_get_pre_activity_metadata(RustBuffer wallet_id, RustBuffer search_key, int8_t search_by_address, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +RustBuffer uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list(RustBuffer wallet_id, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_SUPPORTED_HARDWARE_WALLETS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_SUPPORTED_HARDWARE_WALLETS RustBuffer uniffi_bitkitcore_fn_func_get_supported_hardware_wallets(RustCallStatus *_Nonnull out_status @@ -2102,6 +2112,12 @@ uint16_t uniffi_bitkitcore_checksum_func_get_activities(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_BY_TAG uint16_t uniffi_bitkitcore_checksum_func_get_activities_by_tag(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_TAGS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_TAGS +uint16_t uniffi_bitkitcore_checksum_func_get_activities_tags(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITY_BY_ID @@ -2234,6 +2250,12 @@ uint16_t uniffi_bitkitcore_checksum_func_get_payment(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA uint16_t uniffi_bitkitcore_checksum_func_get_pre_activity_metadata(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +uint16_t uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_SUPPORTED_HARDWARE_WALLETS diff --git a/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h b/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h index 0d16ac0b..79b2fb22 100644 --- a/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h +++ b/bindings/ios/BitkitCore.xcframework/ios-arm64/Headers/bitkitcoreFFI.h @@ -849,6 +849,11 @@ RustBuffer uniffi_bitkitcore_fn_func_get_activities(RustBuffer wallet_id, RustBu RustBuffer uniffi_bitkitcore_fn_func_get_activities_by_tag(RustBuffer wallet_id, RustBuffer tag, RustBuffer limit, RustBuffer sort_direction, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITIES_TAGS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITIES_TAGS +RustBuffer uniffi_bitkitcore_fn_func_get_activities_tags(RustBuffer wallet_id, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITY_BY_ID #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITY_BY_ID RustBuffer uniffi_bitkitcore_fn_func_get_activity_by_id(RustBuffer wallet_id, RustBuffer activity_id, RustCallStatus *_Nonnull out_status @@ -966,6 +971,11 @@ uint64_t uniffi_bitkitcore_fn_func_get_payment(RustBuffer payment_id RustBuffer uniffi_bitkitcore_fn_func_get_pre_activity_metadata(RustBuffer wallet_id, RustBuffer search_key, int8_t search_by_address, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +RustBuffer uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list(RustBuffer wallet_id, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_SUPPORTED_HARDWARE_WALLETS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_SUPPORTED_HARDWARE_WALLETS RustBuffer uniffi_bitkitcore_fn_func_get_supported_hardware_wallets(RustCallStatus *_Nonnull out_status @@ -2102,6 +2112,12 @@ uint16_t uniffi_bitkitcore_checksum_func_get_activities(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_BY_TAG uint16_t uniffi_bitkitcore_checksum_func_get_activities_by_tag(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_TAGS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_TAGS +uint16_t uniffi_bitkitcore_checksum_func_get_activities_tags(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITY_BY_ID @@ -2234,6 +2250,12 @@ uint16_t uniffi_bitkitcore_checksum_func_get_payment(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA uint16_t uniffi_bitkitcore_checksum_func_get_pre_activity_metadata(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +uint16_t uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_SUPPORTED_HARDWARE_WALLETS diff --git a/bindings/ios/bitkitcore.swift b/bindings/ios/bitkitcore.swift index dfae58f5..8db98fc1 100644 --- a/bindings/ios/bitkitcore.swift +++ b/bindings/ios/bitkitcore.swift @@ -23818,6 +23818,16 @@ public func getActivitiesByTag(walletId: String?, tag: String, limit: UInt32?, s ) }) } +/** + * Activity tags for a single wallet scope, or every scope when `wallet_id` is `None`. + */ +public func getActivitiesTags(walletId: String?)throws -> [ActivityTags] { + return try FfiConverterSequenceTypeActivityTags.lift(try rustCallWithError(FfiConverterTypeActivityError_lift) { + uniffi_bitkitcore_fn_func_get_activities_tags( + FfiConverterOptionString.lower(walletId),$0 + ) +}) +} public func getActivityById(walletId: String, activityId: String)throws -> Activity? { return try FfiConverterOptionTypeActivity.lift(try rustCallWithError(FfiConverterTypeActivityError_lift) { uniffi_bitkitcore_fn_func_get_activity_by_id( @@ -24030,6 +24040,16 @@ public func getPreActivityMetadata(walletId: String, searchKey: String, searchBy ) }) } +/** + * Pre-activity metadata for a single wallet scope, or every scope when `wallet_id` is `None`. + */ +public func getPreActivityMetadataList(walletId: String?)throws -> [PreActivityMetadata] { + return try FfiConverterSequenceTypePreActivityMetadata.lift(try rustCallWithError(FfiConverterTypeActivityError_lift) { + uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list( + FfiConverterOptionString.lower(walletId),$0 + ) +}) +} /** * The hardware-wallet models supported by Bitkit and their available transports. */ @@ -25482,6 +25502,9 @@ private let initializationResult: InitializationResult = { if (uniffi_bitkitcore_checksum_func_get_activities_by_tag() != 16182) { return InitializationResult.apiChecksumMismatch } + if (uniffi_bitkitcore_checksum_func_get_activities_tags() != 33500) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_bitkitcore_checksum_func_get_activity_by_id() != 28490) { return InitializationResult.apiChecksumMismatch } @@ -25548,6 +25571,9 @@ private let initializationResult: InitializationResult = { if (uniffi_bitkitcore_checksum_func_get_pre_activity_metadata() != 24738) { return InitializationResult.apiChecksumMismatch } + if (uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list() != 37473) { + return InitializationResult.apiChecksumMismatch + } if (uniffi_bitkitcore_checksum_func_get_supported_hardware_wallets() != 61117) { return InitializationResult.apiChecksumMismatch } diff --git a/bindings/ios/bitkitcoreFFI.h b/bindings/ios/bitkitcoreFFI.h index 0d16ac0b..79b2fb22 100644 --- a/bindings/ios/bitkitcoreFFI.h +++ b/bindings/ios/bitkitcoreFFI.h @@ -849,6 +849,11 @@ RustBuffer uniffi_bitkitcore_fn_func_get_activities(RustBuffer wallet_id, RustBu RustBuffer uniffi_bitkitcore_fn_func_get_activities_by_tag(RustBuffer wallet_id, RustBuffer tag, RustBuffer limit, RustBuffer sort_direction, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITIES_TAGS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITIES_TAGS +RustBuffer uniffi_bitkitcore_fn_func_get_activities_tags(RustBuffer wallet_id, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITY_BY_ID #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_ACTIVITY_BY_ID RustBuffer uniffi_bitkitcore_fn_func_get_activity_by_id(RustBuffer wallet_id, RustBuffer activity_id, RustCallStatus *_Nonnull out_status @@ -966,6 +971,11 @@ uint64_t uniffi_bitkitcore_fn_func_get_payment(RustBuffer payment_id RustBuffer uniffi_bitkitcore_fn_func_get_pre_activity_metadata(RustBuffer wallet_id, RustBuffer search_key, int8_t search_by_address, RustCallStatus *_Nonnull out_status ); #endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +RustBuffer uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list(RustBuffer wallet_id, RustCallStatus *_Nonnull out_status +); +#endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_SUPPORTED_HARDWARE_WALLETS #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_FN_FUNC_GET_SUPPORTED_HARDWARE_WALLETS RustBuffer uniffi_bitkitcore_fn_func_get_supported_hardware_wallets(RustCallStatus *_Nonnull out_status @@ -2102,6 +2112,12 @@ uint16_t uniffi_bitkitcore_checksum_func_get_activities(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_BY_TAG uint16_t uniffi_bitkitcore_checksum_func_get_activities_by_tag(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_TAGS +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITIES_TAGS +uint16_t uniffi_bitkitcore_checksum_func_get_activities_tags(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_ACTIVITY_BY_ID @@ -2234,6 +2250,12 @@ uint16_t uniffi_bitkitcore_checksum_func_get_payment(void #define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA uint16_t uniffi_bitkitcore_checksum_func_get_pre_activity_metadata(void +); +#endif +#ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +#define UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_PRE_ACTIVITY_METADATA_LIST +uint16_t uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list(void + ); #endif #ifndef UNIFFI_FFIDEF_UNIFFI_BITKITCORE_CHECKSUM_FUNC_GET_SUPPORTED_HARDWARE_WALLETS diff --git a/bindings/python/bitkitcore/bitkitcore.py b/bindings/python/bitkitcore/bitkitcore.py index 4a33ef2f..5f7e508e 100644 --- a/bindings/python/bitkitcore/bitkitcore.py +++ b/bindings/python/bitkitcore/bitkitcore.py @@ -573,6 +573,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_get_activities_by_tag() != 16182: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_get_activities_tags() != 33500: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_get_activity_by_id() != 28490: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_get_activity_by_tx_id() != 28432: @@ -617,6 +619,8 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_get_pre_activity_metadata() != 24738: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") + if lib.uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list() != 37473: + raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_get_supported_hardware_wallets() != 61117: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_bitkitcore_checksum_func_get_tags() != 8596: @@ -1536,6 +1540,11 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_bitkitcore_fn_func_get_activities_by_tag.restype = _UniffiRustBuffer +_UniffiLib.uniffi_bitkitcore_fn_func_get_activities_tags.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_bitkitcore_fn_func_get_activities_tags.restype = _UniffiRustBuffer _UniffiLib.uniffi_bitkitcore_fn_func_get_activity_by_id.argtypes = ( _UniffiRustBuffer, _UniffiRustBuffer, @@ -1643,6 +1652,11 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): ctypes.POINTER(_UniffiRustCallStatus), ) _UniffiLib.uniffi_bitkitcore_fn_func_get_pre_activity_metadata.restype = _UniffiRustBuffer +_UniffiLib.uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list.argtypes = ( + _UniffiRustBuffer, + ctypes.POINTER(_UniffiRustCallStatus), +) +_UniffiLib.uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list.restype = _UniffiRustBuffer _UniffiLib.uniffi_bitkitcore_fn_func_get_supported_hardware_wallets.argtypes = ( ctypes.POINTER(_UniffiRustCallStatus), ) @@ -2587,6 +2601,9 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_checksum_func_get_activities_by_tag.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_get_activities_by_tag.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_get_activities_tags.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_get_activities_tags.restype = ctypes.c_uint16 _UniffiLib.uniffi_bitkitcore_checksum_func_get_activity_by_id.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_get_activity_by_id.restype = ctypes.c_uint16 @@ -2653,6 +2670,9 @@ class _UniffiVTableCallbackInterfaceTrezorUiCallback(ctypes.Structure): _UniffiLib.uniffi_bitkitcore_checksum_func_get_pre_activity_metadata.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_get_pre_activity_metadata.restype = ctypes.c_uint16 +_UniffiLib.uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list.argtypes = ( +) +_UniffiLib.uniffi_bitkitcore_checksum_func_get_pre_activity_metadata_list.restype = ctypes.c_uint16 _UniffiLib.uniffi_bitkitcore_checksum_func_get_supported_hardware_wallets.argtypes = ( ) _UniffiLib.uniffi_bitkitcore_checksum_func_get_supported_hardware_wallets.restype = ctypes.c_uint16 @@ -22760,6 +22780,17 @@ def get_activities_by_tag(wallet_id: "typing.Optional[str]",tag: "str",limit: "t _UniffiConverterOptionalTypeSortDirection.lower(sort_direction))) +def get_activities_tags(wallet_id: "typing.Optional[str]") -> "typing.List[ActivityTags]": + """ + Activity tags for a single wallet scope, or every scope when `wallet_id` is `None`. + """ + + _UniffiConverterOptionalString.check_lower(wallet_id) + + return _UniffiConverterSequenceTypeActivityTags.lift(_uniffi_rust_call_with_error(_UniffiConverterTypeActivityError,_UniffiLib.uniffi_bitkitcore_fn_func_get_activities_tags, + _UniffiConverterOptionalString.lower(wallet_id))) + + def get_activity_by_id(wallet_id: "str",activity_id: "str") -> "typing.Optional[Activity]": _UniffiConverterString.check_lower(wallet_id) @@ -23014,6 +23045,17 @@ def get_pre_activity_metadata(wallet_id: "str",search_key: "str",search_by_addre _UniffiConverterBool.lower(search_by_address))) +def get_pre_activity_metadata_list(wallet_id: "typing.Optional[str]") -> "typing.List[PreActivityMetadata]": + """ + Pre-activity metadata for a single wallet scope, or every scope when `wallet_id` is `None`. + """ + + _UniffiConverterOptionalString.check_lower(wallet_id) + + return _UniffiConverterSequenceTypePreActivityMetadata.lift(_uniffi_rust_call_with_error(_UniffiConverterTypeActivityError,_UniffiLib.uniffi_bitkitcore_fn_func_get_pre_activity_metadata_list, + _UniffiConverterOptionalString.lower(wallet_id))) + + def get_supported_hardware_wallets() -> "typing.List[SupportedHardwareWallet]": """ The hardware-wallet models supported by Bitkit and their available transports. @@ -24898,6 +24940,7 @@ def wipe_all_transaction_details() -> None: "generate_mnemonic", "get_activities", "get_activities_by_tag", + "get_activities_tags", "get_activity_by_id", "get_activity_by_tx_id", "get_all_activities_tags", @@ -24920,6 +24963,7 @@ def wipe_all_transaction_details() -> None: "get_orders", "get_payment", "get_pre_activity_metadata", + "get_pre_activity_metadata_list", "get_supported_hardware_wallets", "get_tags", "get_transaction_details", diff --git a/bindings/python/bitkitcore/libbitkitcore.dylib b/bindings/python/bitkitcore/libbitkitcore.dylib index e8dc02f3..a9d75afe 100755 Binary files a/bindings/python/bitkitcore/libbitkitcore.dylib and b/bindings/python/bitkitcore/libbitkitcore.dylib differ diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 2f31bfb6..7c173869 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -2,7 +2,7 @@ setup( name="bitkitcore", - version="0.5.11", + version="0.5.12", packages=find_packages(), package_data={ "bitkitcore": ["*.so", "*.dylib", "*.dll"], diff --git a/src/lib.rs b/src/lib.rs index 0fddfce5..0b4cfab4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -752,6 +752,19 @@ pub fn get_all_activities_tags() -> Result, ActivityError> { db.get_all_activities_tags() } +/// Activity tags for a single wallet scope, or every scope when `wallet_id` is `None`. +#[uniffi::export] +pub fn get_activities_tags(wallet_id: Option) -> Result, ActivityError> { + let guard = get_activity_db()?; + let db = guard + .activity_db + .as_ref() + .ok_or(ActivityError::ConnectionError { + error_details: "Database not initialized. Call init_db first.".to_string(), + })?; + db.get_activities_tags(wallet_id.as_deref()) +} + #[uniffi::export] pub fn upsert_tags(activity_tags: Vec) -> Result<(), ActivityError> { let mut guard = get_activity_db()?; @@ -882,6 +895,21 @@ pub fn get_all_pre_activity_metadata() -> Result, Activ db.get_all_pre_activity_metadata() } +/// Pre-activity metadata for a single wallet scope, or every scope when `wallet_id` is `None`. +#[uniffi::export] +pub fn get_pre_activity_metadata_list( + wallet_id: Option, +) -> Result, ActivityError> { + let guard = get_activity_db()?; + let db = guard + .activity_db + .as_ref() + .ok_or(ActivityError::ConnectionError { + error_details: "Database not initialized. Call init_db first.".to_string(), + })?; + db.get_pre_activity_metadata_list(wallet_id.as_deref()) +} + #[uniffi::export] pub fn upsert_closed_channel(channel: ClosedChannelDetails) -> Result<(), ActivityError> { let mut guard = get_activity_db()?; @@ -3011,3 +3039,141 @@ pub async fn boltz_stop_swap_updates() { .spawn(async move { boltz::stop_swap_updates().await }) .await; } + +#[cfg(test)] +mod tests { + use super::*; + + /// Drives the exported entry points through the global database, so a + /// wrapper that dropped `wallet_id` or fell back to an unscoped getter + /// would fail here even while the `ActivityDB` tests pass. + #[test] + fn test_exported_scoped_getters_preserve_wallet_id() { + let base_path = + std::env::temp_dir().join(format!("bitkitcore_lib_test_{}", rand::random::())); + std::fs::create_dir_all(&base_path).unwrap(); + init_db(base_path.to_string_lossy().into_owned()).unwrap(); + + let hardware_wallet_id = format!("trezor:{}", "c".repeat(64)); + + let mut activity = OnchainActivity { + wallet_id: DEFAULT_WALLET_ID.to_string(), + id: "main_activity".to_string(), + tx_type: PaymentType::Sent, + tx_id: "main_txid".to_string(), + value: 50000, + fee: 500, + fee_rate: 1, + address: "bc1q...".to_string(), + confirmed: true, + timestamp: 1234567890, + is_boosted: false, + boost_tx_ids: vec![], + is_transfer: false, + does_exist: true, + confirm_timestamp: Some(1234568890), + channel_id: None, + transfer_tx_id: None, + contact: None, + created_at: None, + updated_at: None, + seen_at: None, + }; + insert_activity(Activity::Onchain(activity.clone())).unwrap(); + activity.wallet_id = hardware_wallet_id.clone(); + activity.id = "hardware_activity".to_string(); + activity.tx_id = "hardware_txid".to_string(); + insert_activity(Activity::Onchain(activity)).unwrap(); + + upsert_tags(vec![ + ActivityTags { + wallet_id: DEFAULT_WALLET_ID.to_string(), + activity_id: "main_activity".to_string(), + tags: vec!["main".to_string()], + }, + ActivityTags { + wallet_id: hardware_wallet_id.clone(), + activity_id: "hardware_activity".to_string(), + tags: vec!["hardware".to_string()], + }, + ]) + .unwrap(); + + let default_tags = get_activities_tags(Some(DEFAULT_WALLET_ID.to_string())).unwrap(); + assert_eq!(default_tags.len(), 1); + assert_eq!(default_tags[0].wallet_id, DEFAULT_WALLET_ID); + assert_eq!(default_tags[0].tags, vec!["main".to_string()]); + + let hardware_tags = get_activities_tags(Some(hardware_wallet_id.clone())).unwrap(); + assert_eq!(hardware_tags.len(), 1); + assert_eq!(hardware_tags[0].wallet_id, hardware_wallet_id); + assert_eq!(hardware_tags[0].tags, vec!["hardware".to_string()]); + + let tag_scopes = |tags: &[ActivityTags]| { + tags.iter() + .map(|entry| (entry.wallet_id.clone(), entry.activity_id.clone())) + .collect::>() + }; + let all_tags = get_activities_tags(None).unwrap(); + assert_eq!(all_tags.len(), 2); + assert_eq!( + tag_scopes(&all_tags), + tag_scopes(&get_all_activities_tags().unwrap()) + ); + + let mut hardware_metadata = PreActivityMetadata { + wallet_id: DEFAULT_WALLET_ID.to_string(), + payment_id: "bc1qmain".to_string(), + tags: vec!["main".to_string()], + payment_hash: None, + tx_id: None, + address: None, + is_receive: false, + fee_rate: 0, + is_transfer: false, + channel_id: None, + created_at: 0, + }; + add_pre_activity_metadata(hardware_metadata.clone()).unwrap(); + hardware_metadata.wallet_id = hardware_wallet_id.clone(); + hardware_metadata.payment_id = "bc1qhardware".to_string(); + hardware_metadata.tags = vec!["hardware".to_string()]; + add_pre_activity_metadata(hardware_metadata).unwrap(); + + let default_metadata = + get_pre_activity_metadata_list(Some(DEFAULT_WALLET_ID.to_string())).unwrap(); + assert_eq!(default_metadata.len(), 1); + assert_eq!(default_metadata[0].wallet_id, DEFAULT_WALLET_ID); + assert_eq!(default_metadata[0].payment_id, "bc1qmain"); + + let hardware_metadata = + get_pre_activity_metadata_list(Some(hardware_wallet_id.clone())).unwrap(); + assert_eq!(hardware_metadata.len(), 1); + assert_eq!(hardware_metadata[0].wallet_id, hardware_wallet_id); + assert_eq!(hardware_metadata[0].payment_id, "bc1qhardware"); + + let metadata_scopes = |metadata: &[PreActivityMetadata]| { + metadata + .iter() + .map(|entry| (entry.wallet_id.clone(), entry.payment_id.clone())) + .collect::>() + }; + let all_metadata = get_pre_activity_metadata_list(None).unwrap(); + assert_eq!(all_metadata.len(), 2); + assert_eq!( + metadata_scopes(&all_metadata), + metadata_scopes(&get_all_pre_activity_metadata().unwrap()) + ); + + assert!(get_activities_tags(Some("ledger:unknown".to_string())) + .unwrap() + .is_empty()); + assert!( + get_pre_activity_metadata_list(Some("ledger:unknown".to_string())) + .unwrap() + .is_empty() + ); + + std::fs::remove_dir_all(&base_path).ok(); + } +} diff --git a/src/modules/activity/README.md b/src/modules/activity/README.md index 7c3ad6df..deb93611 100644 --- a/src/modules/activity/README.md +++ b/src/modules/activity/README.md @@ -71,6 +71,9 @@ fn add_tags(wallet_id: String, activity_id: String, tags: Vec) -> Result fn remove_tags(wallet_id: String, activity_id: String, tags: Vec) -> Result<(), ActivityError> fn get_tags(wallet_id: String, activity_id: String) -> Result, ActivityError> fn get_all_unique_tags() -> Result, ActivityError> +fn get_all_activities_tags() -> Result, ActivityError> +// Wallet-scoped tag read; `None` returns every wallet scope +fn get_activities_tags(wallet_id: Option) -> Result, ActivityError> // Pre-activity metadata fn add_pre_activity_metadata(pre_activity_metadata: PreActivityMetadata) -> Result<(), ActivityError> @@ -85,6 +88,8 @@ fn get_pre_activity_metadata( search_by_address: bool ) -> Result, ActivityError> fn get_all_pre_activity_metadata() -> Result, ActivityError> +// Wallet-scoped metadata read; `None` returns every wallet scope +fn get_pre_activity_metadata_list(wallet_id: Option) -> Result, ActivityError> // Transaction details fn upsert_transaction_details(details_list: Vec) -> Result<(), ActivityError> diff --git a/src/modules/activity/implementation.rs b/src/modules/activity/implementation.rs index f85cdb62..a7b95698 100644 --- a/src/modules/activity/implementation.rs +++ b/src/modules/activity/implementation.rs @@ -2149,21 +2149,42 @@ impl ActivityDB { Ok(tags) } - /// Get all activity tags for backup + /// Get all activity tags for backup, across every wallet scope pub fn get_all_activities_tags(&self) -> Result, ActivityError> { + self.get_activities_tags(None) + } + + /// Get activity tags for backup, scoped to `wallet_id` when it is `Some` + /// and covering every wallet scope when it is `None`. + pub fn get_activities_tags( + &self, + wallet_id: Option<&str>, + ) -> Result, ActivityError> { + let wallet_id = wallet_id.map(Self::normalize_wallet_id).transpose()?; + let wallet_filter = if wallet_id.is_some() { + " WHERE wallet_id = ?1" + } else { + "" + }; + let sql = format!( + "SELECT wallet_id, activity_id, tag + FROM activity_tags{} + ORDER BY wallet_id, activity_id, tag", + wallet_filter + ); + let mut stmt = self .conn - .prepare( - "SELECT wallet_id, activity_id, tag - FROM activity_tags - ORDER BY wallet_id, activity_id, tag", - ) + .prepare(&sql) .map_err(|e| ActivityError::RetrievalError { error_details: format!("Failed to prepare statement: {}", e), })?; + let params: Vec<&String> = wallet_id.iter().collect(); let rows: Vec<(String, String, String)> = stmt - .query_map([], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?))) + .query_map(rusqlite::params_from_iter(params), |row| { + Ok((row.get(0)?, row.get(1)?, row.get(2)?)) + }) .map_err(|e| ActivityError::RetrievalError { error_details: format!("Failed to execute query: {}", e), })? @@ -2653,15 +2674,37 @@ impl ActivityDB { } } - /// Get all pre-activity metadata for backup - #[allow(clippy::type_complexity)] + /// Get all pre-activity metadata for backup, across every wallet scope pub fn get_all_pre_activity_metadata(&self) -> Result, ActivityError> { - let mut stmt = self.conn.prepare( - "SELECT wallet_id, payment_id, tags, payment_hash, tx_id, address, is_receive, fee_rate, is_transfer, channel_id, created_at FROM pre_activity_metadata ORDER BY wallet_id, payment_id" - ).map_err(|e| ActivityError::RetrievalError { - error_details: format!("Failed to prepare statement: {}", e), - })?; + self.get_pre_activity_metadata_list(None) + } + /// Get pre-activity metadata for backup, scoped to `wallet_id` when it is + /// `Some` and covering every wallet scope when it is `None`. + #[allow(clippy::type_complexity)] + pub fn get_pre_activity_metadata_list( + &self, + wallet_id: Option<&str>, + ) -> Result, ActivityError> { + let wallet_id = wallet_id.map(Self::normalize_wallet_id).transpose()?; + let wallet_filter = if wallet_id.is_some() { + " WHERE wallet_id = ?1" + } else { + "" + }; + let sql = format!( + "SELECT wallet_id, payment_id, tags, payment_hash, tx_id, address, is_receive, fee_rate, is_transfer, channel_id, created_at FROM pre_activity_metadata{} ORDER BY wallet_id, payment_id", + wallet_filter + ); + + let mut stmt = self + .conn + .prepare(&sql) + .map_err(|e| ActivityError::RetrievalError { + error_details: format!("Failed to prepare statement: {}", e), + })?; + + let params: Vec<&String> = wallet_id.iter().collect(); let rows: Vec<( String, String, @@ -2675,7 +2718,7 @@ impl ActivityDB { Option, i64, )> = stmt - .query_map([], |row| { + .query_map(rusqlite::params_from_iter(params), |row| { Ok(( row.get(0)?, row.get(1)?, diff --git a/src/modules/activity/tests.rs b/src/modules/activity/tests.rs index f9a1ff5f..d9474241 100644 --- a/src/modules/activity/tests.rs +++ b/src/modules/activity/tests.rs @@ -3357,6 +3357,71 @@ mod tests { cleanup(&db_path); } + #[test] + fn test_get_activities_tags_wallet_scoped() { + let (mut db, db_path) = setup(); + let hardware_wallet_id = format!("trezor:{}", "a".repeat(64)); + + let mut main = create_test_onchain_activity(); + main.id = "main_activity".to_string(); + main.tx_id = "main_scoped_tags_txid".to_string(); + + let mut hardware = create_test_onchain_activity(); + hardware.wallet_id = hardware_wallet_id.clone(); + hardware.id = "hardware_activity".to_string(); + hardware.tx_id = "hardware_scoped_tags_txid".to_string(); + + db.insert_onchain_activity(&main).unwrap(); + db.insert_onchain_activity(&hardware).unwrap(); + + db.add_tags(DEFAULT_WALLET_ID, &main.id, &["main".to_string()]) + .unwrap(); + db.add_tags(&hardware_wallet_id, &hardware.id, &["hardware".to_string()]) + .unwrap(); + + let default_scope = db.get_activities_tags(Some(DEFAULT_WALLET_ID)).unwrap(); + assert_eq!(default_scope.len(), 1); + assert_eq!(default_scope[0].wallet_id, DEFAULT_WALLET_ID); + assert_eq!(default_scope[0].activity_id, main.id); + assert_eq!(default_scope[0].tags, vec!["main".to_string()]); + + let hardware_scope = db.get_activities_tags(Some(&hardware_wallet_id)).unwrap(); + assert_eq!(hardware_scope.len(), 1); + assert_eq!(hardware_scope[0].wallet_id, hardware_wallet_id); + assert_eq!(hardware_scope[0].activity_id, hardware.id); + assert_eq!(hardware_scope[0].tags, vec!["hardware".to_string()]); + + // None means every scope, matching the legacy unscoped getter. + let scope_ids = |tags: &[ActivityTags]| { + tags.iter() + .map(|entry| (entry.wallet_id.clone(), entry.activity_id.clone())) + .collect::>() + }; + let all_scopes = db.get_activities_tags(None).unwrap(); + assert_eq!(all_scopes.len(), 2); + assert_eq!( + scope_ids(&all_scopes), + scope_ids(&db.get_all_activities_tags().unwrap()) + ); + + // An unknown scope leaks nothing. + assert!(db + .get_activities_tags(Some("ledger:unknown")) + .unwrap() + .is_empty()); + + cleanup(&db_path); + } + + #[test] + fn test_get_activities_tags_rejects_blank_wallet_id() { + let (db, db_path) = setup(); + + assert!(db.get_activities_tags(Some(" ")).is_err()); + + cleanup(&db_path); + } + #[test] fn test_get_all_activities_tags_empty() { let (db, db_path) = setup(); @@ -5400,6 +5465,74 @@ mod tests { cleanup(&db_path); } + #[test] + fn test_get_pre_activity_metadata_list_wallet_scoped() { + let (mut db, db_path) = setup(); + let hardware_wallet_id = format!("trezor:{}", "b".repeat(64)); + + db.add_pre_activity_metadata(&create_test_pre_activity_metadata( + "bc1qmain".to_string(), + ActivityType::Onchain, + vec!["main".to_string()], + )) + .unwrap(); + + let mut hardware = create_test_pre_activity_metadata( + "bc1qhardware".to_string(), + ActivityType::Onchain, + vec!["hardware".to_string()], + ); + hardware.wallet_id = hardware_wallet_id.clone(); + db.add_pre_activity_metadata(&hardware).unwrap(); + + let default_scope = db + .get_pre_activity_metadata_list(Some(DEFAULT_WALLET_ID)) + .unwrap(); + assert_eq!(default_scope.len(), 1); + assert_eq!(default_scope[0].wallet_id, DEFAULT_WALLET_ID); + assert_eq!(default_scope[0].payment_id, "bc1qmain"); + assert_eq!(default_scope[0].tags, vec!["main".to_string()]); + + let hardware_scope = db + .get_pre_activity_metadata_list(Some(&hardware_wallet_id)) + .unwrap(); + assert_eq!(hardware_scope.len(), 1); + assert_eq!(hardware_scope[0].wallet_id, hardware_wallet_id); + assert_eq!(hardware_scope[0].payment_id, "bc1qhardware"); + assert_eq!(hardware_scope[0].tags, vec!["hardware".to_string()]); + + // None means every scope, matching the legacy unscoped getter. + let scope_ids = |metadata: &[PreActivityMetadata]| { + metadata + .iter() + .map(|entry| (entry.wallet_id.clone(), entry.payment_id.clone())) + .collect::>() + }; + let all_scopes = db.get_pre_activity_metadata_list(None).unwrap(); + assert_eq!(all_scopes.len(), 2); + assert_eq!( + scope_ids(&all_scopes), + scope_ids(&db.get_all_pre_activity_metadata().unwrap()) + ); + + // An unknown scope leaks nothing. + assert!(db + .get_pre_activity_metadata_list(Some("ledger:unknown")) + .unwrap() + .is_empty()); + + cleanup(&db_path); + } + + #[test] + fn test_get_pre_activity_metadata_list_rejects_blank_wallet_id() { + let (db, db_path) = setup(); + + assert!(db.get_pre_activity_metadata_list(Some(" ")).is_err()); + + cleanup(&db_path); + } + #[test] fn test_get_all_pre_activity_metadata_empty() { let (db, db_path) = setup();