Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f111b85
feat: support all address types
ben-kaufman Feb 18, 2026
d9d7c6d
Replace node restart with dynamic address type APIs
ben-kaufman Feb 18, 2026
f9b812d
update ldk-node
ben-kaufman Feb 18, 2026
8738aeb
remove fee buffer
ben-kaufman Feb 18, 2026
cb76204
Merge branch 'feat/multiple-addresses-types' into refactor/dynamic-ad…
ben-kaufman Feb 18, 2026
87d977c
fix transfer max to savings
ben-kaufman Feb 18, 2026
2480b36
Increase tests
ben-kaufman Feb 19, 2026
e11f4a2
Update ldk-node
ben-kaufman Feb 20, 2026
e92b519
Merge pull request #789 from synonymdev/refactor/dynamic-address-type…
ben-kaufman Feb 20, 2026
19d91a0
Merge branch 'master' into feat/multiple-addresses-types
ben-kaufman Feb 20, 2026
58d16aa
toast test ids
piotr-iohk Feb 20, 2026
8cfab11
fixes
ben-kaufman Feb 24, 2026
81b1b95
suppress LongParameterList
ben-kaufman Feb 24, 2026
e1d14f9
fix test
ben-kaufman Feb 24, 2026
f3e10d7
fix test
ben-kaufman Feb 24, 2026
f398725
Update ldk-node
ben-kaufman Feb 25, 2026
3bd89a9
Merge branch 'master' into feat/multiple-addresses-types
ben-kaufman Feb 25, 2026
9b0635b
Fix ldk node package name
ben-kaufman Feb 25, 2026
bf46211
Update libs.versions.toml
ben-kaufman Feb 25, 2026
4ddd5f5
Merge branch 'master' into feat/multiple-addresses-types
ben-kaufman Feb 25, 2026
6308576
fix issues
ben-kaufman Feb 26, 2026
b143972
Merge branch 'master' into feat/multiple-addresses-types
ben-kaufman Feb 27, 2026
1c3bad5
fixes
ben-kaufman Mar 2, 2026
48e2db1
Merge branch 'master' into feat/multiple-addresses-types
ben-kaufman Mar 2, 2026
486486c
fix tests
ben-kaufman Mar 2, 2026
9c03667
fix max channel open balance
ben-kaufman Mar 2, 2026
3ddae7b
fix max amount for channel open
ben-kaufman Mar 2, 2026
a6aa908
Merge branch 'master' into feat/multiple-addresses-types
ben-kaufman Mar 3, 2026
53533d0
fix balance issue and add logs
ben-kaufman Mar 3, 2026
f5171fa
disable type selection while loading
ben-kaufman Mar 3, 2026
57f3c95
test multiple addresses
piotr-iohk Mar 3, 2026
beb41b4
run flow on re-open
piotr-iohk Mar 3, 2026
88bde02
Update MigrationService.kt
ben-kaufman Mar 4, 2026
2e78359
fix: add @Immutable to AddressTypePreferenceUiState to fix Compose st…
ben-kaufman Mar 4, 2026
2331293
Merge remote-tracking branch 'origin/master' into feat/multiple-addre…
ben-kaufman Mar 4, 2026
09b2bd8
Delete SweepPromptSheet.kt
ben-kaufman Mar 4, 2026
a42d7a8
migration fixes
ben-kaufman Mar 4, 2026
ffd32ed
Add migration_4 scenario to e2e migration workflow
ben-kaufman Mar 4, 2026
aad545d
Merge pull request #820 from synonymdev/test/multiple-addresses-types
ovitrif Mar 4, 2026
f76fc40
Merge branch 'master' into feat/multiple-addresses-types
ovitrif Mar 4, 2026
903b24a
rename -regtest => -staging
piotr-iohk Mar 5, 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
205 changes: 197 additions & 8 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
required: false
default: "default-feature-branch"
pull_request:
types: [ opened, synchronize, reopened, ready_for_review ]

env:
TERM: xterm-256color
Expand Down Expand Up @@ -37,7 +38,7 @@ jobs:
- 'gradle.properties'
- '.github/workflows/e2e.yml'

build:
build-local:
needs: detect-changes
if: github.event.pull_request.draft == false && needs.detect-changes.outputs.code == 'true'
runs-on: ubuntu-latest
Expand All @@ -60,7 +61,7 @@ jobs:
env:
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}

- name: Build debug app
- name: Build debug app (local)
env:
GITHUB_ACTOR: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -74,12 +75,56 @@ jobs:
apk=$(find app/build/outputs/apk/dev/debug -name 'bitkit-dev-debug-*-universal.apk')
mv "$apk" app/build/outputs/apk/dev/debug/bitkit_e2e.apk

