Cross-platform FFI bindings for the VSS (Versioned Storage Service) Rust Client, providing a simple interface for mobile applications to interact with VSS servers.
- Rust 1.75+
uniffi-bindgenfor generating bindings
# Basic build
cargo build --release
# Generate iOS and Android bindings
./build.sh all
# Generate Swift bindings for iOS
./build_ios.sh
# Generate Kotlin bindings for Android
./build_android.shimport VssRustClientFfi
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
let passphrase: String? = nil
let storeId = try vssDeriveStoreId(
prefix: "bitkit_v1_regtest",
mnemonic: mnemonic,
passphrase: passphrase
)
try await vssNewClientWithLnurlAuth(
baseUrl: "https://vss.example.com",
storeId: storeId,
mnemonic: mnemonic,
passphrase: passphrase,
lnurlAuthServerUrl: "https://auth.example.com/lnurl"
)
// Store data
let item = try await vssStore(
key: "user-settings",
value: "{'theme': 'dark'}".data(using: .utf8)!
)
print("Stored at version: \(item.version)")
// Retrieve data
if let item = try await vssGet(key: "user-settings") {
let data = String(data: item.value, encoding: .utf8)
print("Retrieved: \(data)")
}
// List all items with prefix
let items = try await vssList(prefix: "user/")
for item in items {
print("Key: \(item.key), Version: \(item.version)")
}
// Delete data
let wasDeleted = try await vssDelete(key: "user-settings")
print("Deleted: \(wasDeleted)")
// Clean shutdown (optional)
vssShutdownClient()For fully isolated LDK operations with independent key derivation (full 64-byte BIP39 seed):
// Initialize the dedicated LDK client (separate from the app client)
try await vssNewLdkClientWithLnurlAuth(
baseUrl: "https://vss.example.com",
storeId: storeId,
mnemonic: mnemonic,
passphrase: passphrase,
lnurlAuthServerUrl: "https://auth.example.com/lnurl"
)
// Read an ldk-node key
if let item = try await vssLdkGet(key: "network_graph", namespace: .default) {
print("Graph size: \(item.value.count) bytes")
}
// Store a key
let item = try await vssLdkStore(
key: "network_graph",
value: graphData,
namespace: .default
)
// Delete a key
let wasDeleted = try await vssLdkDelete(key: "network_graph", namespace: .default)
// List keys in a namespace
let keys = try await vssLdkListKeys(namespace: .monitors)
// List all keys across all namespaces
let allKeys = try await vssLdkListAllKeys()
// Clean shutdown
vssShutdownLdkClient()import uniffi.vss_rust_client_ffi.*
val mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
val passphrase: String? = null
val storeId = vssDeriveStoreId(
prefix = "bitkit_v1_regtest",
mnemonic = mnemonic,
passphrase = passphrase
)
vssNewClientWithLnurlAuth(
baseUrl = "https://vss.example.com",
storeId = storeId,
mnemonic = mnemonic,
passphrase = passphrase,
lnurlAuthServerUrl = "https://auth.example.com/lnurl"
)
// Store data
val item = vssStore(
key = "user-settings",
value = "{'theme': 'dark'}".toByteArray()
)
println("Stored at version: ${item.version}")
// Retrieve data
val retrievedItem = vssGet("user-settings")
retrievedItem?.let {
println("Retrieved: ${String(it.value)}")
}
// List all items
val items = vssList(prefix = null)
items.forEach { item ->
println("Key: ${item.key}, Version: ${item.version}")
}
// Clean shutdown (optional)
vssShutdownClient()// Initialize the dedicated LDK client (separate from the app client)
vssNewLdkClientWithLnurlAuth(
baseUrl = "https://vss.example.com",
storeId = storeId,
mnemonic = mnemonic,
passphrase = passphrase,
lnurlAuthServerUrl = "https://auth.example.com/lnurl"
)
// Read an ldk-node key
val item = vssLdkGet(key = "network_graph", namespace = LdkNamespace.Default)
item?.let { println("Graph size: ${it.value.size} bytes") }
// Store a key
val stored = vssLdkStore(
key = "network_graph",
value = graphData,
namespace = LdkNamespace.Default
)
// Delete a key
val wasDeleted = vssLdkDelete(key = "network_graph", namespace = LdkNamespace.Default)
// List keys in a namespace
val keys = vssLdkListKeys(namespace = LdkNamespace.Monitors)
// List all keys across all namespaces
val allKeys = vssLdkListAllKeys()
// Clean shutdown
vssShutdownLdkClient()This constructor is rejected and always returns AuthError. Unauthenticated VSS does not
have a seed-derived encryption key. Use vssNewClientWithLnurlAuth instead.
baseUrl: VSS server URL (e.g., "https://vss.example.com")storeId: Unique identifier for your storage namespace
vssNewClientWithLnurlAuth(baseUrl: String, storeId: String, mnemonic: String, passphrase: String?, lnurlAuthServerUrl: String) -> Void
Initialize the global VSS client connection with LNURL-auth authentication. Provides automatic JWT token management and data encryption.
baseUrl: VSS server URL (e.g., "https://vss.example.com")storeId: Unique identifier for your storage namespacemnemonic: BIP39 mnemonic phrase (12 or 24 words)passphrase: Optional BIP39 passphrase (passnullif none)lnurlAuthServerUrl: LNURL-auth server URL for authentication
Shutdown the VSS client and clean up resources. Optional but recommended for clean application shutdown.
Derives a deterministic VSS store ID from a mnemonic and optional passphrase using BIP32 key derivation.
prefix: A prefix to include in the store ID (e.g., "bitkit_v1_regtest")mnemonic: BIP39 mnemonic phrase (12 or 24 words)passphrase: Optional BIP39 passphrase
Store a key-value pair. The server automatically manages versioning, incrementing the version number with each update.
Retrieve an item by key. Returns null if not found.
List all items, optionally filtered by key prefix. Includes full data.
List keys and versions only (more efficient than vssList).
Store multiple items in a single atomic transaction. The server manages versioning for all items.
Delete an item. Returns true if item existed and was deleted.
A fully separate client (LdkVssClient) with its own key derivation using the full 64-byte BIP39 seed, independent from the app backup client. Use this when LDK operations must be completely isolated from app backup operations.
vssNewLdkClientWithLnurlAuth(baseUrl: String, storeId: String, mnemonic: String, passphrase: String?, lnurlAuthServerUrl: String) -> Void
Initialize the dedicated LDK client with LNURL-auth authentication. This client is fully separate from the app client initialized with vssNewClientWithLnurlAuth.
Shutdown the dedicated LDK client and clean up resources.
Store a key-value pair using the dedicated LDK client.
Retrieve an item by key using the dedicated LDK client. Returns null if not found.
Delete an item using the dedicated LDK client. Returns true if item existed and was deleted.
List keys in a namespace using the dedicated LDK client.
List all keys across all singleton LDK namespaces using the dedicated LDK client.
key: String- The item keyvalue: Data- The stored dataversion: Int64- Version number
key: String- The item keyvalue: Data- The data to store
key: String- The item keyversion: Int64- Version number
Default- Default namespace (channel_manager, scorer, etc.)Monitors- Channel monitorsMonitorUpdates(monitorId)- Updates for a specific monitorArchivedMonitors- Archived channel monitors
Error enum with detailed error information for different failure scenarios.
./build_ios.shGenerates:
dist/ios/VssRustClientFfi.xcframework- iOS frameworkdist/ios/VssRustClientFfi.xcframework.zip- zipped SwiftPM binary artifact for release uploadbindings/ios/vss_rust_client_ffi.swift- Swift bindings source used byPackage.swiftbindings/ios/vss_rust_client_ffiFFI.handbindings/ios/module.modulemap- C interface files used by the Swift package
./build_android.shGenerates:
bindings/android/src/main/kotlin/com/synonym/vssclient/vss_rust_client_ffi.kt- Kotlin bindingsbindings/android/src/main/jniLibs/- native libraries for all Android architecturesbindings/android/native-debug-symbols.zip- native debug symbols for release metadata
Generated iOS and Android artifacts are ignored by git and should be produced by the build scripts or CI instead of committed.
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install uniffi-bindgen
cargo install uniffi_bindgen# Run unit tests (recommended)
cargo test tests::tests --lib
# Check compilation
cargo check
# Build library
cargo build --release
# Test bindings generation
cargo run --bin uniffi-bindgen generate \
--library ./target/release/libvss_rust_client_ffi.dylib \
--language swift \
--out-dir ./test_bindingsThis library provides a thin FFI wrapper around the vss-client-ng Rust library, exposing a simplified async API suitable for mobile and cross-platform applications.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Run
cargo testandcargo clippy - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- VSS Server - The VSS server implementation
- vss-client-ng - The underlying Rust client library
- UniFFI - The FFI binding generator