[#477] Fixes for Zatoshi object

This commit is contained in:
Carter Jernigan 2022-07-07 08:52:07 -04:00 committed by Carter Jernigan
parent 1ac72feae3
commit a1cc8f0b69
17 changed files with 60 additions and 52 deletions

View File

@ -7,6 +7,8 @@ Various APIs used `Long` value to represent Zatoshi currency amounts. Those API
`WalletBalance` no longer has uninitialized default values. This means that `Synchronizer` fields that expose a WalletBalance now use `null` to signal an uninitialized value. Specifically this means `Synchronizer.orchardBalances`, `Synchronzier.saplingBalances`, and `Synchronizer.transparentBalances` have nullable values now. `WalletBalance` no longer has uninitialized default values. This means that `Synchronizer` fields that expose a WalletBalance now use `null` to signal an uninitialized value. Specifically this means `Synchronizer.orchardBalances`, `Synchronzier.saplingBalances`, and `Synchronizer.transparentBalances` have nullable values now.
`WalletBalance` has been moved from the package `cash.z.ecc.android.sdk.type` to `cash.z.ecc.android.sdk.model`
`ZcashSdk.ZATOSHI_PER_ZEC` has been moved to `Zatoshi.ZATOSHI_PER_ZEC`. `ZcashSdk.ZATOSHI_PER_ZEC` has been moved to `Zatoshi.ZATOSHI_PER_ZEC`.
`ZcashSdk.MINERS_FEE_ZATOSHI` has been renamed to `ZcashSdk.MINERS_FEE` and the type has changed from `Long` to `Zatoshi`. `ZcashSdk.MINERS_FEE_ZATOSHI` has been renamed to `ZcashSdk.MINERS_FEE` and the type has changed from `Long` to `Zatoshi`.

View File

@ -10,9 +10,9 @@ import cash.z.ecc.android.sdk.db.entity.isPending
import cash.z.ecc.android.sdk.internal.Twig import cash.z.ecc.android.sdk.internal.Twig
import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService
import cash.z.ecc.android.sdk.internal.twig import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob

View File

@ -14,8 +14,8 @@ import cash.z.ecc.android.sdk.demoapp.ext.requireApplicationContext
import cash.z.ecc.android.sdk.demoapp.util.fromResources import cash.z.ecc.android.sdk.demoapp.util.fromResources
import cash.z.ecc.android.sdk.ext.collectWith import cash.z.ecc.android.sdk.ext.collectWith
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking

View File

@ -29,8 +29,8 @@ import cash.z.ecc.android.sdk.ext.convertZecToZatoshi
import cash.z.ecc.android.sdk.ext.toZecString import cash.z.ecc.android.sdk.ext.toZecString
import cash.z.ecc.android.sdk.internal.Twig import cash.z.ecc.android.sdk.internal.Twig
import cash.z.ecc.android.sdk.internal.twig import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking

View File

@ -10,9 +10,9 @@ import cash.z.ecc.android.sdk.db.entity.isPending
import cash.z.ecc.android.sdk.internal.Twig import cash.z.ecc.android.sdk.internal.Twig
import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService
import cash.z.ecc.android.sdk.internal.twig import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob

View File

@ -46,13 +46,13 @@ import cash.z.ecc.android.sdk.internal.transaction.TransactionRepository
import cash.z.ecc.android.sdk.internal.transaction.WalletTransactionEncoder import cash.z.ecc.android.sdk.internal.transaction.WalletTransactionEncoder
import cash.z.ecc.android.sdk.internal.twig import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.internal.twigTask import cash.z.ecc.android.sdk.internal.twigTask
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.AddressType import cash.z.ecc.android.sdk.type.AddressType
import cash.z.ecc.android.sdk.type.AddressType.Shielded import cash.z.ecc.android.sdk.type.AddressType.Shielded
import cash.z.ecc.android.sdk.type.AddressType.Transparent import cash.z.ecc.android.sdk.type.AddressType.Transparent
import cash.z.ecc.android.sdk.type.ConsensusMatchType import cash.z.ecc.android.sdk.type.ConsensusMatchType
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import cash.z.wallet.sdk.rpc.Service import cash.z.wallet.sdk.rpc.Service
import io.grpc.ManagedChannel import io.grpc.ManagedChannel

View File

@ -4,10 +4,10 @@ import cash.z.ecc.android.sdk.block.CompactBlockProcessor
import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction import cash.z.ecc.android.sdk.db.entity.ConfirmedTransaction
import cash.z.ecc.android.sdk.db.entity.PendingTransaction import cash.z.ecc.android.sdk.db.entity.PendingTransaction
import cash.z.ecc.android.sdk.ext.ZcashSdk import cash.z.ecc.android.sdk.ext.ZcashSdk
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.type.AddressType import cash.z.ecc.android.sdk.type.AddressType
import cash.z.ecc.android.sdk.type.ConsensusMatchType import cash.z.ecc.android.sdk.type.ConsensusMatchType
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import cash.z.wallet.sdk.rpc.Service import cash.z.wallet.sdk.rpc.Service
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View File

@ -39,7 +39,7 @@ import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.internal.twigTask import cash.z.ecc.android.sdk.internal.twigTask
import cash.z.ecc.android.sdk.jni.RustBackend import cash.z.ecc.android.sdk.jni.RustBackend
import cash.z.ecc.android.sdk.jni.RustBackendWelding import cash.z.ecc.android.sdk.jni.RustBackendWelding
import cash.z.ecc.android.sdk.type.WalletBalance import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.wallet.sdk.rpc.Service import cash.z.wallet.sdk.rpc.Service
import io.grpc.StatusRuntimeException import io.grpc.StatusRuntimeException
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

View File

@ -96,6 +96,10 @@ data class PendingTransactionEntity(
@ColumnInfo(typeAffinity = ColumnInfo.BLOB) @ColumnInfo(typeAffinity = ColumnInfo.BLOB)
override val rawTransactionId: ByteArray? = byteArrayOf() override val rawTransactionId: ByteArray? = byteArrayOf()
) : PendingTransaction { ) : PendingTransaction {
val valueZatoshi: Zatoshi
get() = Zatoshi(value)
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is PendingTransactionEntity) return false if (other !is PendingTransactionEntity) return false

View File

@ -115,7 +115,7 @@ class PersistentTransactionManager(
twig("beginning to encode transaction with : $encoder") twig("beginning to encode transaction with : $encoder")
val encodedTx = encoder.createTransaction( val encodedTx = encoder.createTransaction(
spendingKey, spendingKey,
tx.value, tx.valueZatoshi,
tx.toAddress, tx.toAddress,
tx.memo, tx.memo,
tx.accountIndex tx.accountIndex

View File

@ -1,6 +1,7 @@
package cash.z.ecc.android.sdk.internal.transaction package cash.z.ecc.android.sdk.internal.transaction
import cash.z.ecc.android.sdk.db.entity.EncodedTransaction import cash.z.ecc.android.sdk.db.entity.EncodedTransaction
import cash.z.ecc.android.sdk.model.Zatoshi
interface TransactionEncoder { interface TransactionEncoder {
/** /**
@ -18,7 +19,7 @@ interface TransactionEncoder {
*/ */
suspend fun createTransaction( suspend fun createTransaction(
spendingKey: String, spendingKey: String,
zatoshi: Long, amount: Zatoshi,
toAddress: String, toAddress: String,
memo: ByteArray? = byteArrayOf(), memo: ByteArray? = byteArrayOf(),
fromAccountIndex: Int = 0 fromAccountIndex: Int = 0

View File

@ -8,6 +8,7 @@ import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.internal.twigTask import cash.z.ecc.android.sdk.internal.twigTask
import cash.z.ecc.android.sdk.jni.RustBackend import cash.z.ecc.android.sdk.jni.RustBackend
import cash.z.ecc.android.sdk.jni.RustBackendWelding import cash.z.ecc.android.sdk.jni.RustBackendWelding
import cash.z.ecc.android.sdk.model.Zatoshi
/** /**
* Class responsible for encoding a transaction in a consistent way. This bridges the gap by * Class responsible for encoding a transaction in a consistent way. This bridges the gap by
@ -18,7 +19,7 @@ import cash.z.ecc.android.sdk.jni.RustBackendWelding
* @property repository the repository that stores information about the transactions being created * @property repository the repository that stores information about the transactions being created
* such as the raw bytes and raw txId. * such as the raw bytes and raw txId.
*/ */
class WalletTransactionEncoder( internal class WalletTransactionEncoder(
private val rustBackend: RustBackendWelding, private val rustBackend: RustBackendWelding,
private val repository: TransactionRepository private val repository: TransactionRepository
) : TransactionEncoder { ) : TransactionEncoder {
@ -29,7 +30,7 @@ class WalletTransactionEncoder(
* exception ourselves (rather than using double-bangs for things). * exception ourselves (rather than using double-bangs for things).
* *
* @param spendingKey the key associated with the notes that will be spent. * @param spendingKey the key associated with the notes that will be spent.
* @param zatoshi the amount of zatoshi to send. * @param amount the amount of zatoshi to send.
* @param toAddress the recipient's address. * @param toAddress the recipient's address.
* @param memo the optional memo to include as part of the transaction. * @param memo the optional memo to include as part of the transaction.
* @param fromAccountIndex the optional account id to use. By default, the 1st account is used. * @param fromAccountIndex the optional account id to use. By default, the 1st account is used.
@ -38,12 +39,12 @@ class WalletTransactionEncoder(
*/ */
override suspend fun createTransaction( override suspend fun createTransaction(
spendingKey: String, spendingKey: String,
zatoshi: Long, amount: Zatoshi,
toAddress: String, toAddress: String,
memo: ByteArray?, memo: ByteArray?,
fromAccountIndex: Int fromAccountIndex: Int
): EncodedTransaction { ): EncodedTransaction {
val transactionId = createSpend(spendingKey, zatoshi, toAddress, memo) val transactionId = createSpend(spendingKey, amount, toAddress, memo)
return repository.findEncodedTransactionById(transactionId) return repository.findEncodedTransactionById(transactionId)
?: throw TransactionEncoderException.TransactionNotFoundException(transactionId) ?: throw TransactionEncoderException.TransactionNotFoundException(transactionId)
} }
@ -93,7 +94,7 @@ class WalletTransactionEncoder(
* the result in the database. On average, this call takes over 10 seconds. * the result in the database. On average, this call takes over 10 seconds.
* *
* @param spendingKey the key associated with the notes that will be spent. * @param spendingKey the key associated with the notes that will be spent.
* @param zatoshi the amount of zatoshi to send. * @param amount the amount of zatoshi to send.
* @param toAddress the recipient's address. * @param toAddress the recipient's address.
* @param memo the optional memo to include as part of the transaction. * @param memo the optional memo to include as part of the transaction.
* @param fromAccountIndex the optional account id to use. By default, the 1st account is used. * @param fromAccountIndex the optional account id to use. By default, the 1st account is used.
@ -103,13 +104,13 @@ class WalletTransactionEncoder(
*/ */
private suspend fun createSpend( private suspend fun createSpend(
spendingKey: String, spendingKey: String,
zatoshi: Long, amount: Zatoshi,
toAddress: String, toAddress: String,
memo: ByteArray? = byteArrayOf(), memo: ByteArray? = byteArrayOf(),
fromAccountIndex: Int = 0 fromAccountIndex: Int = 0
): Long { ): Long {
return twigTask( return twigTask(
"creating transaction to spend $zatoshi zatoshi to" + "creating transaction to spend $amount zatoshi to" +
" ${toAddress.masked()} with memo $memo" " ${toAddress.masked()} with memo $memo"
) { ) {
try { try {
@ -121,7 +122,7 @@ class WalletTransactionEncoder(
fromAccountIndex, fromAccountIndex,
spendingKey, spendingKey,
toAddress, toAddress,
zatoshi, amount.value,
memo memo
) )
} catch (t: Throwable) { } catch (t: Throwable) {

View File

@ -6,10 +6,10 @@ import cash.z.ecc.android.sdk.ext.ZcashSdk.SPEND_PARAM_FILE_NAME
import cash.z.ecc.android.sdk.internal.SdkDispatchers import cash.z.ecc.android.sdk.internal.SdkDispatchers
import cash.z.ecc.android.sdk.internal.ext.deleteSuspend import cash.z.ecc.android.sdk.internal.ext.deleteSuspend
import cash.z.ecc.android.sdk.internal.twig import cash.z.ecc.android.sdk.internal.twig
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.tool.DerivationTool import cash.z.ecc.android.sdk.tool.DerivationTool
import cash.z.ecc.android.sdk.type.UnifiedViewingKey import cash.z.ecc.android.sdk.type.UnifiedViewingKey
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File

View File

@ -1,8 +1,8 @@
package cash.z.ecc.android.sdk.jni package cash.z.ecc.android.sdk.jni
import cash.z.ecc.android.sdk.model.WalletBalance
import cash.z.ecc.android.sdk.model.Zatoshi import cash.z.ecc.android.sdk.model.Zatoshi
import cash.z.ecc.android.sdk.type.UnifiedViewingKey import cash.z.ecc.android.sdk.type.UnifiedViewingKey
import cash.z.ecc.android.sdk.type.WalletBalance
import cash.z.ecc.android.sdk.type.ZcashNetwork import cash.z.ecc.android.sdk.type.ZcashNetwork
/** /**

View File

@ -0,0 +1,28 @@
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.
*
* @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
* 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.
*/
data class WalletBalance(
val total: Zatoshi,
val available: Zatoshi
) {
init {
require(total.value >= available.value) { "Wallet total balance must be >= available balance" }
}
val pending = total - available
operator fun plus(other: WalletBalance): WalletBalance =
WalletBalance(
total + other.total,
available + other.available
)
}

View File

@ -1,34 +1,5 @@
package cash.z.ecc.android.sdk.type package cash.z.ecc.android.sdk.type
import cash.z.ecc.android.sdk.model.Zatoshi
/**
* Data structure to hold the total and available 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
* 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.
*/
data class WalletBalance(
val total: Zatoshi,
val available: Zatoshi
) {
init {
require(total.value >= available.value) { "Wallet total balance must be >= available balance" }
}
val pending = total - available
operator fun plus(other: WalletBalance): WalletBalance =
WalletBalance(
total + other.total,
available + other.available
)
}
/** /**
* Model object for holding a wallet birthday. * Model object for holding a wallet birthday.
* *

View File

@ -1,5 +1,6 @@
package cash.z.ecc.android.sdk.ext package cash.z.ecc.android.sdk.ext
import cash.z.ecc.android.sdk.model.Zatoshi
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import java.math.BigDecimal import java.math.BigDecimal
@ -9,7 +10,7 @@ internal class ConversionsTest {
@Test @Test
fun `default right padding is 6`() { fun `default right padding is 6`() {
assertEquals(1.13.toZec(6), 113000000L.convertZatoshiToZec()) assertEquals(1.13.toZec(6), Zatoshi(113000000L).convertZatoshiToZec())
assertEquals(1.13.toZec(6), 1.13.toZec()) assertEquals(1.13.toZec(6), 1.13.toZec())
} }
@ -21,12 +22,12 @@ internal class ConversionsTest {
@Test @Test
fun `toZecString defaults to 6 digits`() { fun `toZecString defaults to 6 digits`() {
assertEquals("1.123457", 112345678L.convertZatoshiToZecString()) assertEquals("1.123457", Zatoshi(112345678L).convertZatoshiToZecString())
} }
@Test @Test
fun `toZecString uses banker's rounding`() { fun `toZecString uses banker's rounding`() {
assertEquals("1.123456", 112345650L.convertZatoshiToZecString()) assertEquals("1.123456", Zatoshi(112345650L).convertZatoshiToZecString())
} }
@Test @Test
@ -72,7 +73,7 @@ internal class ConversionsTest {
@Test @Test
fun `toZecString zatoshi converts`() { fun `toZecString zatoshi converts`() {
assertEquals("1.123456", 112345650L.convertZatoshiToZecString(6, 0)) assertEquals("1.123456", Zatoshi(112345650L).convertZatoshiToZecString(6, 0))
} }
@Test @Test