- name: Upload APK
- name: Upload APK (local)
uses: actions/upload-artifact@v4
with:
name: bitkit-e2e-apk_${{ github.run_number }}
path: app/build/outputs/apk/dev/debug/bitkit_e2e.apk

build-staging:
needs: detect-changes
if: github.event.pull_request.draft == false && needs.detect-changes.outputs.code == 'true'
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: "17"
distribution: "adopt"

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Decode google-services.json
run: echo "$GOOGLE_SERVICES_JSON_BASE64" | base64 -d > app/google-services.json
env:
GOOGLE_SERVICES_JSON_BASE64: ${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}

- name: Build debug app (regtest)
env:
GITHUB_ACTOR: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHATWOOT_API: ${{ secrets.CHATWOOT_API }}
E2E: true
E2E_BACKEND: network
GEO: false
run: ./gradlew assembleDevDebug

- name: Rename APK
run: |
apk=$(find app/build/outputs/apk/dev/debug -name 'bitkit-dev-debug-*-universal.apk')
mv "$apk" app/build/outputs/apk/dev/debug/bitkit_e2e.apk

- name: Upload APK (regtest)
uses: actions/upload-artifact@v4
with:
name: bitkit-e2e-apk-regtest_${{ github.run_number }}
path: app/build/outputs/apk/dev/debug/bitkit_e2e.apk

e2e-branch:
needs: detect-changes
if: github.event.pull_request.draft == false && needs.detect-changes.outputs.code == 'true'
Expand All @@ -88,10 +133,10 @@ jobs:
app_branch: ${{ github.head_ref || github.ref_name }}
e2e_branch_input: ${{ github.event.inputs.e2e_branch || 'default-feature-branch' }}

e2e-tests:
e2e-tests-local:
if: github.event.pull_request.draft == false && needs.detect-changes.outputs.code == 'true'
runs-on: ubuntu-latest
needs: [detect-changes, build, e2e-branch]
needs: [detect-changes, build-local, e2e-branch]

strategy:
fail-fast: false
Expand All @@ -103,8 +148,9 @@ jobs:
- { name: send, grep: "@send" }
- { name: lightning_security, grep: "@lightning|@security" }
- { name: lnurl_transfer, grep: "@lnurl|@transfer" }
- { name: multi_address_local, grep: "@multi_address_1|@multi_address_3|@multi_address_4" }

name: e2e-tests - ${{ matrix.shard.name }}
name: e2e-tests-local - ${{ matrix.shard.name }}

steps:
- name: Show selected E2E branch
Expand Down Expand Up @@ -249,11 +295,154 @@ jobs:
if: failure()
uses: jwalton/gh-docker-logs@v2

e2e-tests-staging:
if: github.event.pull_request.draft == false && needs.detect-changes.outputs.code == 'true'
runs-on: ubuntu-latest
needs: [detect-changes, build-staging, e2e-branch]

strategy:
fail-fast: false
matrix:
shard:
- { name: multi_address_2_regtest, grep: "@multi_address_2" }

name: e2e-tests-staging - ${{ matrix.shard.name }}

steps:
- name: Show selected E2E branch
env:
E2E_BRANCH: ${{ needs.e2e-branch.outputs.branch }}
run: echo $E2E_BRANCH

- name: Clone E2E tests
uses: actions/checkout@v4
with:
repository: synonymdev/bitkit-e2e-tests
path: bitkit-e2e-tests
ref: ${{ needs.e2e-branch.outputs.branch }}

