Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
c194f6c
docs: add Kotlin SDK migration plan (phased, with shielded-balance re…
bfoss765 Jul 7, 2026
ba70db2
fix: repair pre-existing broken tests and two latent bugs they exposed
bfoss765 Jul 7, 2026
83ce13c
feat!: remove CoinJoin mixing; begin dashj seam neutralization
bfoss765 Jul 7, 2026
25e5baa
refactor: neutral money kit in common; migrate uphold off dashj
bfoss765 Jul 7, 2026
b38b2e1
refactor: migrate exploredash off dashj
bfoss765 Jul 7, 2026
04caa30
refactor: migrate maya off dashj
bfoss765 Jul 7, 2026
75d2181
refactor: migrate coinbase off dashj
bfoss765 Jul 7, 2026
59ee9f6
refactor: migrate crowdnode UI/API surface off dashj
bfoss765 Jul 8, 2026
24fe5b7
docs: update migration plan status — Phase 1 substantially complete
bfoss765 Jul 8, 2026
3840b17
build: raise minSdk to 29 and ship 64-bit ABIs only
bfoss765 Jul 8, 2026
d981946
refactor: vendor BIP70 payment protocol from dashj into common
bfoss765 Jul 8, 2026
25d2e07
docs: Phase 0 status — CoinJoin-restore verified SAFE (conditional), …
bfoss765 Jul 8, 2026
9e24bd5
feat: add Dash Platform Kotlin SDK dependency (Phase 3 start)
bfoss765 Jul 8, 2026
6400ba9
feat: Kotlin SDK bootstrap scaffold (Phase 3a)
bfoss765 Jul 8, 2026
e60ea56
feat: bridge PIN-encrypted wallet seed to the Kotlin SDK (Phase 3b)
bfoss765 Jul 8, 2026
ec6bbf3
feat: first production flow on the Kotlin SDK — DPNS reads (Phase 3c)
bfoss765 Jul 8, 2026
b71aadd
docs: record Phase 4 shielded-UX Figma design references
bfoss765 Jul 8, 2026
8a5af1c
feat: contested-name vote state and profile reads on the Kotlin SDK (…
bfoss765 Jul 8, 2026
36cb571
feat: DashPay writes on the Kotlin SDK behind a new flag (Phase 3e)
bfoss765 Jul 8, 2026
5f98e0f
feat: production SDK wallet binding + identity discovery (Phase 3f)
bfoss765 Jul 8, 2026
3b5d5c1
feat: debug builds seed the Kotlin SDK flags ON for testnet verification
bfoss765 Jul 8, 2026
979195d
fix: don't crash at startup when built without google-services.json
bfoss765 Jul 8, 2026
6d84436
fix: builds without google-services.json start cleanly
bfoss765 Jul 8, 2026
3cb989b
fix: treat SDK 'ManagedIdentity not found' as not-managed in identity…
bfoss765 Jul 8, 2026
4e89be0
fix: classify SDK signing failures as not-broadcast so dashj fallback…
bfoss765 Jul 8, 2026
5a18ea9
feat: heal discovered identity keys so SDK writes can sign (Phase 3f-b)
bfoss765 Jul 8, 2026
1956e30
docs: record live testnet validation results
bfoss765 Jul 8, 2026
b8c3075
docs: draft the 8 Kotlin SDK issues to file on dashpay/platform
bfoss765 Jul 8, 2026
de94a0e
docs/test: verify accept-contact-request is covered by the SDK write …
bfoss765 Jul 8, 2026
67c5860
feat: shielded-balances service layer (Phase 4 plumbing)
bfoss765 Jul 8, 2026
e501b98
feat: shielded-balances UI from Figma designs (Phase 4)
bfoss765 Jul 9, 2026
094cdbe
docs: Phase 4 UI + SDK-fix status
bfoss765 Jul 9, 2026
0adf2c2
feat: L1 shadow-sync parity harness + checkpoint birth-height mapping…
bfoss765 Jul 9, 2026
44b5ade
fix: shielded UI per live testing feedback
bfoss765 Jul 9, 2026
c3fb2ae
feat: Dash Wallet → Shielded funds from the L1 balance (asset-lock pi…
bfoss765 Jul 9, 2026
85bbbe3
feat: shielded-transfer acceptance criteria + live-test fixes
bfoss765 Jul 9, 2026
39388e5
fix: four shielded-transfer bugs from live testing
bfoss765 Jul 9, 2026
3a6fa48
fix: funding gate ignores tx-count delta; credits icon from design
bfoss765 Jul 9, 2026
c15de50
feat: shadow-state corruption detection, auto-reset, and More-card po…
bfoss765 Jul 9, 2026
67af91d
fix: hard shadow reset (filesystem-level), scan watchdog, debug trigger
bfoss765 Jul 9, 2026
c124375
feat: definitive shadow recovery — full SDK-wallet re-creation
bfoss765 Jul 9, 2026
437a2fe
feat: debug builds auto-recreate on persistent empty deficit (remote-…
bfoss765 Jul 9, 2026
672887a
test: pin release vs debug decider semantics; service-level override …
bfoss765 Jul 9, 2026
363ad04
feat: live verification progress on the transfer screen
bfoss765 Jul 10, 2026
2a94e52
feat: show git commit on the About screen in debug builds
bfoss765 Jul 10, 2026
0fadeac
fix: instant balance refresh after shielded ops; More card to 2-decim…
bfoss765 Jul 10, 2026
073fd2d
fix: More balance cards pixel-matched to Figma; shielded card shows S…
bfoss765 Jul 10, 2026
78b4431
feat: L1 send through the SDK behind an opt-in flag (Phase 5b)
bfoss765 Jul 10, 2026
f43b594
fix: stable More-card pill heights; gate transfers on shielded-pool R…
bfoss765 Jul 10, 2026
b0c6554
fix: classify SDK insufficient-funds/coin-selection errors as pre-bro…
bfoss765 Jul 10, 2026
d0cbbd1
fix: classify 'SPV client not started' broadcast failure as pre-broad…
bfoss765 Jul 10, 2026
3114ce8
fix: ensure SDK SPV is running before shield broadcast; live transfer…
bfoss765 Jul 10, 2026
3c81f61
feat: dismissible proving dialog with completion notification/toast
bfoss765 Jul 10, 2026
9e1fed2
feat: stall watchdog for shielded transfers stuck in the native layer
bfoss765 Jul 10, 2026
de7bbdd
fix: restart SDK shadow sync on every blockchain-service start
bfoss765 Jul 10, 2026
25b5ac0
fix: arm the parity self-spend grace before wallet-shield broadcasts
bfoss765 Jul 10, 2026
9c95af0
fix: post the outcome notification whenever off the transfer screen
bfoss765 Jul 10, 2026
bd5aaa1
docs: record 2026-07-10 live-test findings and PR #4074 fix chain
bfoss765 Jul 10, 2026
3162e0b
docs: record the CoinJoin gap-limit root cause and cutover note
bfoss765 Jul 10, 2026
0def78e
feat: debug toggle for SDK L1 sends; heal the missing-mnemonic bind w…
bfoss765 Jul 10, 2026
51400bf
feat: one-tap SDK soak send in debug settings; arm grace on dashj sends
bfoss765 Jul 10, 2026
874ddb1
fix: shielded withdrawals show as received, not internal
bfoss765 Jul 10, 2026
2d9458c
docs: Phase 3h addendum — retire the legacy org.dashj.platform stack
bfoss765 Jul 10, 2026
5bc9db6
docs: Phase 5c design — bridge strategy, SDK gaps, ordered work plan
bfoss765 Jul 10, 2026
ce41e09
feat: fee-parity and bridge-feasibility probes on the L1 send paths
bfoss765 Jul 10, 2026
8847703
feat: route identityVerify docs through the SDK's generic document APIs
bfoss765 Jul 10, 2026
0e4965f
feat: SdkBridgedTransactionFactory — SDK tx bytes to live dashj Trans…
bfoss765 Jul 11, 2026
a413d81
feat: live SDK-engine gate indicator on the debug soak settings
bfoss765 Jul 11, 2026
66385b8
fix: layered SDK fee resolution in the fee-parity probe
bfoss765 Jul 11, 2026
65023be
feat: legacy TxMetadata decrypt-proof probe in debug settings
bfoss765 Jul 11, 2026
1d000e4
feat: create-username flow on the shielded designs
bfoss765 Jul 11, 2026
35e8985
feat: shielded-funded username creation + persistent Join DashPay flow
bfoss765 Jul 11, 2026
a2b2431
debug: forensic logging on the decrypt-probe fetch boundary
bfoss765 Jul 11, 2026
3474a05
docs: spec username creation via authorized L2 fund-hop
bfoss765 Jul 11, 2026
d500fc1
fix: More-screen credits card shows zero on never-configured wallets
bfoss765 Jul 11, 2026
8375a18
fix: rewrite covariant java.nio buffer calls for Android <= 15
bfoss765 Jul 11, 2026
d6728fc
fix: Keystore auth-window accept dead-ends — classify, fall back, sur…
bfoss765 Jul 11, 2026
d8a304d
fix: blank contacts screen after back navigation
bfoss765 Jul 11, 2026
0aa9386
docs: to-do — contested usernames across shielded/invitations/dual paths
bfoss765 Jul 11, 2026
f712077
docs: baseline correction (shipped dpp 4.0.0) + cross-platform contac…
bfoss765 Jul 11, 2026
51f3ec9
fix: tolerate legacy identity-cache CBOR failure on v4.x contact iden…
bfoss765 Jul 11, 2026
dff670f
fix: don't stringify legacy identities — toString CBOR-encodes and th…
bfoss765 Jul 11, 2026
2e49101
feat: contested usernames via the shielded path (0.3 denomination)
bfoss765 Jul 11, 2026
8e73d1b
feat: dual usernames on the shielded path — register the secondary too
bfoss765 Jul 11, 2026
1fd16c4
fix: insufficiency row names the real requirement, not a hardcoded 0.25
bfoss765 Jul 11, 2026
bcb1114
feat: fresh wallets bind for shielded + confirm dialog shows the with…
bfoss765 Jul 11, 2026
665dbc0
fix: testnet faucet moved to faucet.thepasta.org (iOS-example parity)
bfoss765 Jul 11, 2026
a5d0ec0
fix: Reset Wallet must block until DashPay data is actually cleared
bfoss765 Jul 12, 2026
9c0ca26
feat: More-screen shielded card shows DASH, not credits
bfoss765 Jul 12, 2026
4ce6ca1
feat: make-username-private sheet polish + 0.3 max cost (S21 feedback)
bfoss765 Jul 12, 2026
5d9d6dd
test: UsernamePaymentViewModel fixtures gain the walletData collaborator
bfoss765 Jul 12, 2026
004bae4
fix: prune orphan SDK wallets at bind + shielded card font parity
bfoss765 Jul 12, 2026
ae62504
fix: private-username sheet — visible ⓘ, single minimum mention
bfoss765 Jul 12, 2026
7e7d534
feat: adopt DEVICE_BOUND identity keys + org.dashj SDK coordinates
bfoss765 Jul 12, 2026
141f41b
chore: cost explainer titled "Shielded username costs"
bfoss765 Jul 12, 2026
8b73f44
feat: shield-guidance amounts 0.15/0.35 on the funding surfaces
bfoss765 Jul 12, 2026
f863e0f
fix: immediate shielded sync on screen entry and after resumed shields
bfoss765 Jul 12, 2026
a55ac66
fix: Type-20 fallback address must use the storage tag, not 0xb0
bfoss765 Jul 12, 2026
8e2e4c4
fix: missing-encryption-key contact sends fall back to dashj
bfoss765 Jul 12, 2026
bd6861b
feat: dismissible processing dialog during shielded username creation
bfoss765 Jul 12, 2026
e072aae
fix: username qualifier rows are literal, meet-one-of header for all
bfoss765 Jul 12, 2026
f905b28
fix: legacy signing for SDK-created identities — backfill identity ch…
bfoss765 Jul 12, 2026
132a3e8
docs: Phase 5d migration-without-data-loss design (inventory + state …
bfoss765 Jul 12, 2026
23793b1
feat: Phase 5d cutover-readiness evaluator (pure decision table + tests)
bfoss765 Jul 12, 2026
097e7e3
feat: Phase 5d evidence collectors — parity streak, drained-ops, orph…
bfoss765 Jul 12, 2026
a4e5e09
fix: re-seed debug SDK flags after Reset Wallet wipes the DataStore
bfoss765 Jul 12, 2026
a661ae8
feat: Phase 5d step 3 — cutover coordinator + state machine (inert, f…
bfoss765 Jul 12, 2026
b46db60
feat: Phase 5d debug readiness readout + fix ViewModel worker-scope l…
bfoss765 Jul 12, 2026
2e8d396
fix: fingerprint permanently bricked after lock-screen removal (ciphe…
bfoss765 Jul 13, 2026
08c18ff
fix: stop platform sync across Reset Wallet + refuse identity resurre…
bfoss765 Jul 13, 2026
5a7b837
fix: wallet wipe clears live DataStore configs via API, not file dele…
bfoss765 Jul 13, 2026
62b526c
fix: binder latch revalidates against the live wallet on every trigger
bfoss765 Jul 13, 2026
372f32a
fix: gate the inflated-mismatch auto-reset on dashj being genuinely s…
bfoss765 Jul 13, 2026
a2527ae
fix: derive DIP-15 friend chains in the SDK so contact payments are c…
bfoss765 Jul 13, 2026
02dcaf8
fix: contested-username submits are never silent + shared processing …
bfoss765 Jul 14, 2026
5010c33
fix: reconcile NOT_PRESENT username status from platform truth
bfoss765 Jul 14, 2026
48eba90
feat: shielded transfer screen shows all amounts in Dash, never credits
bfoss765 Jul 14, 2026
549db0f
fix: shielded Max withdraw — classify note-selection failures, fee-ad…
bfoss765 Jul 14, 2026
36a7453
fix: Max shield — classify asset-lock selection shortfall, reserve th…
bfoss765 Jul 14, 2026
97f9fa0
fix: shielded timing info sheet — wallet→shielded takes ~30 seconds, …
bfoss765 Jul 14, 2026
9a48c89
feat: mainnet-safe SDK validation — shadow flag binds, network-aware …
bfoss765 Jul 14, 2026
c5ebfee
feat: debug-only Kotlin sync indicator in the home-screen sync header
bfoss765 Jul 14, 2026
1bec8d0
fix: two-engine sync header — 'DashJ 63% · Kotlin 19%', combined Kotl…
bfoss765 Jul 14, 2026
e31d0d3
fix: three live-QA bugs — fail-closed username check, gate-reopen pro…
bfoss765 Jul 15, 2026
5d2742f
feat: show the username under the avatar on the edit-profile screen
bfoss765 Jul 15, 2026
6419365
feat: platform-health warning + honest status during identity registr…
bfoss765 Jul 15, 2026
2f83b23
fix: require authentication before every username-request spend; stal…
bfoss765 Jul 15, 2026
e440f32
feat: keep SDK engines warm across idle teardowns (debug); stall bann…
bfoss765 Jul 15, 2026
cd2a1b8
feat: username tile/cost fixes, creation status in dialog, invite shi…
bfoss765 Jul 15, 2026
91578b7
fix: instant/secondary username confirm is always free (revert cost r…
bfoss765 Jul 15, 2026
4d83184
fix: invite shielded sheet shows the amount to shield (0.15/0.35), no…
bfoss765 Jul 15, 2026
0b4a6b3
fix: four live-QA bugs — shield-first exit, dual-name render, tile fl…
bfoss765 Jul 15, 2026
395ea27
fix: under-avatar dual name shows the DISPLAY form, not the normalize…
bfoss765 Jul 16, 2026
7e5235e
fix: shielded username submit — calm 'still syncing' surface + live p…
bfoss765 Jul 16, 2026
6766aaf
fix: L1 username creation processing dialog now dismisses on completion
bfoss765 Jul 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ android {

defaultConfig {
compileSdk 35
minSdkVersion 24
minSdkVersion 29
targetSdkVersion 35
vectorDrawables.useSupportLibrary = true

Expand Down Expand Up @@ -55,6 +55,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation "org.dashj:dashj-core:$dashjVersion"
implementation 'com.google.protobuf:protobuf-javalite:3.17.3'
// Needed at compile time by the BIP70 code copied from dashj (payments.bip70.X509Utils);
// dashj only exposes bouncycastle as a runtime dependency. Version matches dashj 22.0.3.
implementation 'org.bouncycastle:bcprov-jdk15to18:1.74'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"

Expand Down
20 changes: 16 additions & 4 deletions common/src/main/java/org/dash/wallet/common/WalletDataProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,23 @@ interface WalletDataProvider {
fun freshReceiveAddress(): Address
fun currentReceiveAddress(): Address

// Neutral (dashj-free) accessors for feature/integration modules.
// Default implementations delegate to the dashj-typed methods above.
val networkId: String
get() = networkParameters.id
fun freshReceiveAddressString(): String = freshReceiveAddress().toBase58()
fun currentReceiveAddressString(): String = currentReceiveAddress().toBase58()

fun getWalletBalance(): Coin
fun getMixedBalance(): Coin

/**
* Number of spendable unspent outputs coin selection can draw on —
* `calculateAllSpendCandidates(false, false)`, the exact output set
* `getBalance(ESTIMATED)` sums (all keychains) — or 0 while no wallet
* is loaded.
*/
@Suppress("DEPRECATION")
fun spendableUtxoCount(): Int = wallet?.calculateAllSpendCandidates(false, false)?.size ?: 0

fun observeWalletChanged(): Flow<Unit>

Expand All @@ -59,8 +74,6 @@ interface WalletDataProvider {
coinSelector: CoinSelector? = null
): Flow<Coin>

fun observeSpendableBalance(): Flow<Coin>

fun canAffordIdentityCreation(): Boolean

// Treat @withConfidence with care - it may produce a lot of events and affect performance.
Expand All @@ -84,7 +97,6 @@ interface WalletDataProvider {
fun checkSendingConditions(address: Address?, amount: Coin)

fun observeMostRecentTransaction(): Flow<Transaction>
fun observeMixedBalance(): Flow<Coin>
fun observeTotalBalance(): Flow<Coin>
fun lockOutput(outPoint: TransactionOutPoint): Boolean
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2026 Dash Core Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.dash.wallet.common

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import org.bitcoinj.core.Sha256Hash
import org.bitcoinj.wallet.Wallet
import org.dash.wallet.common.money.Dash
import org.dash.wallet.common.money.toCoin
import org.dash.wallet.common.money.toDash
import org.dash.wallet.common.services.LeftoverBalanceException
import org.dash.wallet.common.transactions.filters.LockedTransaction

// ---------------------------------------------------------------------------------------------
// Neutral (dashj-free) adapters over WalletDataProvider for feature/integration modules.
// They delegate to the dashj-typed interface methods, so behavior is identical.
// ---------------------------------------------------------------------------------------------

/** [WalletDataProvider.observeTotalBalance] as neutral [Dash] amounts. */
fun WalletDataProvider.observeTotalDashBalance(): Flow<Dash> = observeTotalBalance().map { it.toDash() }

/** [WalletDataProvider.observeBalance] (with its default estimated balance type) as neutral [Dash] amounts. */
fun WalletDataProvider.observeDashBalance(): Flow<Dash> = observeBalance().map { it.toDash() }

/** [WalletDataProvider.getWalletBalance] as a neutral [Dash] amount. */
fun WalletDataProvider.getDashBalance(): Dash = getWalletBalance().toDash()

/** Estimated wallet balance (mirrors `wallet.getBalance(BalanceType.ESTIMATED)`), or null when no wallet is loaded. */
@Suppress("DEPRECATION")
fun WalletDataProvider.getEstimatedDashBalance(): Dash? =
wallet?.getBalance(Wallet.BalanceType.ESTIMATED)?.toDash()

/**
* Emits the hex tx id once the wallet transaction with hex id [txId] is IS-locked or confirmed
* (mirrors [WalletDataProvider.observeTransactions] with a [LockedTransaction] filter).
*/
fun WalletDataProvider.observeTransactionLocked(txId: String): Flow<String> =
observeTransactions(true, LockedTransaction(Sha256Hash.wrap(txId))).map { it.txId.toString() }

/**
* Whether the wallet transaction with hex id [txId] is pending (mirrors `Transaction.isPending`);
* false if the wallet doesn't know the transaction.
*/
fun WalletDataProvider.isTransactionPending(txId: String): Boolean =
getTransaction(Sha256Hash.wrap(txId))?.isPending ?: false

/**
* Net wallet value of the transaction with hex id [txId] (mirrors
* `Transaction.getValue(transactionBag)`), or null if the wallet doesn't know the transaction.
*/
fun WalletDataProvider.getTransactionValue(txId: String): Dash? =
getTransaction(Sha256Hash.wrap(txId))?.getValue(transactionBag)?.toDash()

/** Serialized hex of the wallet transaction with hex id [txId], or null if unknown. Useful for logging. */
fun WalletDataProvider.getTransactionHex(txId: String): String? =
getTransaction(Sha256Hash.wrap(txId))?.toStringHex()

/**
* True when sending [amount] would trip the leftover-balance check
* (i.e. [WalletDataProvider.checkSendingConditions] would throw [LeftoverBalanceException]).
*/
fun WalletDataProvider.needsLeftoverBalanceWarning(amount: Dash): Boolean {
return try {
checkSendingConditions(null, amount.toCoin())
false
} catch (_: LeftoverBalanceException) {
true
}
}
51 changes: 50 additions & 1 deletion common/src/main/java/org/dash/wallet/common/data/BaseConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,15 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.CancellationException
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.dash.wallet.common.WalletDataProvider
import org.dash.wallet.common.util.security.EncryptionProvider
import org.slf4j.LoggerFactory
import java.io.IOException
import java.util.WeakHashMap

abstract class BaseConfig(
private val context: Context,
Expand All @@ -47,9 +50,54 @@ abstract class BaseConfig(
private val encryptionProvider: EncryptionProvider? = null,
migrations: List<DataMigration<Preferences>> = listOf()
) {
companion object {
private val log = LoggerFactory.getLogger(BaseConfig::class.java)

// Registry of live BaseConfig instances, weakly referenced so GC'able
// configs don't leak. Every instance registers itself on construction.
// A wallet wipe must clear each LIVE config through its DataStore API
// (memory + disk reset atomically) instead of deleting the backing file
// out-of-band: an out-of-band delete leaves the live DataStore's
// in-memory cache populated while disk is empty, so later reads return
// stale values and later writes recreate the file with a random subset
// of keys (observed live: debug SDK flags never reseeding after a
// Reset Wallet because the stale cache made them look already-set).
private val registryLock = Any()
private val liveInstances = WeakHashMap<BaseConfig, Unit>()

/**
* Clears every live [BaseConfig] instance through its DataStore API and
* returns the DataStore file names (e.g. "dashpay.preferences_pb") that
* were cleared. An instance whose clear fails is logged and excluded
* from the returned set so callers can fall back to raw file deletion
* for it.
*/
suspend fun clearAllLiveInstances(): Set<String> {
val snapshot = synchronized(registryLock) { liveInstances.keys.toList() }
val cleared = mutableSetOf<String>()

for (instance in snapshot) {
try {
instance.clearAll()
cleared.add(instance.preferencesFileName)
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
log.warn("failed to clear live config '{}' via API", instance.preferencesFileName, e)
}
}

return cleared
}
}

private val securityKeyAlias = "${name}_security_key"
private val json = Json { encodeDefaults = true }

/** File name used by the underlying preferences DataStore for this config. */
val preferencesFileName: String
get() = "$name.preferences_pb"

protected val Context.dataStore by preferencesDataStore(
name = name,
produceMigrations = { migrations }
Expand All @@ -65,6 +113,7 @@ abstract class BaseConfig(
}

init {
synchronized(registryLock) { liveInstances[this] = Unit }
walletDataProvider.attachOnWalletWipedListener {
clearAll()
}
Expand Down Expand Up @@ -95,7 +144,7 @@ abstract class BaseConfig(
context.dataStore.secureEdit(value) { preferences, encryptedValue -> preferences[key] = encryptedValue }
}

suspend fun clearAll() {
open suspend fun clearAll() {
context.dataStore.edit { it.clear() }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.protocols.payments.PaymentProtocol;
import org.bitcoinj.protocols.payments.PaymentProtocolException;
import org.dash.wallet.common.payments.bip70.PaymentProtocol;
import org.dash.wallet.common.payments.bip70.PaymentProtocolException;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptException;
Expand Down
31 changes: 31 additions & 0 deletions common/src/main/java/org/dash/wallet/common/data/SyncStage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2026 Dash Core Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.dash.wallet.common.data

/**
* Blockchain sync stage, independent of the underlying wallet library.
* The wallet module maps its sync engine's stages onto these values.
*/
enum class SyncStage {
OFFLINE,
HEADERS,
MNLIST,
PREBLOCKS,
BLOCKS,
COMPLETE
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ open class WalletUIConfig @Inject constructor(
val SELECTED_CURRENCY = stringPreferencesKey("exchange_currency")
val EXCHANGE_CURRENCY_DETECTED = booleanPreferencesKey("exchange_currency_detected")
val LAST_TOTAL_BALANCE = longPreferencesKey("last_total_balance")
val LAST_MIXED_BALANCE = longPreferencesKey("last_mixed_balance")
val CUSTOMIZED_SHORTCUTS = stringPreferencesKey("customized_shortcuts")
val IS_SHORTCUT_INFO_HIDDEN = booleanPreferencesKey("is_shortcut_info_hidden")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,59 @@ data class GiftCard(
var note: String? = null, // holds order number
var index: Int = 0,
var redeemUrlChallenge: String? = null
)
) {
companion object {
/**
* Neutral (dashj-free) factory: builds a GiftCard from a hex transaction id
* ([Sha256Hash.toString] format), for modules that must not depend on dashj.
*/
fun fromHex(
txId: String,
merchantName: String = "",
price: Double = 0.0,
number: String? = null,
pin: String? = null,
barcodeValue: String? = null,
barcodeFormat: BarcodeFormat? = null,
merchantUrl: String? = null,
note: String? = null,
index: Int = 0,
redeemUrlChallenge: String? = null
) = GiftCard(
Sha256Hash.wrap(txId), merchantName, price, number, pin, barcodeValue,
barcodeFormat, merchantUrl, note, index, redeemUrlChallenge
)
}

/** The transaction id as a hex string ([Sha256Hash.toString]); dashj-free accessor. */
val txIdHex: String get() = txId.toString()

/**
* Neutral (dashj-free) variant of [copy]: duplicates the card (txId always preserved)
* with the given field overrides, for modules that must not depend on dashj.
*/
fun copyCard(
merchantName: String = this.merchantName,
price: Double = this.price,
number: String? = this.number,
pin: String? = this.pin,
barcodeValue: String? = this.barcodeValue,
barcodeFormat: BarcodeFormat? = this.barcodeFormat,
merchantUrl: String? = this.merchantUrl,
note: String? = this.note,
index: Int = this.index,
redeemUrlChallenge: String? = this.redeemUrlChallenge
) = copy(
txId = txId,
merchantName = merchantName,
price = price,
number = number,
pin = pin,
barcodeValue = barcodeValue,
barcodeFormat = barcodeFormat,
merchantUrl = merchantUrl,
note = note,
index = index,
redeemUrlChallenge = redeemUrlChallenge
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ data class TransactionMetadata(
@Ignore
val defaultTaxCategory = TaxCategory.getDefault(value.isPositive, isTransfer)

/** [customIconId] as a hex string ([Sha256Hash.toString]); dashj-free accessor. */
val customIconIdHex: String? get() = customIconId?.toString()

fun isNotEmpty(): Boolean {
return timestamp != 0L || taxCategory != null || memo.isNotEmpty() || currencyCode != null ||
rate != null || service != null || customIconId != null
Expand Down
Loading