Browse Source

feat: use macro to reduce duplicate ffi db code (#1521)

tsk 2 tuần trước cách đây
mục cha
commit
bf0f58f404
3 tập tin đã thay đổi với 256 bổ sung437 xóa
  1. 252 0
      crates/cdk-ffi/src/database.rs
  2. 2 219
      crates/cdk-ffi/src/postgres.rs
  3. 2 218
      crates/cdk-ffi/src/sqlite.rs

+ 252 - 0
crates/cdk-ffi/src/database.rs

@@ -1198,6 +1198,258 @@ where
     }
 }
 
+/// Macro to implement WalletDatabase for wrapper types that delegate to an inner FfiWalletSQLDatabase.
+/// This eliminates duplication between SQLite and Postgres FFI implementations.
+///
+/// Requirements: The following types must be in scope where this macro is invoked:
+/// - WalletDatabase, FfiError, PublicKey, ProofInfo, MintUrl, MintInfo, KeySetInfo, Id,
+///   MintQuote, MeltQuote, Keys, CurrencyUnit, ProofState, SpendingConditions, Transaction,
+///   TransactionId, TransactionDirection, KeySet
+/// - std::collections::HashMap
+#[macro_export]
+macro_rules! impl_ffi_wallet_database {
+    ($wrapper_type:ty) => {
+        #[uniffi::export(async_runtime = "tokio")]
+        #[async_trait::async_trait]
+        impl WalletDatabase for $wrapper_type {
+            // ========== Read methods ==========
+
+            async fn get_proofs_by_ys(
+                &self,
+                ys: Vec<PublicKey>,
+            ) -> Result<Vec<ProofInfo>, FfiError> {
+                self.inner.get_proofs_by_ys(ys).await
+            }
+
+            async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
+                self.inner.get_mint(mint_url).await
+            }
+
+            async fn get_mints(
+                &self,
+            ) -> Result<std::collections::HashMap<MintUrl, Option<MintInfo>>, FfiError> {
+                self.inner.get_mints().await
+            }
+
+            async fn get_mint_keysets(
+                &self,
+                mint_url: MintUrl,
+            ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
+                self.inner.get_mint_keysets(mint_url).await
+            }
+
+            async fn get_keyset_by_id(
+                &self,
+                keyset_id: Id,
+            ) -> Result<Option<KeySetInfo>, FfiError> {
+                self.inner.get_keyset_by_id(keyset_id).await
+            }
+
+            async fn get_mint_quote(
+                &self,
+                quote_id: String,
+            ) -> Result<Option<MintQuote>, FfiError> {
+                self.inner.get_mint_quote(quote_id).await
+            }
+
+            async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
+                self.inner.get_mint_quotes().await
+            }
+
+            async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
+                self.inner.get_unissued_mint_quotes().await
+            }
+
+            async fn get_melt_quote(
+                &self,
+                quote_id: String,
+            ) -> Result<Option<MeltQuote>, FfiError> {
+                self.inner.get_melt_quote(quote_id).await
+            }
+
+            async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
+                self.inner.get_melt_quotes().await
+            }
+
+            async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
+                self.inner.get_keys(id).await
+            }
+
+            async fn get_proofs(
+                &self,
+                mint_url: Option<MintUrl>,
+                unit: Option<CurrencyUnit>,
+                state: Option<Vec<ProofState>>,
+                spending_conditions: Option<Vec<SpendingConditions>>,
+            ) -> Result<Vec<ProofInfo>, FfiError> {
+                self.inner
+                    .get_proofs(mint_url, unit, state, spending_conditions)
+                    .await
+            }
+
+            async fn get_balance(
+                &self,
+                mint_url: Option<MintUrl>,
+                unit: Option<CurrencyUnit>,
+                state: Option<Vec<ProofState>>,
+            ) -> Result<u64, FfiError> {
+                self.inner.get_balance(mint_url, unit, state).await
+            }
+
+            async fn get_transaction(
+                &self,
+                transaction_id: TransactionId,
+            ) -> Result<Option<Transaction>, FfiError> {
+                self.inner.get_transaction(transaction_id).await
+            }
+
+            async fn list_transactions(
+                &self,
+                mint_url: Option<MintUrl>,
+                direction: Option<TransactionDirection>,
+                unit: Option<CurrencyUnit>,
+            ) -> Result<Vec<Transaction>, FfiError> {
+                self.inner
+                    .list_transactions(mint_url, direction, unit)
+                    .await
+            }
+
+            async fn kv_read(
+                &self,
+                primary_namespace: String,
+                secondary_namespace: String,
+                key: String,
+            ) -> Result<Option<Vec<u8>>, FfiError> {
+                self.inner
+                    .kv_read(primary_namespace, secondary_namespace, key)
+                    .await
+            }
+
+            async fn kv_list(
+                &self,
+                primary_namespace: String,
+                secondary_namespace: String,
+            ) -> Result<Vec<String>, FfiError> {
+                self.inner
+                    .kv_list(primary_namespace, secondary_namespace)
+                    .await
+            }
+
+            async fn kv_write(
+                &self,
+                primary_namespace: String,
+                secondary_namespace: String,
+                key: String,
+                value: Vec<u8>,
+            ) -> Result<(), FfiError> {
+                self.inner
+                    .kv_write(primary_namespace, secondary_namespace, key, value)
+                    .await
+            }
+
+            async fn kv_remove(
+                &self,
+                primary_namespace: String,
+                secondary_namespace: String,
+                key: String,
+            ) -> Result<(), FfiError> {
+                self.inner
+                    .kv_remove(primary_namespace, secondary_namespace, key)
+                    .await
+            }
+
+            // ========== Write methods ==========
+
+            async fn update_proofs(
+                &self,
+                added: Vec<ProofInfo>,
+                removed_ys: Vec<PublicKey>,
+            ) -> Result<(), FfiError> {
+                self.inner.update_proofs(added, removed_ys).await
+            }
+
+            async fn update_proofs_state(
+                &self,
+                ys: Vec<PublicKey>,
+                state: ProofState,
+            ) -> Result<(), FfiError> {
+                self.inner.update_proofs_state(ys, state).await
+            }
+
+            async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
+                self.inner.add_transaction(transaction).await
+            }
+
+            async fn remove_transaction(
+                &self,
+                transaction_id: TransactionId,
+            ) -> Result<(), FfiError> {
+                self.inner.remove_transaction(transaction_id).await
+            }
+
+            async fn update_mint_url(
+                &self,
+                old_mint_url: MintUrl,
+                new_mint_url: MintUrl,
+            ) -> Result<(), FfiError> {
+                self.inner.update_mint_url(old_mint_url, new_mint_url).await
+            }
+
+            async fn increment_keyset_counter(
+                &self,
+                keyset_id: Id,
+                count: u32,
+            ) -> Result<u32, FfiError> {
+                self.inner.increment_keyset_counter(keyset_id, count).await
+            }
+
+            async fn add_mint(
+                &self,
+                mint_url: MintUrl,
+                mint_info: Option<MintInfo>,
+            ) -> Result<(), FfiError> {
+                self.inner.add_mint(mint_url, mint_info).await
+            }
+
+            async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
+                self.inner.remove_mint(mint_url).await
+            }
+
+            async fn add_mint_keysets(
+                &self,
+                mint_url: MintUrl,
+                keysets: Vec<KeySetInfo>,
+            ) -> Result<(), FfiError> {
+                self.inner.add_mint_keysets(mint_url, keysets).await
+            }
+
+            async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
+                self.inner.add_mint_quote(quote).await
+            }
+
+            async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
+                self.inner.remove_mint_quote(quote_id).await
+            }
+
+            async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
+                self.inner.add_melt_quote(quote).await
+            }
+
+            async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
+                self.inner.remove_melt_quote(quote_id).await
+            }
+
+            async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
+                self.inner.add_keys(keyset).await
+            }
+
+            async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
+                self.inner.remove_keys(id).await
+            }
+        }
+    };
+}
+
 /// FFI-safe database type enum
 #[derive(uniffi::Enum, Clone)]
 pub enum WalletDbBackend {

+ 2 - 219
crates/cdk-ffi/src/postgres.rs

@@ -1,7 +1,5 @@
-use std::collections::HashMap;
 use std::sync::Arc;
 
-// Bring the CDK wallet database trait into scope so trait methods resolve on the inner DB
 use cdk_postgres::PgConnectionPool;
 
 use crate::{
@@ -59,220 +57,5 @@ impl WalletPostgresDatabase {
     }
 }
 
-#[uniffi::export(async_runtime = "tokio")]
-#[async_trait::async_trait]
-impl WalletDatabase for WalletPostgresDatabase {
-    // ========== Read methods ==========
-
-    async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, FfiError> {
-        self.inner.get_proofs_by_ys(ys).await
-    }
-
-    async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
-        self.inner.get_mint(mint_url).await
-    }
-
-    async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, FfiError> {
-        self.inner.get_mints().await
-    }
-
-    async fn get_mint_keysets(
-        &self,
-        mint_url: MintUrl,
-    ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
-        self.inner.get_mint_keysets(mint_url).await
-    }
-
-    async fn get_keyset_by_id(&self, keyset_id: Id) -> Result<Option<KeySetInfo>, FfiError> {
-        self.inner.get_keyset_by_id(keyset_id).await
-    }
-
-    async fn get_mint_quote(&self, quote_id: String) -> Result<Option<MintQuote>, FfiError> {
-        self.inner.get_mint_quote(quote_id).await
-    }
-
-    async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
-        self.inner.get_mint_quotes().await
-    }
-
-    async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
-        self.inner.get_unissued_mint_quotes().await
-    }
-
-    async fn get_melt_quote(&self, quote_id: String) -> Result<Option<MeltQuote>, FfiError> {
-        self.inner.get_melt_quote(quote_id).await
-    }
-
-    async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
-        self.inner.get_melt_quotes().await
-    }
-
-    async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
-        self.inner.get_keys(id).await
-    }
-
-    async fn get_proofs(
-        &self,
-        mint_url: Option<MintUrl>,
-        unit: Option<CurrencyUnit>,
-        state: Option<Vec<ProofState>>,
-        spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Vec<ProofInfo>, FfiError> {
-        self.inner
-            .get_proofs(mint_url, unit, state, spending_conditions)
-            .await
-    }
-
-    async fn get_balance(
-        &self,
-        mint_url: Option<MintUrl>,
-        unit: Option<CurrencyUnit>,
-        state: Option<Vec<ProofState>>,
-    ) -> Result<u64, FfiError> {
-        self.inner.get_balance(mint_url, unit, state).await
-    }
-
-    async fn get_transaction(
-        &self,
-        transaction_id: TransactionId,
-    ) -> Result<Option<Transaction>, FfiError> {
-        self.inner.get_transaction(transaction_id).await
-    }
-
-    async fn list_transactions(
-        &self,
-        mint_url: Option<MintUrl>,
-        direction: Option<TransactionDirection>,
-        unit: Option<CurrencyUnit>,
-    ) -> Result<Vec<Transaction>, FfiError> {
-        self.inner
-            .list_transactions(mint_url, direction, unit)
-            .await
-    }
-
-    async fn kv_read(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-        key: String,
-    ) -> Result<Option<Vec<u8>>, FfiError> {
-        self.inner
-            .kv_read(primary_namespace, secondary_namespace, key)
-            .await
-    }
-
-    async fn kv_list(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-    ) -> Result<Vec<String>, FfiError> {
-        self.inner
-            .kv_list(primary_namespace, secondary_namespace)
-            .await
-    }
-
-    async fn kv_write(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-        key: String,
-        value: Vec<u8>,
-    ) -> Result<(), FfiError> {
-        self.inner
-            .kv_write(primary_namespace, secondary_namespace, key, value)
-            .await
-    }
-
-    async fn kv_remove(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-        key: String,
-    ) -> Result<(), FfiError> {
-        self.inner
-            .kv_remove(primary_namespace, secondary_namespace, key)
-            .await
-    }
-
-    // ========== Write methods ==========
-
-    async fn update_proofs(
-        &self,
-        added: Vec<ProofInfo>,
-        removed_ys: Vec<PublicKey>,
-    ) -> Result<(), FfiError> {
-        self.inner.update_proofs(added, removed_ys).await
-    }
-
-    async fn update_proofs_state(
-        &self,
-        ys: Vec<PublicKey>,
-        state: ProofState,
-    ) -> Result<(), FfiError> {
-        self.inner.update_proofs_state(ys, state).await
-    }
-
-    async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
-        self.inner.add_transaction(transaction).await
-    }
-
-    async fn remove_transaction(&self, transaction_id: TransactionId) -> Result<(), FfiError> {
-        self.inner.remove_transaction(transaction_id).await
-    }
-
-    async fn update_mint_url(
-        &self,
-        old_mint_url: MintUrl,
-        new_mint_url: MintUrl,
-    ) -> Result<(), FfiError> {
-        self.inner.update_mint_url(old_mint_url, new_mint_url).await
-    }
-
-    async fn increment_keyset_counter(&self, keyset_id: Id, count: u32) -> Result<u32, FfiError> {
-        self.inner.increment_keyset_counter(keyset_id, count).await
-    }
-
-    async fn add_mint(
-        &self,
-        mint_url: MintUrl,
-        mint_info: Option<MintInfo>,
-    ) -> Result<(), FfiError> {
-        self.inner.add_mint(mint_url, mint_info).await
-    }
-
-    async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
-        self.inner.remove_mint(mint_url).await
-    }
-
-    async fn add_mint_keysets(
-        &self,
-        mint_url: MintUrl,
-        keysets: Vec<KeySetInfo>,
-    ) -> Result<(), FfiError> {
-        self.inner.add_mint_keysets(mint_url, keysets).await
-    }
-
-    async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
-        self.inner.add_mint_quote(quote).await
-    }
-
-    async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
-        self.inner.remove_mint_quote(quote_id).await
-    }
-
-    async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
-        self.inner.add_melt_quote(quote).await
-    }
-
-    async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
-        self.inner.remove_melt_quote(quote_id).await
-    }
-
-    async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
-        self.inner.add_keys(keyset).await
-    }
-
-    async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
-        self.inner.remove_keys(id).await
-    }
-}
+// Use macro to implement WalletDatabase trait - delegates all methods to inner
+crate::impl_ffi_wallet_database!(WalletPostgresDatabase);

