[#1385] Adopt `AccountBalance` fields in Kotlin layer
* [#1385] Adopt `AccountBalance` fields in Kotlin layer - Adds the Kotlin side changes for #1380 - Changed WalletBalance to contain these three fields: available, changePending, and valuePending, instead of total and available, and change the transparent flow to StateFlow<Zatoshi>, as we don't distinguish there. - Related connected APIs changed - Closes #1385 * Add WalletBalanceFixture Placed in the public directory to be visible for clients as well * Changelog update * Remove `getVerifiedTransparentBalance ` API entirely Co-authored-by: str4d <jack@electriccoin.co>
This commit is contained in:
parent
b617eb1bb3
commit
19cca515fb
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -6,6 +6,16 @@ and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
- `WalletBalance` now contains new fields `changePending` and `valuePending`. Fields `total` and `pending` are
|
||||
still provided. See more in the class documentation
|
||||
`sdk-lib/src/main/java/cash/z/ecc/android/sdk/model/WalletBalance.kt`
|
||||
- `Synchronizer.transparentBalances: WalletBalance` to `Synchronizer.transparentBalance: Zatoshi`
|
||||
- `WalletSnapshot.transparentBalance: WalletBalance` to `WalletSnapshot.transparentBalance: Zatoshi`
|
||||
|
||||
### Added
|
||||
- `WalletBalanceFixture` class with mock values that are supposed to be used only for testing purposes
|
||||
|
||||
## [2.0.6] - 2024-01-30
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -170,8 +170,6 @@ interface Backend {
|
|||
|
||||
suspend fun rewindBlockMetadataToHeight(height: Long)
|
||||
|
||||
suspend fun getVerifiedTransparentBalance(address: String): Long
|
||||
|
||||
suspend fun getTotalTransparentBalance(address: String): Long
|
||||
|
||||
/**
|
||||
|
|
|
@ -161,15 +161,6 @@ class RustBackend private constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun getVerifiedTransparentBalance(address: String): Long =
|
||||
withContext(SdkDispatchers.DATABASE_IO) {
|
||||
getVerifiedTransparentBalance(
|
||||
dataDbFile.absolutePath,
|
||||
address,
|
||||
networkId = networkId
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getTotalTransparentBalance(address: String): Long =
|
||||
withContext(SdkDispatchers.DATABASE_IO) {
|
||||
getTotalTransparentBalance(
|
||||
|
@ -628,13 +619,6 @@ class RustBackend private constructor(
|
|||
networkId: Int
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
private external fun getVerifiedTransparentBalance(
|
||||
pathDataDb: String,
|
||||
taddr: String,
|
||||
networkId: Int
|
||||
): Long
|
||||
|
||||
@JvmStatic
|
||||
private external fun getTotalTransparentBalance(
|
||||
pathDataDb: String,
|
||||
|
|
|
@ -671,47 +671,6 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_isValidUn
|
|||
unwrap_exc_or(&mut env, res, JNI_FALSE)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getVerifiedTransparentBalance<
|
||||
'local,
|
||||
>(
|
||||
mut env: JNIEnv<'local>,
|
||||
_: JClass<'local>,
|
||||
db_data: JString<'local>,
|
||||
address: JString<'local>,
|
||||
network_id: jint,
|
||||
) -> jlong {
|
||||
let res = catch_unwind(&mut env, |env| {
|
||||
let _span = tracing::info_span!("RustBackend.getVerifiedTransparentBalance").entered();
|
||||
let network = parse_network(network_id as u32)?;
|
||||
let db_data = wallet_db(env, network, db_data)?;
|
||||
let addr = utils::java_string_to_rust(env, &address);
|
||||
let taddr = TransparentAddress::decode(&network, &addr).unwrap();
|
||||
|
||||
let amount = (&db_data)
|
||||
.get_target_and_anchor_heights(ANCHOR_OFFSET)
|
||||
.map_err(|e| format_err!("Error while fetching anchor height: {}", e))
|
||||
.and_then(|opt_anchor| {
|
||||
opt_anchor
|
||||
.map(|(_, a)| a)
|
||||
.ok_or(format_err!("Anchor height not available; scan required."))
|
||||
})
|
||||
.and_then(|anchor| {
|
||||
(&db_data)
|
||||
.get_unspent_transparent_outputs(&taddr, anchor, &[])
|
||||
.map_err(|e| format_err!("Error while fetching verified balance: {}", e))
|
||||
})?
|
||||
.iter()
|
||||
.map(|utxo| utxo.txout().value)
|
||||
.sum::<Option<NonNegativeAmount>>()
|
||||
.ok_or_else(|| format_err!("Balance overflowed MAX_MONEY."))?;
|
||||
|
||||
Ok(Amount::from(amount).into())
|
||||
});
|
||||
|
||||
unwrap_exc_or(&mut env, res, -1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_getTotalTransparentBalance<
|
||||
'local,
|
||||
|
|
|
@ -10,7 +10,6 @@ import cash.z.ecc.android.sdk.ext.Darkside
|
|||
import cash.z.ecc.android.sdk.internal.Twig
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||
|
@ -81,7 +80,7 @@ class TestWallet(
|
|||
val birthdayHeight get() = synchronizer.latestBirthdayHeight
|
||||
val networkName get() = synchronizer.network.networkName
|
||||
|
||||
suspend fun transparentBalance(): WalletBalance {
|
||||
suspend fun transparentBalance(): Zatoshi {
|
||||
synchronizer.refreshUtxos(account, synchronizer.latestBirthdayHeight)
|
||||
return synchronizer.getTransparentBalance(transparentAddress)
|
||||
}
|
||||
|
@ -121,7 +120,7 @@ class TestWallet(
|
|||
}
|
||||
|
||||
synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
|
||||
if (walletBalance.available.value > 0L) {
|
||||
if (walletBalance.value > 0L) {
|
||||
synchronizer.shieldFunds(shieldedSpendingKey)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
|||
launch {
|
||||
sharedViewModel.synchronizerFlow
|
||||
.filterNotNull()
|
||||
.flatMapLatest { it.transparentBalances }
|
||||
.flatMapLatest { it.transparentBalance }
|
||||
.collect { onTransparentBalance(it) }
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun onTransparentBalance(transparentBalance: WalletBalance?) {
|
||||
private fun onTransparentBalance(transparentBalance: Zatoshi?) {
|
||||
binding.transparentBalance.apply {
|
||||
text = transparentBalance.humanString()
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
|||
// TODO [#776]: Support variable fees
|
||||
// TODO [#776]: https://github.com/zcash/zcash-android-wallet-sdk/issues/776
|
||||
visibility =
|
||||
if ((transparentBalance?.available ?: Zatoshi(0)) > ZcashSdk.MINERS_FEE) {
|
||||
if ((transparentBalance ?: Zatoshi(0)) > ZcashSdk.MINERS_FEE) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
|
@ -160,7 +160,7 @@ class GetBalanceFragment : BaseDemoFragment<FragmentGetBalanceBinding>() {
|
|||
sharedViewModel.synchronizerFlow.value?.let { synchronizer ->
|
||||
onOrchardBalance(synchronizer.orchardBalances.value)
|
||||
onSaplingBalance(synchronizer.saplingBalances.value)
|
||||
onTransparentBalance(synchronizer.transparentBalances.value)
|
||||
onTransparentBalance(synchronizer.transparentBalance.value)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,3 +183,13 @@ private fun WalletBalance?.humanString() =
|
|||
Total balance: ${total.convertZatoshiToZecString(12)}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun Zatoshi?.humanString() =
|
||||
if (null == this) {
|
||||
"Calculating balance"
|
||||
} else {
|
||||
"""
|
||||
Balance: ${convertZatoshiToZecString(12)}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import cash.z.ecc.android.sdk.Synchronizer
|
|||
import cash.z.ecc.android.sdk.block.processor.CompactBlockProcessor
|
||||
import cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel.SynchronizerError
|
||||
import cash.z.ecc.android.sdk.demoapp.ui.screen.home.viewmodel.WalletSnapshot
|
||||
import cash.z.ecc.android.sdk.fixture.WalletBalanceFixture
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
@ -12,9 +13,9 @@ import cash.z.ecc.android.sdk.model.Zatoshi
|
|||
object WalletSnapshotFixture {
|
||||
val STATUS = Synchronizer.Status.SYNCED
|
||||
val PROGRESS = PercentDecimal.ZERO_PERCENT
|
||||
val TRANSPARENT_BALANCE: WalletBalance = WalletBalance(Zatoshi(8), Zatoshi(1))
|
||||
val ORCHARD_BALANCE: WalletBalance = WalletBalance(Zatoshi(5), Zatoshi(2))
|
||||
val SAPLING_BALANCE: WalletBalance = WalletBalance(Zatoshi(4), Zatoshi(4))
|
||||
val TRANSPARENT_BALANCE: Zatoshi = Zatoshi(8)
|
||||
val ORCHARD_BALANCE: WalletBalance = WalletBalanceFixture.new(Zatoshi(5), Zatoshi(2), Zatoshi(1))
|
||||
val SAPLING_BALANCE: WalletBalance = WalletBalanceFixture.new(Zatoshi(4), Zatoshi(4), Zatoshi(2))
|
||||
|
||||
// Should fill in with non-empty values for better example values in tests and UI previews
|
||||
@Suppress("LongParameterList")
|
||||
|
@ -28,7 +29,7 @@ object WalletSnapshotFixture {
|
|||
),
|
||||
orchardBalance: WalletBalance = ORCHARD_BALANCE,
|
||||
saplingBalance: WalletBalance = SAPLING_BALANCE,
|
||||
transparentBalance: WalletBalance = TRANSPARENT_BALANCE,
|
||||
transparentBalance: Zatoshi = TRANSPARENT_BALANCE,
|
||||
progress: PercentDecimal = PROGRESS,
|
||||
synchronizerError: SynchronizerError? = null
|
||||
) = WalletSnapshot(
|
||||
|
|
|
@ -148,20 +148,14 @@ private fun BalanceMainContent(
|
|||
Text(
|
||||
stringResource(
|
||||
id = R.string.balance_available_amount_format,
|
||||
walletSnapshot.transparentBalance.available.toZecString()
|
||||
)
|
||||
)
|
||||
Text(
|
||||
stringResource(
|
||||
id = R.string.balance_pending_amount_format,
|
||||
walletSnapshot.transparentBalance.pending.toZecString()
|
||||
walletSnapshot.transparentBalance.toZecString()
|
||||
)
|
||||
)
|
||||
|
||||
// TODO [#776]: Support variable fees
|
||||
// TODO [#776]: https://github.com/zcash/zcash-android-wallet-sdk/issues/776
|
||||
// This check will not be correct with variable fees
|
||||
if (walletSnapshot.transparentBalance.available > ZcashSdk.MINERS_FEE) {
|
||||
if (walletSnapshot.transparentBalance > ZcashSdk.MINERS_FEE) {
|
||||
// Note this implementation does not guard against multiple clicks
|
||||
Button(onClick = onShieldFunds) {
|
||||
Text(stringResource(id = R.string.action_shield))
|
||||
|
|
|
@ -12,7 +12,7 @@ data class WalletSnapshot(
|
|||
val processorInfo: CompactBlockProcessor.ProcessorInfo,
|
||||
val orchardBalance: WalletBalance,
|
||||
val saplingBalance: WalletBalance,
|
||||
val transparentBalance: WalletBalance,
|
||||
val transparentBalance: Zatoshi,
|
||||
val progress: PercentDecimal,
|
||||
val synchronizerError: SynchronizerError?
|
||||
) {
|
||||
|
@ -27,7 +27,7 @@ data class WalletSnapshot(
|
|||
val isSendEnabled: Boolean get() = status == Synchronizer.Status.SYNCED && hasFunds
|
||||
}
|
||||
|
||||
fun WalletSnapshot.totalBalance() = orchardBalance.total + saplingBalance.total + transparentBalance.total
|
||||
fun WalletSnapshot.totalBalance() = orchardBalance.total + saplingBalance.total + transparentBalance
|
||||
|
||||
// Note that considering both to be spendable is subject to change.
|
||||
// The user experience could be confusing, and in the future we might prefer to ask users
|
||||
|
|
|
@ -377,7 +377,7 @@ private fun Synchronizer.toWalletSnapshot() =
|
|||
// 3
|
||||
saplingBalances,
|
||||
// 4
|
||||
transparentBalances,
|
||||
transparentBalance,
|
||||
// 5
|
||||
progress,
|
||||
// 6
|
||||
|
@ -385,15 +385,15 @@ private fun Synchronizer.toWalletSnapshot() =
|
|||
) { flows ->
|
||||
val orchardBalance = flows[2] as WalletBalance?
|
||||
val saplingBalance = flows[3] as WalletBalance?
|
||||
val transparentBalance = flows[4] as WalletBalance?
|
||||
val transparentBalance = flows[4] as Zatoshi?
|
||||
val progressPercentDecimal = (flows[5] as PercentDecimal)
|
||||
|
||||
WalletSnapshot(
|
||||
flows[0] as Synchronizer.Status,
|
||||
flows[1] as CompactBlockProcessor.ProcessorInfo,
|
||||
orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
||||
saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
||||
transparentBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0)),
|
||||
orchardBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0), Zatoshi(0)),
|
||||
saplingBalance ?: WalletBalance(Zatoshi(0), Zatoshi(0), Zatoshi(0)),
|
||||
transparentBalance ?: Zatoshi(0),
|
||||
progressPercentDecimal,
|
||||
flows[6] as SynchronizerError?
|
||||
)
|
||||
|
|
|
@ -60,9 +60,9 @@ class TransparentRestoreSample {
|
|||
val address = wallet.transparentAddress
|
||||
|
||||
Assert.assertTrue(
|
||||
"Not enough funds to run sample. Expected some Zatoshi but found ${tbalance.available}. " +
|
||||
"Not enough funds to run sample. Expected some Zatoshi but found $tbalance. " +
|
||||
"Try adding funds to $address",
|
||||
tbalance.available.value > 0
|
||||
tbalance.value > 0
|
||||
)
|
||||
|
||||
// wallet.shieldFunds()
|
||||
|
|
|
@ -12,7 +12,6 @@ import cash.z.ecc.android.sdk.internal.deriveUnifiedSpendingKey
|
|||
import cash.z.ecc.android.sdk.internal.jni.RustDerivationTool
|
||||
import cash.z.ecc.android.sdk.model.Account
|
||||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import co.electriccoin.lightwallet.client.model.LightWalletEndpoint
|
||||
|
@ -82,7 +81,7 @@ class TestWallet(
|
|||
val birthdayHeight get() = synchronizer.latestBirthdayHeight
|
||||
val networkName get() = synchronizer.network.networkName
|
||||
|
||||
suspend fun transparentBalance(): WalletBalance {
|
||||
suspend fun transparentBalance(): Zatoshi {
|
||||
synchronizer.refreshUtxos(account, synchronizer.latestBirthdayHeight)
|
||||
return synchronizer.getTransparentBalance(transparentAddress)
|
||||
}
|
||||
|
@ -122,9 +121,9 @@ class TestWallet(
|
|||
}
|
||||
|
||||
synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
|
||||
Twig.debug { "FOUND utxo balance of total: ${walletBalance.total} available: ${walletBalance.available}" }
|
||||
Twig.debug { "FOUND utxo balance of total: $walletBalance" }
|
||||
|
||||
if (walletBalance.available.value > 0L) {
|
||||
if (walletBalance.value > 0L) {
|
||||
synchronizer.shieldFunds(spendingKey)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,10 +49,6 @@ internal class FakeRustBackend(
|
|||
|
||||
override suspend fun getLatestCacheHeight(): Long = metadata.maxOf { it.height }
|
||||
|
||||
override suspend fun getVerifiedTransparentBalance(address: String): Long {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun getTotalTransparentBalance(address: String): Long {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ import cash.z.ecc.android.sdk.model.PercentDecimal
|
|||
import cash.z.ecc.android.sdk.model.TransactionOverview
|
||||
import cash.z.ecc.android.sdk.model.TransactionRecipient
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import cash.z.ecc.android.sdk.type.AddressType
|
||||
|
@ -185,7 +184,7 @@ class SdkSynchronizer private constructor(
|
|||
|
||||
override val orchardBalances = processor.orchardBalances.asStateFlow()
|
||||
override val saplingBalances = processor.saplingBalances.asStateFlow()
|
||||
override val transparentBalances = processor.transparentBalances.asStateFlow()
|
||||
override val transparentBalance = processor.transparentBalance.asStateFlow()
|
||||
|
||||
override val transactions
|
||||
get() =
|
||||
|
@ -359,7 +358,7 @@ class SdkSynchronizer private constructor(
|
|||
|
||||
/**
|
||||
* Calculate the latest balance based on the blocks that have been scanned and transmit this information into the
|
||||
* [transparentBalances] and [saplingBalances] flow. The [orchardBalances] flow is still not filled with proper data
|
||||
* [transparentBalance] and [saplingBalances] flow. The [orchardBalances] flow is still not filled with proper data
|
||||
* because of the current limited Orchard support.
|
||||
*/
|
||||
suspend fun refreshAllBalances() {
|
||||
|
@ -587,7 +586,7 @@ class SdkSynchronizer private constructor(
|
|||
val encodedTx =
|
||||
txManager.encode(
|
||||
usk,
|
||||
tBalance.available,
|
||||
tBalance,
|
||||
TransactionRecipient.Account(usk.account),
|
||||
memo,
|
||||
usk.account
|
||||
|
@ -607,7 +606,7 @@ class SdkSynchronizer private constructor(
|
|||
return processor.refreshUtxos(account, since)
|
||||
}
|
||||
|
||||
override suspend fun getTransparentBalance(tAddr: String): WalletBalance {
|
||||
override suspend fun getTransparentBalance(tAddr: String): Zatoshi {
|
||||
return processor.getUtxoCacheBalance(tAddr)
|
||||
}
|
||||
|
||||
|
|
|
@ -69,19 +69,19 @@ interface Synchronizer {
|
|||
val networkHeight: StateFlow<BlockHeight?>
|
||||
|
||||
/**
|
||||
* A stream of balance values for the orchard pool. Includes the available and total balance.
|
||||
* A stream of balance values for the orchard pool.
|
||||
*/
|
||||
val orchardBalances: StateFlow<WalletBalance?>
|
||||
|
||||
/**
|
||||
* A stream of balance values for the sapling pool. Includes the available and total balance.
|
||||
* A stream of balance values for the sapling pool.
|
||||
*/
|
||||
val saplingBalances: StateFlow<WalletBalance?>
|
||||
|
||||
/**
|
||||
* A stream of balance values for the transparent pool. Includes the available and total balance.
|
||||
* A stream of a balance for the transparent pool.
|
||||
*/
|
||||
val transparentBalances: StateFlow<WalletBalance?>
|
||||
val transparentBalance: StateFlow<Zatoshi?>
|
||||
|
||||
/**
|
||||
* A flow of all the transactions that are on the blockchain.
|
||||
|
@ -273,7 +273,7 @@ interface Synchronizer {
|
|||
/**
|
||||
* Returns the balance that the wallet knows about. This should be called after [refreshUtxos].
|
||||
*/
|
||||
suspend fun getTransparentBalance(tAddr: String): WalletBalance
|
||||
suspend fun getTransparentBalance(tAddr: String): Zatoshi
|
||||
|
||||
/**
|
||||
* Returns the safest height to which we can rewind, given a desire to rewind to the height
|
||||
|
|
|
@ -49,6 +49,7 @@ import cash.z.ecc.android.sdk.model.Account
|
|||
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||
import cash.z.ecc.android.sdk.model.PercentDecimal
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import co.electriccoin.lightwallet.client.model.BlockHeightUnsafe
|
||||
import co.electriccoin.lightwallet.client.model.GetAddressUtxosReplyUnsafe
|
||||
|
@ -155,7 +156,7 @@ class CompactBlockProcessor internal constructor(
|
|||
// pools
|
||||
internal val saplingBalances = MutableStateFlow<WalletBalance?>(null)
|
||||
internal val orchardBalances = MutableStateFlow<WalletBalance?>(null)
|
||||
internal val transparentBalances = MutableStateFlow<WalletBalance?>(null)
|
||||
internal val transparentBalance = MutableStateFlow<Zatoshi?>(null)
|
||||
|
||||
private val processingMutex = Mutex()
|
||||
|
||||
|
@ -738,11 +739,7 @@ class CompactBlockProcessor internal constructor(
|
|||
// orchardBalances.value = it.orchard
|
||||
// We only allow stored transparent balance to be shielded, and we do so with
|
||||
// a zero-conf transaction, so treat all unshielded balance as available.
|
||||
transparentBalances.value =
|
||||
WalletBalance(
|
||||
it.unshielded,
|
||||
it.unshielded
|
||||
)
|
||||
transparentBalance.value = it.unshielded
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2148,7 +2145,7 @@ class CompactBlockProcessor internal constructor(
|
|||
} ?: lowerBoundHeight
|
||||
}
|
||||
|
||||
suspend fun getUtxoCacheBalance(address: String): WalletBalance = backend.getDownloadedUtxoBalance(address)
|
||||
suspend fun getUtxoCacheBalance(address: String): Zatoshi = backend.getDownloadedUtxoBalance(address)
|
||||
|
||||
/**
|
||||
* Sealed class representing the various states of this processor.
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package cash.z.ecc.android.sdk.fixture
|
||||
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
object WalletBalanceFixture {
|
||||
const val AVAILABLE: Long = 8L
|
||||
const val CHANGE_PENDING: Long = 4
|
||||
const val VALUE_PENDING: Long = 4
|
||||
|
||||
fun new(
|
||||
available: Zatoshi = Zatoshi(AVAILABLE),
|
||||
changePending: Zatoshi = Zatoshi(CHANGE_PENDING),
|
||||
valuePending: Zatoshi = Zatoshi(VALUE_PENDING)
|
||||
) = WalletBalance(
|
||||
available = available,
|
||||
changePending = changePending,
|
||||
valuePending = valuePending
|
||||
)
|
||||
|
||||
fun newLong(
|
||||
available: Long = AVAILABLE,
|
||||
changePending: Long = CHANGE_PENDING,
|
||||
valuePending: Long = VALUE_PENDING
|
||||
) = WalletBalance(
|
||||
available = Zatoshi(available),
|
||||
changePending = Zatoshi(changePending),
|
||||
valuePending = Zatoshi(valuePending)
|
||||
)
|
||||
}
|
|
@ -11,7 +11,7 @@ import cash.z.ecc.android.sdk.model.BlockHeight
|
|||
import cash.z.ecc.android.sdk.model.FirstClassByteArray
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
|
@ -58,7 +58,7 @@ internal interface TypesafeBackend {
|
|||
|
||||
suspend fun rewindBlockMetadataToHeight(height: BlockHeight)
|
||||
|
||||
suspend fun getDownloadedUtxoBalance(address: String): WalletBalance
|
||||
suspend fun getDownloadedUtxoBalance(address: String): Zatoshi
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
suspend fun putUtxo(
|
||||
|
|
|
@ -12,7 +12,6 @@ import cash.z.ecc.android.sdk.model.BlockHeight
|
|||
import cash.z.ecc.android.sdk.model.FirstClassByteArray
|
||||
import cash.z.ecc.android.sdk.model.Proposal
|
||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
||||
import cash.z.ecc.android.sdk.model.Zatoshi
|
||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -114,21 +113,12 @@ internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBacke
|
|||
backend.rewindBlockMetadataToHeight(height.value)
|
||||
}
|
||||
|
||||
override suspend fun getDownloadedUtxoBalance(address: String): WalletBalance {
|
||||
// Note this implementation is not ideal because it requires two database queries without a transaction, which
|
||||
// makes the data potentially inconsistent. However the verified amount is queried first which makes this less
|
||||
// bad.
|
||||
val verified =
|
||||
withContext(SdkDispatchers.DATABASE_IO) {
|
||||
backend.getVerifiedTransparentBalance(address)
|
||||
}
|
||||
override suspend fun getDownloadedUtxoBalance(address: String): Zatoshi {
|
||||
val total =
|
||||
withContext(SdkDispatchers.DATABASE_IO) {
|
||||
backend.getTotalTransparentBalance(
|
||||
address
|
||||
)
|
||||
backend.getTotalTransparentBalance(address)
|
||||
}
|
||||
return WalletBalance(Zatoshi(total), Zatoshi(verified))
|
||||
return Zatoshi(total)
|
||||
}
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
|
|
|
@ -13,13 +13,15 @@ internal data class AccountBalance(
|
|||
return AccountBalance(
|
||||
sapling =
|
||||
WalletBalance(
|
||||
Zatoshi(jni.saplingVerifiedBalance + jni.saplingChangePending + jni.saplingValuePending),
|
||||
Zatoshi(jni.saplingVerifiedBalance)
|
||||
available = Zatoshi(jni.saplingVerifiedBalance),
|
||||
changePending = Zatoshi(jni.saplingChangePending),
|
||||
valuePending = Zatoshi(jni.saplingValuePending)
|
||||
),
|
||||
orchard =
|
||||
WalletBalance(
|
||||
Zatoshi(jni.orchardVerifiedBalance + jni.orchardChangePending + jni.orchardValuePending),
|
||||
Zatoshi(jni.orchardVerifiedBalance)
|
||||
available = Zatoshi(jni.orchardVerifiedBalance),
|
||||
changePending = Zatoshi(jni.orchardChangePending),
|
||||
valuePending = Zatoshi(jni.orchardValuePending)
|
||||
),
|
||||
unshielded = Zatoshi(jni.unshieldedBalance)
|
||||
)
|
||||
|
|
|
@ -1,28 +1,30 @@
|
|||
package cash.z.ecc.android.sdk.model
|
||||
|
||||
/**
|
||||
* Data structure to hold the total and available balance of the wallet. This is what is
|
||||
* received on the balance channel.
|
||||
* Data structure to hold the balance of the wallet. This is what is received on the balance channel.
|
||||
*
|
||||
* @param total the total balance, ignoring funds that cannot be used.
|
||||
* @param available the amount of funds that are available for use. Typical reasons that funds
|
||||
* @param available The amount of funds that are available for use. Typical reasons that funds
|
||||
* may be unavailable include fairly new transactions that do not have enough confirmations or
|
||||
* notes that are tied up because we are awaiting change from a transaction. When a note has
|
||||
* been spent, its change cannot be used until there are enough confirmations.
|
||||
* @param changePending The value in the account of change notes that do not yet have sufficient confirmations to be
|
||||
* spendable.
|
||||
* @param valuePending The value in the account of all remaining received notes that either do not have sufficient
|
||||
* confirmations to be spendable, or for which witnesses cannot yet be constructed without additional scanning.
|
||||
*/
|
||||
data class WalletBalance(
|
||||
val total: Zatoshi,
|
||||
val available: Zatoshi
|
||||
val available: Zatoshi,
|
||||
val changePending: Zatoshi,
|
||||
val valuePending: Zatoshi
|
||||
) {
|
||||
init {
|
||||
require(total.value >= available.value) { "Wallet total balance must be >= available balance" }
|
||||
}
|
||||
/**
|
||||
* The current total balance is calculated as a sum of [available], [changePending],
|
||||
* and [valuePending].
|
||||
*/
|
||||
val total = available + changePending + valuePending
|
||||
|
||||
/**
|
||||
* The current pending balance is calculated as the difference between [total] and [available] balances.
|
||||
*/
|
||||
val pending = total - available
|
||||
|
||||
operator fun plus(other: WalletBalance): WalletBalance =
|
||||
WalletBalance(
|
||||
total + other.total,
|
||||
available + other.available
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue