Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
bd97cf4
feat: trezor hardware support
coreyphillips Feb 18, 2026
74de0ce
fix: detekt warning
coreyphillips Feb 18, 2026
391242f
fix: bump bitkit-core to 0.1.39
coreyphillips Feb 18, 2026
89172b2
fix: add TrezorCoinType
coreyphillips Feb 25, 2026
e413a7f
chore: upgrade bitkit-core to v0.1.40
coreyphillips Feb 25, 2026
95e9526
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Feb 25, 2026
a1cd7c2
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 3, 2026
4cebd2f
feat: add network selector and balance lookup to trezor dashboard
coreyphillips Mar 3, 2026
8986b33
feat: add tx compose, sign, and broadcast to trezor dashboard
coreyphillips Mar 5, 2026
03b2019
fix: trezor usb priority and connect guard
coreyphillips Mar 6, 2026
dccbab3
fix: bump bitkit-core version
coreyphillips Mar 7, 2026
cf6bb00
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 9, 2026
c6b7973
chore: lint
jvsena42 Mar 9, 2026
4637508
refactor: replace Spacer composable with VerticalSpacer/HorizontalSpacer
jvsena42 Mar 9, 2026
a5b0f64
refactor: replace raw text with custom components
jvsena42 Mar 9, 2026
6fc047c
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
54a14d1
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
88795b6
refactor: replace mising components fix the closet references
jvsena42 Mar 9, 2026
9d9d09d
fix: implement text style patterns using existing screens as reference
jvsena42 Mar 9, 2026
63aa84c
Merge branch 'feat/trezor-hardware-support' of github.com:synonymdev/…
jvsena42 Mar 9, 2026
eca363a
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
c99dffc
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 9, 2026
7b7204e
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 9, 2026
4ad6c84
fix: address pr #792 review feedback
coreyphillips Mar 9, 2026
811d6dc
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 10, 2026
82d27d8
chore: add preview data and previews for trezor screens
jvsena42 Mar 10, 2026
d77a92c
fix: replace clickable text with proper components
jvsena42 Mar 10, 2026
a2a1ae6
fix: match existent spacing patterns
jvsena42 Mar 10, 2026
20c0024
fix: preview and corner radius
jvsena42 Mar 10, 2026
d1f13c4
chore: upgrade bitkit-core bindings
coreyphillips Mar 10, 2026
f635d09
refactor: extract derivation path constants
coreyphillips Mar 10, 2026
1500a1c
fix: address pr #792 review feedback
coreyphillips Mar 10, 2026
f544695
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 10, 2026
9d47337
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 13, 2026
a273e90
chore: update bitkit-core to 0.1.47
coreyphillips Mar 13, 2026
35d55bb
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
a8c82e3
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 16, 2026
818da17
fix: remove dead code
jvsena42 Mar 16, 2026
c6fe3fc
refactor: use Electrum address
jvsena42 Mar 16, 2026
8fb72c9
refactor: replace bgDispatcher with ioDispatcher
jvsena42 Mar 16, 2026
5e39fdd
refactor: convert connectWithThpRetry to Result API
jvsena42 Mar 16, 2026
1828bcd
chore: add missing trailing newlines
jvsena42 Mar 16, 2026
5d28d92
test: add basic tests
jvsena42 Mar 16, 2026
f005d16
chore: log cleanup
jvsena42 Mar 16, 2026
c0ccc80
refactor: composable name
jvsena42 Mar 16, 2026
f5c05ca
refactor: replace shared preferences with DataStore
jvsena42 Mar 16, 2026
a40e6af
chore: upgrade bitkit-core to 0.1.48
coreyphillips Mar 17, 2026
bc3a0fc
fix: add test dispatcher
coreyphillips Mar 17, 2026
a851b87
fix: trezor test
coreyphillips Mar 17, 2026
71dca7c
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 17, 2026
5eb6430
fix: add stable annotation
jvsena42 Mar 19, 2026
e150d8a
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
5fbc9c0
refactor: convert try/catch call to runCatching were possible
jvsena42 Mar 19, 2026
2939356
refactor: apply prefs extension function
jvsena42 Mar 19, 2026
2580905
chore: lint
jvsena42 Mar 19, 2026
3f3746f
fix: warnings
jvsena42 Mar 19, 2026
2806d72
chore: remove dead code
jvsena42 Mar 19, 2026
e798946
refactor: get Electrum url from Env
jvsena42 Mar 19, 2026
dee54ea
refactor: move hardware wallet panel to dev settings
jvsena42 Mar 19, 2026
7dfe56c
fix: bulkTransfer() is only valid for bulk endpoints and returns -1 o…
jvsena42 Mar 19, 2026
c0c497f
Merge branch 'master' into feat/trezor-hardware-support
jvsena42 Mar 19, 2026
e80dc32
fix: remove redundant modifier
jvsena42 Mar 19, 2026
c16d15b
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
jvsena42 Mar 19, 2026
3e02723
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips Mar 20, 2026
2bbec26
Merge branch 'refs/heads/master' into feat/trezor-hardware-support
coreyphillips Mar 23, 2026
d8e2d80
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
coreyphillips Mar 23, 2026
48972c1
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 26, 2026
c92df2b
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Mar 30, 2026
9bff331
chore: update bitkit-core
ovitrif Apr 1, 2026
fe8bdce
feat: add tx history and balance functionality to Trezor dev view
coreyphillips Apr 1, 2026
d9db103
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 2, 2026
27a4d87
Merge remote-tracking branch 'origin/feat/trezor-hardware-support' in…
ovitrif Apr 2, 2026
481459f
chore: upgrade bitkit-core to 0.1.57
coreyphillips Apr 8, 2026
f57a289
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 9, 2026
209eacc
Merge branch 'master' into feat/trezor-hardware-support
ovitrif Apr 21, 2026
57eb7bb
Merge branch 'master' into feat/trezor-hardware-support
coreyphillips May 7, 2026
e951e8a
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 11, 2026
280c4e7
feat: add trezor bridge transport
ovitrif May 17, 2026
f010231
Merge branch 'master' into feat/trezor-hardware-support
ovitrif May 17, 2026
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
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line numberDiff line numberDiff line change
Expand Up@@ -48,6 +48,8 @@ val bcp47Locales = listOf(
)
val e2eBackendEnv = System.getenv("E2E_BACKEND") ?: "local"
val e2eHomegateUrlEnv = System.getenv("E2E_HOMEGATE_URL") ?: "http://127.0.0.1:6288"
val trezorBridgeEnv = System.getenv("TREZOR_BRIDGE")?.toBoolean()?.toString() ?: "false"
val trezorBridgeUrlEnv = System.getenv("TREZOR_BRIDGE_URL") ?: "http://10.0.2.2:21325"