+ 2 - 218
crates/cdk-ffi/src/sqlite.rs

@@ -1,4 +1,3 @@
-use std::collections::HashMap;
 use std::sync::Arc;
 
 use cdk_sqlite::wallet::WalletSqliteDatabase as CdkWalletSqliteDatabase;
@@ -64,220 +63,5 @@ impl WalletSqliteDatabase {
     }
 }
 
-#[uniffi::export(async_runtime = "tokio")]
-#[async_trait::async_trait]
-impl WalletDatabase for WalletSqliteDatabase {
-    // ========== Read methods ==========
-
-    async fn get_proofs_by_ys(&self, ys: Vec<PublicKey>) -> Result<Vec<ProofInfo>, FfiError> {
-        self.inner.get_proofs_by_ys(ys).await
-    }
-
-    async fn get_mint(&self, mint_url: MintUrl) -> Result<Option<MintInfo>, FfiError> {
-        self.inner.get_mint(mint_url).await
-    }
-
-    async fn get_mints(&self) -> Result<HashMap<MintUrl, Option<MintInfo>>, FfiError> {
-        self.inner.get_mints().await
-    }
-
-    async fn get_mint_keysets(
-        &self,
-        mint_url: MintUrl,
-    ) -> Result<Option<Vec<KeySetInfo>>, FfiError> {
-        self.inner.get_mint_keysets(mint_url).await
-    }
-
-    async fn get_keyset_by_id(&self, keyset_id: Id) -> Result<Option<KeySetInfo>, FfiError> {
-        self.inner.get_keyset_by_id(keyset_id).await
-    }
-
-    async fn get_mint_quote(&self, quote_id: String) -> Result<Option<MintQuote>, FfiError> {
-        self.inner.get_mint_quote(quote_id).await
-    }
-
-    async fn get_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
-        self.inner.get_mint_quotes().await
-    }
-
-    async fn get_unissued_mint_quotes(&self) -> Result<Vec<MintQuote>, FfiError> {
-        self.inner.get_unissued_mint_quotes().await
-    }
-
-    async fn get_melt_quote(&self, quote_id: String) -> Result<Option<MeltQuote>, FfiError> {
-        self.inner.get_melt_quote(quote_id).await
-    }
-
-    async fn get_melt_quotes(&self) -> Result<Vec<MeltQuote>, FfiError> {
-        self.inner.get_melt_quotes().await
-    }
-
-    async fn get_keys(&self, id: Id) -> Result<Option<Keys>, FfiError> {
-        self.inner.get_keys(id).await
-    }
-
-    async fn get_proofs(
-        &self,
-        mint_url: Option<MintUrl>,
-        unit: Option<CurrencyUnit>,
-        state: Option<Vec<ProofState>>,
-        spending_conditions: Option<Vec<SpendingConditions>>,
-    ) -> Result<Vec<ProofInfo>, FfiError> {
-        self.inner
-            .get_proofs(mint_url, unit, state, spending_conditions)
-            .await
-    }
-
-    async fn get_balance(
-        &self,
-        mint_url: Option<MintUrl>,
-        unit: Option<CurrencyUnit>,
-        state: Option<Vec<ProofState>>,
-    ) -> Result<u64, FfiError> {
-        self.inner.get_balance(mint_url, unit, state).await
-    }
-
-    async fn get_transaction(
-        &self,
-        transaction_id: TransactionId,
-    ) -> Result<Option<Transaction>, FfiError> {
-        self.inner.get_transaction(transaction_id).await
-    }
-
-    async fn list_transactions(
-        &self,
-        mint_url: Option<MintUrl>,
-        direction: Option<TransactionDirection>,
-        unit: Option<CurrencyUnit>,
-    ) -> Result<Vec<Transaction>, FfiError> {
-        self.inner
-            .list_transactions(mint_url, direction, unit)
-            .await
-    }
-
-    async fn kv_read(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-        key: String,
-    ) -> Result<Option<Vec<u8>>, FfiError> {
-        self.inner
-            .kv_read(primary_namespace, secondary_namespace, key)
-            .await
-    }
-
-    async fn kv_list(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-    ) -> Result<Vec<String>, FfiError> {
-        self.inner
-            .kv_list(primary_namespace, secondary_namespace)
-            .await
-    }
-
-    async fn kv_write(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-        key: String,
-        value: Vec<u8>,
-    ) -> Result<(), FfiError> {
-        self.inner
-            .kv_write(primary_namespace, secondary_namespace, key, value)
-            .await
-    }
-
-    async fn kv_remove(
-        &self,
-        primary_namespace: String,
-        secondary_namespace: String,
-        key: String,
-    ) -> Result<(), FfiError> {
-        self.inner
-            .kv_remove(primary_namespace, secondary_namespace, key)
-            .await
-    }
-
-    // ========== Write methods ==========
-
-    async fn update_proofs(
-        &self,
-        added: Vec<ProofInfo>,
-        removed_ys: Vec<PublicKey>,
-    ) -> Result<(), FfiError> {
-        self.inner.update_proofs(added, removed_ys).await
-    }
-
-    async fn update_proofs_state(
-        &self,
-        ys: Vec<PublicKey>,
-        state: ProofState,
-    ) -> Result<(), FfiError> {
-        self.inner.update_proofs_state(ys, state).await
-    }
-
-    async fn add_transaction(&self, transaction: Transaction) -> Result<(), FfiError> {
-        self.inner.add_transaction(transaction).await
-    }
-
-    async fn remove_transaction(&self, transaction_id: TransactionId) -> Result<(), FfiError> {
-        self.inner.remove_transaction(transaction_id).await
-    }
-
-    async fn update_mint_url(
-        &self,
-        old_mint_url: MintUrl,
-        new_mint_url: MintUrl,
-    ) -> Result<(), FfiError> {
-        self.inner.update_mint_url(old_mint_url, new_mint_url).await
-    }
-
-    async fn increment_keyset_counter(&self, keyset_id: Id, count: u32) -> Result<u32, FfiError> {
-        self.inner.increment_keyset_counter(keyset_id, count).await
-    }
-
-    async fn add_mint(
-        &self,
-        mint_url: MintUrl,
-        mint_info: Option<MintInfo>,
-    ) -> Result<(), FfiError> {
-        self.inner.add_mint(mint_url, mint_info).await
-    }
-
-    async fn remove_mint(&self, mint_url: MintUrl) -> Result<(), FfiError> {
-        self.inner.remove_mint(mint_url).await
-    }
-
-    async fn add_mint_keysets(
-        &self,
-        mint_url: MintUrl,
-        keysets: Vec<KeySetInfo>,
-    ) -> Result<(), FfiError> {
-        self.inner.add_mint_keysets(mint_url, keysets).await
-    }
-
-    async fn add_mint_quote(&self, quote: MintQuote) -> Result<(), FfiError> {
-        self.inner.add_mint_quote(quote).await
-    }
-
-    async fn remove_mint_quote(&self, quote_id: String) -> Result<(), FfiError> {
-        self.inner.remove_mint_quote(quote_id).await
-    }
-
-    async fn add_melt_quote(&self, quote: MeltQuote) -> Result<(), FfiError> {
-        self.inner.add_melt_quote(quote).await
-    }
-
-    async fn remove_melt_quote(&self, quote_id: String) -> Result<(), FfiError> {
-        self.inner.remove_melt_quote(quote_id).await
-    }
-
-    async fn add_keys(&self, keyset: KeySet) -> Result<(), FfiError> {
-        self.inner.add_keys(keyset).await
-    }
-
-    async fn remove_keys(&self, id: Id) -> Result<(), FfiError> {
-        self.inner.remove_keys(id).await
-    }
-}
+// Use macro to implement WalletDatabase trait - delegates all methods to inner
+crate::impl_ffi_wallet_database!(WalletSqliteDatabase);