- name: Enable KVM
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: AVD cache
uses: actions/cache@v4
id: avd-cache
with:
path: |
~/.android/avd/*
~/.android/adb*
key: avd-33-x86_64-pixel_6

- name: Create AVD and generate snapshot for caching
if: steps.avd-cache.outputs.cache-hit != 'true'
uses: reactivecircus/android-emulator-runner@v2
with:
profile: pixel_6
api-level: 33
arch: x86_64
avd-name: Pixel_6
force-avd-creation: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-front none
disable-animations: false
script: echo "Generated AVD snapshot for caching."

- name: Download APK (regtest)
uses: actions/download-artifact@v4
with:
name: bitkit-e2e-apk-regtest_${{ github.run_number }}
path: bitkit-e2e-tests/aut

- name: List APK directory contents
run: ls -l bitkit-e2e-tests/aut

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Cache npm cache
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Install dependencies
working-directory: bitkit-e2e-tests
run: npm ci

- name: Run E2E Tests 1 (${{ matrix.shard.name }})
continue-on-error: true
id: test1
uses: reactivecircus/android-emulator-runner@v2
with:
profile: pixel_6
api-level: 33
arch: x86_64
avd-name: Pixel_6
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-front none
script: cd bitkit-e2e-tests && ./ci_run_android.sh --mochaOpts.grep "${{ matrix.shard.grep }}"
env:
BACKEND: regtest
RECORD_VIDEO: true
ATTEMPT: 1

- name: Run E2E Tests 2 (${{ matrix.shard.name }})
continue-on-error: true
id: test2
if: steps.test1.outcome != 'success'
uses: reactivecircus/android-emulator-runner@v2
with:
profile: pixel_6
api-level: 33
arch: x86_64
avd-name: Pixel_6
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-front none
script: cd bitkit-e2e-tests && ./ci_run_android.sh --mochaOpts.grep "${{ matrix.shard.grep }}"
env:
BACKEND: regtest
RECORD_VIDEO: true
ATTEMPT: 2

- name: Run E2E Tests 3 (${{ matrix.shard.name }})
id: test3
if: steps.test1.outcome != 'success' && steps.test2.outcome != 'success'
uses: reactivecircus/android-emulator-runner@v2
with:
profile: pixel_6
api-level: 33
arch: x86_64
avd-name: Pixel_6
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-front none
script: cd bitkit-e2e-tests && ./ci_run_android.sh --mochaOpts.grep "${{ matrix.shard.grep }}"
env:
BACKEND: regtest
RECORD_VIDEO: true
ATTEMPT: 3

- name: Upload E2E Artifacts (${{ matrix.shard.name }})
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e-artifacts-regtest_${{ matrix.shard.name }}_${{ github.run_number }}
path: bitkit-e2e-tests/artifacts/

- name: Dump docker logs on failure (${{ matrix.shard.name }})
if: failure()
uses: jwalton/gh-docker-logs@v2

e2e-status:
if: always() && github.event.pull_request.draft == false
name: e2e-status
runs-on: ubuntu-latest
needs: [detect-changes, e2e-tests]
needs: [detect-changes, e2e-tests-local, e2e-tests-staging]
steps:
- name: E2E skipped - no code changes
if: needs.detect-changes.outputs.code != 'true'
Expand All @@ -262,7 +451,7 @@ jobs:
- name: Verify all E2E shards succeeded
if: needs.detect-changes.outputs.code == 'true'
run: |
if [ "${{ needs.e2e-tests.result }}" != "success" ]; then
if [ "${{ needs.e2e-tests-local.result }}" != "success" ] || [ "${{ needs.e2e-tests-staging.result }}" != "success" ]; then
echo "❌ Some E2E shards failed."
exit 1
fi
Expand Down
16 changes: 15 additions & 1 deletion app/src/main/java/to/bitkit/data/SettingsStore.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import to.bitkit.data.serializers.SettingsSerializer
import to.bitkit.env.Env
import to.bitkit.models.BitcoinDisplayUnit
import to.bitkit.models.CoinSelectionPreference
import to.bitkit.models.DEFAULT_ADDRESS_TYPE_STRING
import to.bitkit.models.PrimaryDisplay
import to.bitkit.models.SettingsBackupV1
import to.bitkit.models.Suggestion
Expand All @@ -31,12 +32,21 @@ class SettingsStore @Inject constructor(

val data: Flow<SettingsData> = store.data

@Volatile
var restoredMonitoredTypesFromBackup: Boolean = false
private set

suspend fun restoreFromBackup(payload: SettingsBackupV1) =
runCatching {
val data = payload.settings.resetPin()
store.updateData { data }

val monitored = data.addressTypesToMonitor
val selected = data.selectedAddressType
restoredMonitoredTypesFromBackup = monitored.size > 1 ||
(monitored.size == 1 && monitored.first() != selected)
}.onSuccess {
Logger.debug("Restored settings", TAG)
Logger.debug("Restored settings, monitoredFromBackup=$restoredMonitoredTypesFromBackup", context = TAG)
}

suspend fun update(transform: (SettingsData) -> SettingsData) {
Expand Down Expand Up @@ -66,6 +76,7 @@ class SettingsStore @Inject constructor(

suspend fun reset() {
store.updateData { SettingsData() }
restoredMonitoredTypesFromBackup = false
Logger.info("Deleted all user settings data.")
}

Expand Down Expand Up @@ -117,6 +128,9 @@ data class SettingsData(
val coinSelectPreference: CoinSelectionPreference = CoinSelectionPreference.BranchAndBound,
val electrumServer: String = Env.electrumServerUrl,
val rgsServerUrl: String? = Env.ldkRgsServerUrl,
val selectedAddressType: String = DEFAULT_ADDRESS_TYPE_STRING,
val addressTypesToMonitor: List<String> = listOf(DEFAULT_ADDRESS_TYPE_STRING),
val pendingRestoreAddressTypePrune: Boolean = false,
)

fun SettingsData.resetPin() = this.copy(
Expand Down
Loading
Loading