android {
namespace = "to.bitkit"
Expand All@@ -65,6 +67,8 @@ android {
buildConfigField("boolean", "E2E", System.getenv("E2E")?.toBoolean()?.toString() ?: "false")
buildConfigField("String", "E2E_BACKEND", "\"$e2eBackendEnv\"")
buildConfigField("String", "E2E_HOMEGATE_URL", "\"$e2eHomegateUrlEnv\"")
buildConfigField("boolean", "TREZOR_BRIDGE", trezorBridgeEnv)
buildConfigField("String", "TREZOR_BRIDGE_URL", "\"$trezorBridgeUrlEnv\"")
buildConfigField("boolean", "GEO", System.getenv("GEO")?.toBoolean()?.toString() ?: "true")
buildConfigField("String", "LOCALES", "\"${bcp47Locales.joinToString(",")}\"")
}
Expand DownExpand Up@@ -217,7 +221,7 @@ composeCompiler {
}

dependencies {
implementation(fileTree("libs") { include("*.aar") })
implementation(fileTree("libs") { include("*.aar", "*.jar") })
implementation(libs.jna) { artifact { type = "aar" } }
implementation(platform(libs.kotlin.bom))
implementation(libs.core.ktx)
Expand Down
Binary file addedapp/libs/btleplug.aar
Binary file not shown.
Binary file addedapp/libs/jni-utils.jar
Binary file not shown.
9 changes: 8 additions & 1 deletion app/proguard-rules.pro
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,4 +18,11 @@

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile

# btleplug (droidplug) Android Bluetooth support
# These classes are loaded via JNI from Rust code
-keep class com.nonpolynomial.btleplug.** { *; }

# jni-utils support library for btleplug
-keep class io.github.gedgygedgy.rust.** { *; }
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,6 +26,25 @@
android:name="android.permission.FOREGROUND_SERVICE"
tools:ignore="ForegroundServicePermission,ForegroundServicesPolicy" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />

<!-- USB Host support for Trezor hardware wallet -->
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />

<!-- Bluetooth permissions for Trezor Safe 7 (Android 12+) -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" />

<!-- Bluetooth permissions (legacy, Android 11 and below) -->
<uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />

<!-- Required for E2E tests connecting to local Electrum server (Android 16+) -->
<uses-permission
android:name="android.permission.NEARBY_WIFI_DEVICES"
Expand DownExpand Up@@ -132,6 +151,14 @@
<data android:scheme="lnurlp" />
</intent-filter>

<!-- USB device attached — auto-grants permission when Trezor is plugged in -->
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/App.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -11,6 +11,7 @@ import coil3.ImageLoader
import coil3.SingletonImageLoader
import dagger.hilt.android.HiltAndroidApp
import to.bitkit.env.Env
import to.bitkit.services.BluetoothInit
import javax.inject.Inject

@HiltAndroidApp
Expand All@@ -31,6 +32,8 @@ internal open class App : Application(), Configuration.Provider {
SingletonImageLoader.setSafe { imageLoader }
currentActivity = CurrentActivity().also { registerActivityLifecycleCallbacks(it) }
Env.initAppStoragePath(filesDir.absolutePath)
// Initialize btleplug for Bluetooth support (required before any BLE usage)
BluetoothInit.ensureInitialized()
}

companion object {
Expand Down
43 changes: 43 additions & 0 deletions app/src/main/java/to/bitkit/data/TrezorStore.kt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
package to.bitkit.data

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.serialization.Serializable
import to.bitkit.data.serializers.TrezorDataSerializer
import to.bitkit.repositories.KnownDevice
import javax.inject.Inject
import javax.inject.Singleton

private val Context.trezorDataStore: DataStore<TrezorData> by dataStore(
fileName = "trezor_device.json",
serializer = TrezorDataSerializer
)

@Singleton
class TrezorStore @Inject constructor(
@ApplicationContext private val context: Context,
) {
private val store = context.trezorDataStore

val data: Flow<TrezorData> = store.data

suspend fun loadKnownDevices(): List<KnownDevice> =
store.data.first().knownDevices

suspend fun saveKnownDevices(devices: List<KnownDevice>) {
store.updateData { it.copy(knownDevices = devices) }
}

suspend fun reset() {
store.updateData { TrezorData() }
}
}

@Serializable
data class TrezorData(
val knownDevices: List<KnownDevice> = emptyList(),
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
package to.bitkit.data.serializers

import androidx.datastore.core.Serializer
import kotlinx.serialization.SerializationException
import to.bitkit.data.TrezorData
import to.bitkit.di.json
import to.bitkit.utils.Logger
import java.io.InputStream
import java.io.OutputStream

object TrezorDataSerializer : Serializer<TrezorData> {
override val defaultValue: TrezorData = TrezorData()

override suspend fun readFrom(input: InputStream): TrezorData {
return try {
json.decodeFromString(input.readBytes().decodeToString())
} catch (e: SerializationException) {
Logger.error("Failed to deserialize: $e")
defaultValue
}
}

override suspend fun writeTo(t: TrezorData, output: OutputStream) {
output.write(json.encodeToString(t).encodeToByteArray())
}
}
12 changes: 12 additions & 0 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,7 @@ import to.bitkit.models.NodePeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

@Suppress("ConstPropertyName", "KotlinConstantConditions", "SimplifyBooleanWithConstants")
internal object Env {
Expand DownExpand Up@@ -199,6 +200,17 @@ internal object Env {
else -> "https://bitkit.stag0.blocktank.to/backups-ldk"
}

fun electrumUrlForNetwork(network: BitkitCoreNetwork): String {
val isE2eLocal = isE2eTest && e2eBackend == "local"
return when (network) {
BitkitCoreNetwork.BITCOIN -> ElectrumServers.MAINNET.ESPLORA
BitkitCoreNetwork.TESTNET, BitkitCoreNetwork.TESTNET4, BitkitCoreNetwork.SIGNET ->
ElectrumServers.TESTNET
BitkitCoreNetwork.REGTEST ->
if (isE2eLocal) ElectrumServers.REGTEST.LOCAL else ElectrumServers.REGTEST.STAG
}
}

// endregion

// region paths
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/to/bitkit/ext/Context.kt
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,13 +3,15 @@ package to.bitkit.ext
import android.app.Activity
import android.app.ActivityManager
import android.app.NotificationManager
import android.bluetooth.BluetoothManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Context.NOTIFICATION_SERVICE
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.hardware.usb.UsbManager
import android.provider.Settings
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
Expand All@@ -31,6 +33,12 @@ val Context.clipboardManager: ClipboardManager
val Context.activityManager: ActivityManager
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val Context.usbManager: UsbManager
get() = getSystemService(Context.USB_SERVICE) as UsbManager

val Context.bluetoothManager: BluetoothManager
get() = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager

// Permissions

fun Context.requiresPermission(permission: String): Boolean =
Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/to/bitkit/models/Network.kt
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
package to.bitkit.models

import com.synonym.bitkitcore.NetworkType
import com.synonym.bitkitcore.TrezorCoinType
import org.lightningdevkit.ldknode.Network
import com.synonym.bitkitcore.Network as BitkitCoreNetwork

Expand All@@ -11,6 +12,13 @@ fun Network.networkUiText(): String = when (this) {
Network.REGTEST -> "Regtest"
}

fun Network.toTrezorCoinType(): TrezorCoinType = when (this) {
Network.BITCOIN -> TrezorCoinType.BITCOIN
Network.TESTNET -> TrezorCoinType.TESTNET
Network.SIGNET -> TrezorCoinType.SIGNET
Network.REGTEST -> TrezorCoinType.REGTEST
}

fun Network.toCoreNetwork(): BitkitCoreNetwork = when (this) {
Network.BITCOIN -> BitkitCoreNetwork.BITCOIN
Network.TESTNET -> BitkitCoreNetwork.TESTNET
Expand All@@ -31,3 +39,11 @@ fun NetworkType.toLdkNetwork(): Network = when (this) {
NetworkType.SIGNET -> Network.SIGNET
NetworkType.REGTEST -> Network.REGTEST
}

fun BitkitCoreNetwork.toTrezorCoinType(): TrezorCoinType = when (this) {
BitkitCoreNetwork.BITCOIN -> TrezorCoinType.BITCOIN
BitkitCoreNetwork.TESTNET -> TrezorCoinType.TESTNET
BitkitCoreNetwork.TESTNET4 -> TrezorCoinType.TESTNET
BitkitCoreNetwork.SIGNET -> TrezorCoinType.SIGNET
BitkitCoreNetwork.REGTEST -> TrezorCoinType.REGTEST
}
Loading
Loading