zcash-android-wallet-sdk/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackendImpl.kt

204 lines
6.9 KiB
Kotlin

package cash.z.ecc.android.sdk.internal
import cash.z.ecc.android.sdk.internal.model.Checkpoint
import cash.z.ecc.android.sdk.internal.model.JniBlockMeta
import cash.z.ecc.android.sdk.internal.model.JniSubtreeRoot
import cash.z.ecc.android.sdk.internal.model.ScanRange
import cash.z.ecc.android.sdk.internal.model.SubtreeRoot
import cash.z.ecc.android.sdk.model.Account
import cash.z.ecc.android.sdk.model.BlockHeight
import cash.z.ecc.android.sdk.model.FirstClassByteArray
import cash.z.ecc.android.sdk.model.UnifiedFullViewingKey
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.tool.DerivationTool
import kotlinx.coroutines.withContext
@Suppress("TooManyFunctions")
internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBackend {
override val network: ZcashNetwork
get() = ZcashNetwork.from(backend.networkId)
override suspend fun initAccountsTable(vararg keys: UnifiedFullViewingKey) {
val ufvks = Array(keys.size) { keys[it].encoding }
@Suppress("SpreadOperator")
backend.initAccountsTable(*ufvks)
}
override suspend fun initAccountsTable(
seed: ByteArray,
numberOfAccounts: Int
): List<UnifiedFullViewingKey> {
return DerivationTool.getInstance().deriveUnifiedFullViewingKeys(seed, network, numberOfAccounts)
}
override suspend fun initBlocksTable(checkpoint: Checkpoint) {
backend.initBlocksTable(
checkpoint.height.value,
checkpoint.hash,
checkpoint.epochSeconds,
checkpoint.tree
)
}
override suspend fun createAccountAndGetSpendingKey(seed: ByteArray): UnifiedSpendingKey {
return UnifiedSpendingKey(backend.createAccount(seed))
}
@Suppress("LongParameterList")
override suspend fun createToAddress(
usk: UnifiedSpendingKey,
to: String,
value: Long,
memo: ByteArray?
): FirstClassByteArray = FirstClassByteArray(
backend.createToAddress(
usk.account.value,
usk.copyBytes(),
to,
value,
memo
)
)
override suspend fun shieldToAddress(
usk: UnifiedSpendingKey,
memo: ByteArray?
): FirstClassByteArray = FirstClassByteArray(
backend.shieldToAddress(
usk.account.value,
usk.copyBytes(),
memo
)
)
override suspend fun getCurrentAddress(account: Account): String {
return backend.getCurrentAddress(account.value)
}
override suspend fun listTransparentReceivers(account: Account): List<String> {
return backend.listTransparentReceivers(account.value)
}
override suspend fun getBalance(account: Account): Zatoshi {
return Zatoshi(backend.getBalance(account.value))
}
override fun getBranchIdForHeight(height: BlockHeight): Long {
return backend.getBranchIdForHeight(height.value)
}
override suspend fun getVerifiedBalance(account: Account): Zatoshi {
return Zatoshi(backend.getVerifiedBalance(account.value))
}
override suspend fun getNearestRewindHeight(height: BlockHeight): BlockHeight {
return BlockHeight.new(
ZcashNetwork.from(backend.networkId),
backend.getNearestRewindHeight(height.value)
)
}
override suspend fun rewindToHeight(height: BlockHeight) {
backend.rewindToHeight(height.value)
}
override suspend fun getLatestBlockHeight(): BlockHeight? {
return backend.getLatestHeight()?.let {
BlockHeight.new(
ZcashNetwork.from(backend.networkId),
it
)
}
}
override suspend fun findBlockMetadata(height: BlockHeight): JniBlockMeta? {
return backend.findBlockMetadata(height.value)
}
override suspend fun rewindBlockMetadataToHeight(height: BlockHeight) {
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)
}
val total = withContext(SdkDispatchers.DATABASE_IO) {
backend.getTotalTransparentBalance(
address
)
}
return WalletBalance(Zatoshi(total), Zatoshi(verified))
}
@Suppress("LongParameterList")
override suspend fun putUtxo(
tAddress: String,
txId: ByteArray,
index: Int,
script: ByteArray,
value: Long,
height: BlockHeight
) {
return backend.putUtxo(
tAddress,
txId,
index,
script,
value,
height.value
)
}
override suspend fun getMemoAsUtf8(txId: ByteArray, outputIndex: Int): String? =
backend.getMemoAsUtf8(txId, outputIndex)
override suspend fun initDataDb(seed: ByteArray?): Int = backend.initDataDb(seed)
override suspend fun putSaplingSubtreeRoots(startIndex: Long, roots: List<SubtreeRoot>) =
backend.putSaplingSubtreeRoots(
startIndex = startIndex,
roots = roots.map {
JniSubtreeRoot.new(
rootHash = it.rootHash,
completingBlockHeight = it.completingBlockHeight.value
)
}
)
override suspend fun updateChainTip(height: BlockHeight) = backend.updateChainTip(height.value)
override suspend fun scanBlocks(fromHeight: BlockHeight, limit: Long) = backend.scanBlocks(fromHeight.value, limit)
override suspend fun suggestScanRanges(): List<ScanRange> = backend.suggestScanRanges().map { jniScanRange ->
ScanRange.new(
jniScanRange,
network
)
}
override suspend fun decryptAndStoreTransaction(tx: ByteArray) = backend.decryptAndStoreTransaction(tx)
override fun getSaplingReceiver(ua: String): String? = backend.getSaplingReceiver(ua)
override fun getTransparentReceiver(ua: String): String? = backend.getTransparentReceiver(ua)
override suspend fun initBlockMetaDb(): Int = backend.initBlockMetaDb()
override suspend fun writeBlockMetadata(blockMetadata: List<JniBlockMeta>) =
backend.writeBlockMetadata(blockMetadata)
override fun isValidShieldedAddr(addr: String): Boolean = backend.isValidShieldedAddr(addr)
override fun isValidTransparentAddr(addr: String): Boolean = backend.isValidTransparentAddr(addr)
override fun isValidUnifiedAddr(addr: String): Boolean = backend.isValidUnifiedAddr(addr)
}