[#325] Migrate to SDK with BlockHeight AP
SDK 1.8 is not released yet, so this consumes a snapshot of the SDK 1.8 release.
This commit is contained in:
parent
48d86b23ae
commit
acd0012919
|
@ -1,6 +1,7 @@
|
||||||
package cash.z.ecc.android.feedback
|
package cash.z.ecc.android.feedback
|
||||||
|
|
||||||
import cash.z.ecc.android.ZcashWalletApp
|
import cash.z.ecc.android.ZcashWalletApp
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
|
|
||||||
object Report {
|
object Report {
|
||||||
|
|
||||||
|
@ -56,7 +57,7 @@ object Report {
|
||||||
|
|
||||||
object Error {
|
object Error {
|
||||||
object NonFatal {
|
object NonFatal {
|
||||||
class Reorg(errorBlockHeight: Int, rewindBlockHeight: Int) : Feedback.AppError(
|
class Reorg(errorBlockHeight: BlockHeight, rewindBlockHeight: BlockHeight) : Feedback.AppError(
|
||||||
"reorg",
|
"reorg",
|
||||||
"Chain error detected at height $errorBlockHeight, rewinding to $rewindBlockHeight",
|
"Chain error detected at height $errorBlockHeight, rewinding to $rewindBlockHeight",
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -78,6 +78,7 @@ import cash.z.ecc.android.sdk.exception.CompactBlockProcessorException
|
||||||
import cash.z.ecc.android.sdk.ext.BatchMetrics
|
import cash.z.ecc.android.sdk.ext.BatchMetrics
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
|
import cash.z.ecc.android.sdk.ext.toAbbreviatedAddress
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.ui.history.HistoryViewModel
|
import cash.z.ecc.android.ui.history.HistoryViewModel
|
||||||
import cash.z.ecc.android.ui.util.MemoUtil
|
import cash.z.ecc.android.ui.util.MemoUtil
|
||||||
import cash.z.ecc.android.util.twig
|
import cash.z.ecc.android.util.twig
|
||||||
|
@ -122,7 +123,7 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
|
||||||
Manifest.permission.CAMERA
|
Manifest.permission.CAMERA
|
||||||
) == PackageManager.PERMISSION_GRANTED
|
) == PackageManager.PERMISSION_GRANTED
|
||||||
|
|
||||||
val latestHeight: Int? get() = if (isInitialized) {
|
val latestHeight: BlockHeight? get() = if (isInitialized) {
|
||||||
synchronizerComponent.synchronizer().latestHeight
|
synchronizerComponent.synchronizer().latestHeight
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
@ -278,7 +279,7 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
|
||||||
if (isComplete) {
|
if (isComplete) {
|
||||||
if (batchMetrics.cumulativeItems > reportingThreshold) {
|
if (batchMetrics.cumulativeItems > reportingThreshold) {
|
||||||
val network = synchronizerComponent.synchronizer().network.networkName
|
val network = synchronizerComponent.synchronizer().network.networkName
|
||||||
reportAction(Report.Performance.ScanRate(network, batchMetrics.cumulativeItems, batchMetrics.cumulativeTime, batchMetrics.cumulativeIps))
|
reportAction(Report.Performance.ScanRate(network, batchMetrics.cumulativeItems.toInt(), batchMetrics.cumulativeTime, batchMetrics.cumulativeIps))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,7 +585,7 @@ class MainActivity : AppCompatActivity(R.layout.main_activity) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onChainError(errorHeight: Int, rewindHeight: Int) {
|
private fun onChainError(errorHeight: BlockHeight, rewindHeight: BlockHeight) {
|
||||||
feedback.report(Reorg(errorHeight, rewindHeight))
|
feedback.report(Reorg(errorHeight, rewindHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ class HistoryViewModel @Inject constructor() : ViewModel() {
|
||||||
tx != null && tx.toAddress.isNullOrEmpty() && tx.value > 0L && tx.minedHeight > 0 -> true
|
tx != null && tx.toAddress.isNullOrEmpty() && tx.value > 0L && tx.minedHeight > 0 -> true
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
isMined = tx?.minedHeight != null && tx.minedHeight > synchronizer.network.saplingActivationHeight
|
isMined = tx?.minedHeight != null && tx.minedHeight > synchronizer.network.saplingActivationHeight.value
|
||||||
topValue = if (tx == null) "" else "\$${WalletZecFormmatter.toZecStringFull(tx.valueInZatoshi)}"
|
topValue = if (tx == null) "" else "\$${WalletZecFormmatter.toZecStringFull(tx.valueInZatoshi)}"
|
||||||
minedHeight = String.format("%,d", tx?.minedHeight ?: 0)
|
minedHeight = String.format("%,d", tx?.minedHeight ?: 0)
|
||||||
val flags =
|
val flags =
|
||||||
|
@ -102,7 +102,7 @@ class HistoryViewModel @Inject constructor() : ViewModel() {
|
||||||
tx?.let {
|
tx?.let {
|
||||||
val isMined = it.blockTimeInSeconds != 0L
|
val isMined = it.blockTimeInSeconds != 0L
|
||||||
if (isMined) {
|
if (isMined) {
|
||||||
val hasLatestHeight = latestHeight != null && latestHeight > synchronizer.network.saplingActivationHeight
|
val hasLatestHeight = latestHeight != null && latestHeight > synchronizer.network.saplingActivationHeight.value
|
||||||
if (it.minedHeight > 0 && hasLatestHeight) {
|
if (it.minedHeight > 0 && hasLatestHeight) {
|
||||||
val confirmations = latestHeight!! - it.minedHeight + 1
|
val confirmations = latestHeight!! - it.minedHeight + 1
|
||||||
confirmation = if (confirmations >= 10) getString(R.string.transaction_status_confirmed) else "$confirmations ${getString(
|
confirmation = if (confirmations >= 10) getString(R.string.transaction_status_confirmed) else "$confirmations ${getString(
|
||||||
|
@ -165,7 +165,7 @@ class HistoryViewModel @Inject constructor() : ViewModel() {
|
||||||
private fun isSufficientlyOld(tx: ConfirmedTransaction): Boolean {
|
private fun isSufficientlyOld(tx: ConfirmedTransaction): Boolean {
|
||||||
val threshold = 75 * 1000 * 25 // approx 25 blocks
|
val threshold = 75 * 1000 * 25 // approx 25 blocks
|
||||||
val delta = System.currentTimeMillis() / 1000L - tx.blockTimeInSeconds
|
val delta = System.currentTimeMillis() / 1000L - tx.blockTimeInSeconds
|
||||||
return tx.minedHeight > synchronizer.network.saplingActivationHeight &&
|
return tx.minedHeight > synchronizer.network.saplingActivationHeight.value &&
|
||||||
delta < threshold
|
delta < threshold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ class TransactionViewHolder<T : ConfirmedTransaction>(itemView: View) : Recycler
|
||||||
R.string.transaction_status_pending
|
R.string.transaction_status_pending
|
||||||
)
|
)
|
||||||
// TODO: this logic works but is sloppy. Find a more robust solution to displaying information about expiration (such as expires in 1 block, etc). Then if it is way beyond expired, remove it entirely. Perhaps give the user a button for that (swipe to dismiss?)
|
// TODO: this logic works but is sloppy. Find a more robust solution to displaying information about expiration (such as expires in 1 block, etc). Then if it is way beyond expired, remove it entirely. Perhaps give the user a button for that (swipe to dismiss?)
|
||||||
if (!isMined && (expiryHeight != null) && (expiryHeight!! < mainActivity.latestHeight ?: -1)) lineTwo =
|
if (!isMined && (expiryHeight != null) && (expiryHeight!! < mainActivity.latestHeight?.value ?: -1)) lineTwo =
|
||||||
str(R.string.transaction_status_expired)
|
str(R.string.transaction_status_expired)
|
||||||
amountDisplay = "- $amountZec"
|
amountDisplay = "- $amountZec"
|
||||||
if (isMined) {
|
if (isMined) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import cash.z.ecc.android.ext.toAppColor
|
||||||
import cash.z.ecc.android.ext.toSplitColorSpan
|
import cash.z.ecc.android.ext.toSplitColorSpan
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.RECEIVE_BACK
|
import cash.z.ecc.android.feedback.Report.Tap.RECEIVE_BACK
|
||||||
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.ui.base.BaseFragment
|
import cash.z.ecc.android.ui.base.BaseFragment
|
||||||
import cash.z.ecc.android.ui.home.BalanceDetailViewModel.StatusModel
|
import cash.z.ecc.android.ui.home.BalanceDetailViewModel.StatusModel
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
@ -26,7 +27,7 @@ import kotlinx.coroutines.launch
|
||||||
class BalanceDetailFragment : BaseFragment<FragmentBalanceDetailBinding>() {
|
class BalanceDetailFragment : BaseFragment<FragmentBalanceDetailBinding>() {
|
||||||
|
|
||||||
private val viewModel: BalanceDetailViewModel by viewModel()
|
private val viewModel: BalanceDetailViewModel by viewModel()
|
||||||
private var lastSignal = -1
|
private var lastSignal: BlockHeight? = null
|
||||||
|
|
||||||
override fun inflate(inflater: LayoutInflater): FragmentBalanceDetailBinding =
|
override fun inflate(inflater: LayoutInflater): FragmentBalanceDetailBinding =
|
||||||
FragmentBalanceDetailBinding.inflate(inflater)
|
FragmentBalanceDetailBinding.inflate(inflater)
|
||||||
|
@ -127,7 +128,7 @@ class BalanceDetailFragment : BaseFragment<FragmentBalanceDetailBinding>() {
|
||||||
binding.textBlockHeight.text = String.format("%,d", status.info.lastScannedHeight) + " of " + String.format("%,d", status.info.networkBlockHeight)
|
binding.textBlockHeight.text = String.format("%,d", status.info.lastScannedHeight) + " of " + String.format("%,d", status.info.networkBlockHeight)
|
||||||
} else {
|
} else {
|
||||||
status.info.lastScannedHeight.let { height ->
|
status.info.lastScannedHeight.let { height ->
|
||||||
if (height < 1) {
|
if (height == null) {
|
||||||
binding.textBlockHeightPrefix.text = "Processing..."
|
binding.textBlockHeightPrefix.text = "Processing..."
|
||||||
binding.textBlockHeight.text = ""
|
binding.textBlockHeight.text = ""
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,9 +146,9 @@ class BalanceDetailFragment : BaseFragment<FragmentBalanceDetailBinding>() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendNewBlockSignal(currentHeight: Int) {
|
private fun sendNewBlockSignal(currentHeight: BlockHeight?) {
|
||||||
// prevent a flood of signals while scanning blocks
|
// prevent a flood of signals while scanning blocks
|
||||||
if (lastSignal != -1 && currentHeight > lastSignal) {
|
if (lastSignal != null && (currentHeight?.value ?: 0) > lastSignal!!.value) {
|
||||||
mainActivity?.vibrate(0, 100, 100, 300)
|
mainActivity?.vibrate(0, 100, 100, 300)
|
||||||
Toast.makeText(mainActivity, "New block!", Toast.LENGTH_SHORT).show()
|
Toast.makeText(mainActivity, "New block!", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
@ -199,7 +200,7 @@ class BalanceDetailFragment : BaseFragment<FragmentBalanceDetailBinding>() {
|
||||||
if (status.contains("Awaiting")) status += " and "
|
if (status.contains("Awaiting")) status += " and "
|
||||||
status += "$count outbound ${"transaction".plural(count)}"
|
status += "$count outbound ${"transaction".plural(count)}"
|
||||||
remainingConfirmations().firstOrNull()?.let { remaining ->
|
remainingConfirmations().firstOrNull()?.let { remaining ->
|
||||||
status += " with $remaining ${"confirmation".plural(remaining)} remaining"
|
status += " with $remaining ${"confirmation".plural(remaining.toInt())} remaining"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import cash.z.ecc.android.sdk.db.entity.isMined
|
||||||
import cash.z.ecc.android.sdk.db.entity.isSubmitSuccess
|
import cash.z.ecc.android.sdk.db.entity.isSubmitSuccess
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
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 kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
@ -116,15 +117,17 @@ class BalanceDetailViewModel @Inject constructor() : ViewModel() {
|
||||||
val hasUnmined = pendingUnmined.isNotEmpty()
|
val hasUnmined = pendingUnmined.isNotEmpty()
|
||||||
val hasPendingShieldedBalance = (pendingShieldedBalance?.value ?: 0L) > 0L
|
val hasPendingShieldedBalance = (pendingShieldedBalance?.value ?: 0L) > 0L
|
||||||
val hasPendingTransparentBalance = (pendingTransparentBalance?.value ?: 0L) > 0L
|
val hasPendingTransparentBalance = (pendingTransparentBalance?.value ?: 0L) > 0L
|
||||||
val missingBlocks = (info.networkBlockHeight - info.lastScannedHeight).coerceAtLeast(0)
|
val missingBlocks = ((info.networkBlockHeight?.value ?: 0) - (info.lastScannedHeight?.value ?: 0)).coerceAtLeast(0)
|
||||||
|
|
||||||
private fun PendingTransaction.isConfirmed(networkBlockHeight: Int): Boolean {
|
private fun PendingTransaction.isConfirmed(networkBlockHeight: BlockHeight?): Boolean {
|
||||||
return isMined() && (networkBlockHeight - minedHeight + 1) > 10 // fix: plus 1 because the mined block counts as the FIRST confirmation
|
return networkBlockHeight?.let {
|
||||||
|
isMined() && (it.value - minedHeight + 1) > 10 // fix: plus 1 because the mined block counts as the FIRST confirmation
|
||||||
|
} ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun remainingConfirmations(confirmationsRequired: Int = 10) =
|
fun remainingConfirmations(confirmationsRequired: Int = 10) =
|
||||||
pendingUnconfirmed
|
pendingUnconfirmed
|
||||||
.map { confirmationsRequired - (info.lastScannedHeight - it.minedHeight + 1) } // fix: plus 1 because the mined block counts as the FIRST confirmation
|
.map { confirmationsRequired - ((info.lastScannedHeight?.value ?: -1) - it.minedHeight + 1) } // fix: plus 1 because the mined block counts as the FIRST confirmation
|
||||||
.filter { it > 0 }
|
.filter { it > 0 }
|
||||||
.sortedDescending()
|
.sortedDescending()
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ class HomeViewModel @Inject constructor() : ViewModel() {
|
||||||
|
|
||||||
data class UiModel(
|
data class UiModel(
|
||||||
val status: Synchronizer.Status = DISCONNECTED,
|
val status: Synchronizer.Status = DISCONNECTED,
|
||||||
val processorInfo: CompactBlockProcessor.ProcessorInfo = CompactBlockProcessor.ProcessorInfo(),
|
val processorInfo: CompactBlockProcessor.ProcessorInfo = CompactBlockProcessor.ProcessorInfo(null, null, null, null, null),
|
||||||
val orchardBalance: WalletBalance?,
|
val orchardBalance: WalletBalance?,
|
||||||
val saplingBalance: WalletBalance?,
|
val saplingBalance: WalletBalance?,
|
||||||
val transparentBalance: WalletBalance?,
|
val transparentBalance: WalletBalance?,
|
||||||
|
@ -141,11 +141,11 @@ class HomeViewModel @Inject constructor() : ViewModel() {
|
||||||
val isDisconnected = status == DISCONNECTED
|
val isDisconnected = status == DISCONNECTED
|
||||||
val downloadProgress: Int get() {
|
val downloadProgress: Int get() {
|
||||||
return processorInfo.run {
|
return processorInfo.run {
|
||||||
if (lastDownloadRange.isEmpty()) {
|
if (lastDownloadRange?.isEmpty() == true) {
|
||||||
100
|
100
|
||||||
} else {
|
} else {
|
||||||
val progress =
|
val progress =
|
||||||
(((lastDownloadedHeight - lastDownloadRange.first + 1).coerceAtLeast(0).toFloat() / (lastDownloadRange.last - lastDownloadRange.first + 1)) * 100.0f).coerceAtMost(
|
((((lastDownloadedHeight?.value ?: 0) - (lastDownloadRange?.start?.value ?: 0) + 1).coerceAtLeast(0).toFloat() / ((lastDownloadRange?.endInclusive?.value ?: 0) - (lastDownloadRange?.start?.value ?: 0) + 1)) * 100.0f).coerceAtMost(
|
||||||
100.0f
|
100.0f
|
||||||
).roundToInt()
|
).roundToInt()
|
||||||
progress
|
progress
|
||||||
|
@ -154,10 +154,10 @@ class HomeViewModel @Inject constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
val scanProgress: Int get() {
|
val scanProgress: Int get() {
|
||||||
return processorInfo.run {
|
return processorInfo.run {
|
||||||
if (lastScanRange.isEmpty()) {
|
if (lastScanRange?.isEmpty() == true) {
|
||||||
100
|
100
|
||||||
} else {
|
} else {
|
||||||
val progress = (((lastScannedHeight - lastScanRange.first + 1).coerceAtLeast(0).toFloat() / (lastScanRange.last - lastScanRange.first + 1)) * 100.0f).coerceAtMost(100.0f).roundToInt()
|
val progress = ((((lastScannedHeight?.value ?: 0) - (lastScanRange?.start?.value ?: 0) + 1).coerceAtLeast(0).toFloat() / ((lastScanRange?.endInclusive?.value ?: 0) - (lastScanRange?.start?.value ?: 0) + 1)) * 100.0f).coerceAtMost(100.0f).roundToInt()
|
||||||
progress
|
progress
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import cash.z.ecc.android.sdk.Initializer
|
||||||
import cash.z.ecc.android.sdk.Synchronizer
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
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.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
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.util.twig
|
import cash.z.ecc.android.util.twig
|
||||||
|
@ -48,8 +49,10 @@ class ProfileViewModel @Inject constructor() : ViewModel() {
|
||||||
|
|
||||||
suspend fun fetchUtxos(): Int {
|
suspend fun fetchUtxos(): Int {
|
||||||
val address = getTransparentAddress()
|
val address = getTransparentAddress()
|
||||||
val height: Int = lockBox[Const.Backup.BIRTHDAY_HEIGHT] ?: synchronizer.network.saplingActivationHeight
|
val height: Long = lockBox[Const.Backup.BIRTHDAY_HEIGHT]
|
||||||
return synchronizer.refreshUtxos(address, height) ?: 0
|
?: synchronizer.network.saplingActivationHeight.value
|
||||||
|
return synchronizer.refreshUtxos(address, BlockHeight.new(synchronizer.network, height))
|
||||||
|
?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getTransparentBalance(): WalletBalance {
|
suspend fun getTransparentBalance(): WalletBalance {
|
||||||
|
@ -60,9 +63,19 @@ class ProfileViewModel @Inject constructor() : ViewModel() {
|
||||||
fun shieldFunds(): Flow<PendingTransaction> {
|
fun shieldFunds(): Flow<PendingTransaction> {
|
||||||
return lockBox.getBytes(Const.Backup.SEED)?.let {
|
return lockBox.getBytes(Const.Backup.SEED)?.let {
|
||||||
val sk = runBlocking { DerivationTool.deriveSpendingKeys(it, synchronizer.network)[0] }
|
val sk = runBlocking { DerivationTool.deriveSpendingKeys(it, synchronizer.network)[0] }
|
||||||
val tsk = runBlocking { DerivationTool.deriveTransparentSecretKey(it, synchronizer.network) }
|
val tsk =
|
||||||
val addr = runBlocking { DerivationTool.deriveTransparentAddressFromPrivateKey(tsk, synchronizer.network) }
|
runBlocking { DerivationTool.deriveTransparentSecretKey(it, synchronizer.network) }
|
||||||
synchronizer.shieldFunds(sk, tsk, "${ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX}\nAll UTXOs from $addr").onEach {
|
val addr = runBlocking {
|
||||||
|
DerivationTool.deriveTransparentAddressFromPrivateKey(
|
||||||
|
tsk,
|
||||||
|
synchronizer.network
|
||||||
|
)
|
||||||
|
}
|
||||||
|
synchronizer.shieldFunds(
|
||||||
|
sk,
|
||||||
|
tsk,
|
||||||
|
"${ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX}\nAll UTXOs from $addr"
|
||||||
|
).onEach {
|
||||||
twig("Received shielding txUpdate: ${it?.toString()}")
|
twig("Received shielding txUpdate: ${it?.toString()}")
|
||||||
// updateMetrics(it)
|
// updateMetrics(it)
|
||||||
// reportFailures(it)
|
// reportFailures(it)
|
||||||
|
@ -84,7 +97,11 @@ class ProfileViewModel @Inject constructor() : ViewModel() {
|
||||||
|
|
||||||
fun wipe() {
|
fun wipe() {
|
||||||
synchronizer.stop()
|
synchronizer.stop()
|
||||||
Toast.makeText(ZcashWalletApp.instance, "SUCCESS! Wallet data cleared. Please relaunch to rescan!", Toast.LENGTH_LONG).show()
|
Toast.makeText(
|
||||||
|
ZcashWalletApp.instance,
|
||||||
|
"SUCCESS! Wallet data cleared. Please relaunch to rescan!",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
runBlocking {
|
runBlocking {
|
||||||
Initializer.erase(
|
Initializer.erase(
|
||||||
ZcashWalletApp.instance,
|
ZcashWalletApp.instance,
|
||||||
|
@ -94,33 +111,57 @@ class ProfileViewModel @Inject constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun fullRescan() {
|
suspend fun fullRescan() {
|
||||||
rewindTo(synchronizer.latestBirthdayHeight)
|
synchronizer.latestBirthdayHeight?.let {
|
||||||
|
rewindTo(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun quickRescan() {
|
suspend fun quickRescan() {
|
||||||
rewindTo(synchronizer.latestHeight - 8064)
|
synchronizer.latestHeight?.let {
|
||||||
|
val newHeightValue =
|
||||||
|
(it.value - 8064L).coerceAtLeast(synchronizer.network.saplingActivationHeight.value)
|
||||||
|
rewindTo(BlockHeight.new(synchronizer.network, newHeightValue))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun rewindTo(targetHeight: Int) {
|
private suspend fun rewindTo(targetHeight: BlockHeight) {
|
||||||
twig("TMP: rewinding to targetHeight $targetHeight")
|
twig("TMP: rewinding to targetHeight $targetHeight")
|
||||||
synchronizer.rewindToNearestHeight(targetHeight, true)
|
synchronizer.rewindToNearestHeight(targetHeight, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fullScanDistance() =
|
fun fullScanDistance(): Long {
|
||||||
(synchronizer.latestHeight - synchronizer.latestBirthdayHeight).coerceAtLeast(0)
|
synchronizer.latestHeight?.let { latestHeight ->
|
||||||
|
synchronizer.latestBirthdayHeight?.let { latestBirthdayHeight ->
|
||||||
|
return (latestHeight.value - latestBirthdayHeight.value).coerceAtLeast(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
fun quickScanDistance(): Int {
|
fun quickScanDistance(): Int {
|
||||||
val latest = synchronizer.latestHeight
|
val latest = synchronizer.latestHeight
|
||||||
val oneWeek = 60 * 60 * 24 / 75 * 7 // a week's worth of blocks
|
val oneWeek = 60 * 60 * 24 / 75 * 7 // a week's worth of blocks
|
||||||
var foo = 0
|
val height = BlockHeight.new(
|
||||||
runBlocking {
|
synchronizer.network,
|
||||||
foo = synchronizer.getNearestRewindHeight(latest - oneWeek)
|
((latest?.value ?: synchronizer.network.saplingActivationHeight.value) - oneWeek)
|
||||||
|
.coerceAtLeast(synchronizer.network.saplingActivationHeight.value)
|
||||||
|
)
|
||||||
|
val foo = runBlocking {
|
||||||
|
synchronizer.getNearestRewindHeight(height)
|
||||||
}
|
}
|
||||||
return latest - foo
|
return ((latest?.value ?: 0) - foo.value).toInt().coerceAtLeast(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun blocksToMinutesString(blocks: BlockHeight): String {
|
||||||
|
val duration = (blocks.value / bps.toDouble()).toDuration(DurationUnit.SECONDS)
|
||||||
|
return duration.toString(DurationUnit.MINUTES).replace("m", " minutes")
|
||||||
|
}
|
||||||
fun blocksToMinutesString(blocks: Int): String {
|
fun blocksToMinutesString(blocks: Int): String {
|
||||||
val duration = (blocks / bps.toDouble()).toDuration(DurationUnit.SECONDS)
|
val duration = (blocks / bps.toDouble()).toDuration(DurationUnit.SECONDS)
|
||||||
return duration.toString(DurationUnit.MINUTES).replace("m", " minutes")
|
return duration.toString(DurationUnit.MINUTES).replace("m", " minutes")
|
||||||
}
|
}
|
||||||
|
fun blocksToMinutesString(blocks: Long): String {
|
||||||
|
val duration = (blocks / bps.toDouble()).toDuration(DurationUnit.SECONDS)
|
||||||
|
return duration.toString(DurationUnit.MINUTES).replace("m", " minutes")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import cash.z.ecc.android.sdk.db.entity.isMined
|
||||||
import cash.z.ecc.android.sdk.db.entity.isSubmitSuccess
|
import cash.z.ecc.android.sdk.db.entity.isSubmitSuccess
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
import cash.z.ecc.android.sdk.ext.convertZatoshiToZecString
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.WalletBalance
|
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
|
||||||
|
@ -49,8 +50,10 @@ class AutoShieldViewModel @Inject constructor() : ViewModel() {
|
||||||
emit(StatusModel(unmined, unconfirmed, pending, info.networkBlockHeight))
|
emit(StatusModel(unmined, unconfirmed, pending, info.networkBlockHeight))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PendingTransaction.isConfirmed(networkBlockHeight: Int): Boolean {
|
private fun PendingTransaction.isConfirmed(networkBlockHeight: BlockHeight?): Boolean {
|
||||||
return isMined() && (networkBlockHeight - minedHeight + 1) > 10
|
return networkBlockHeight?.let { height ->
|
||||||
|
isMined() && (height.value - minedHeight + 1) > 10
|
||||||
|
} ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun cancel(id: Long) {
|
fun cancel(id: Long) {
|
||||||
|
@ -129,7 +132,7 @@ class AutoShieldViewModel @Inject constructor() : ViewModel() {
|
||||||
val pendingUnconfirmed: List<PendingTransaction> = listOf(),
|
val pendingUnconfirmed: List<PendingTransaction> = listOf(),
|
||||||
val pendingUnmined: List<PendingTransaction> = listOf(),
|
val pendingUnmined: List<PendingTransaction> = listOf(),
|
||||||
val pendingBalance: Long = 0L,
|
val pendingBalance: Long = 0L,
|
||||||
val latestHeight: Int = 0,
|
val latestHeight: BlockHeight? = null,
|
||||||
) {
|
) {
|
||||||
val hasUnconfirmed = pendingUnconfirmed.isNotEmpty()
|
val hasUnconfirmed = pendingUnconfirmed.isNotEmpty()
|
||||||
val hasUnmined = pendingUnmined.isNotEmpty()
|
val hasUnmined = pendingUnmined.isNotEmpty()
|
||||||
|
|
|
@ -21,7 +21,9 @@ import cash.z.ecc.android.feedback.Report.Tap.BACKUP_DONE
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.BACKUP_VERIFY
|
import cash.z.ecc.android.feedback.Report.Tap.BACKUP_VERIFY
|
||||||
import cash.z.ecc.android.feedback.measure
|
import cash.z.ecc.android.feedback.measure
|
||||||
import cash.z.ecc.android.lockbox.LockBox
|
import cash.z.ecc.android.lockbox.LockBox
|
||||||
|
import cash.z.ecc.android.sdk.db.entity.Block
|
||||||
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
import cash.z.ecc.android.sdk.ext.ZcashSdk
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.ui.base.BaseFragment
|
import cash.z.ecc.android.ui.base.BaseFragment
|
||||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITH_BACKUP
|
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITH_BACKUP
|
||||||
import cash.z.ecc.android.ui.util.AddressPartNumberSpan
|
import cash.z.ecc.android.ui.util.AddressPartNumberSpan
|
||||||
|
@ -91,23 +93,25 @@ class BackupFragment : BaseFragment<FragmentBackupBinding>() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move this into the SDK
|
// TODO: move this into the SDK
|
||||||
private suspend fun calculateBirthday(): Int {
|
private suspend fun calculateBirthday(): BlockHeight {
|
||||||
var storedBirthday = 0
|
var storedBirthday: BlockHeight? = null
|
||||||
var oldestTransactionHeight = 0
|
var oldestTransactionHeight: BlockHeight? = null
|
||||||
var activationHeight = 0
|
var activationHeight: BlockHeight? = null
|
||||||
try {
|
try {
|
||||||
activationHeight = mainActivity?.synchronizerComponent?.synchronizer()?.network?.saplingActivationHeight ?: 0
|
activationHeight = mainActivity?.synchronizerComponent?.synchronizer()?.network?.saplingActivationHeight
|
||||||
storedBirthday = walletSetup.loadBirthdayHeight() ?: 0
|
storedBirthday = walletSetup.loadBirthdayHeight()
|
||||||
oldestTransactionHeight = mainActivity?.synchronizerComponent?.synchronizer()?.receivedTransactions?.first()?.last()?.minedHeight ?: 0
|
oldestTransactionHeight = mainActivity?.synchronizerComponent?.synchronizer()?.receivedTransactions?.first()?.last()?.minedHeight?.let {
|
||||||
|
BlockHeight.new(ZcashWalletApp.instance.defaultNetwork, it)
|
||||||
|
}
|
||||||
// to be safe adjust for reorgs (and generally a little cushion is good for privacy)
|
// to be safe adjust for reorgs (and generally a little cushion is good for privacy)
|
||||||
// so we round down to the nearest 100 and then subtract 100 to ensure that the result is always at least 100 blocks away
|
// so we round down to the nearest 100 and then subtract 100 to ensure that the result is always at least 100 blocks away
|
||||||
oldestTransactionHeight = ZcashSdk.MAX_REORG_SIZE.let { boundary ->
|
oldestTransactionHeight = ZcashSdk.MAX_REORG_SIZE.let { boundary ->
|
||||||
oldestTransactionHeight.let { it - it.rem(boundary) - boundary }
|
oldestTransactionHeight?.let { it.value - it.value.rem(boundary) - boundary }?.let { BlockHeight.new(ZcashWalletApp.instance.defaultNetwork, it) }
|
||||||
}
|
}
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
twig("failed to calculate birthday due to: $t")
|
twig("failed to calculate birthday due to: $t")
|
||||||
}
|
}
|
||||||
return maxOf(storedBirthday, oldestTransactionHeight, activationHeight)
|
return listOfNotNull(storedBirthday, oldestTransactionHeight, activationHeight).maxBy { it.value }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onEnterWallet(showMessage: Boolean = !this.hasBackUp) {
|
private fun onEnterWallet(showMessage: Boolean = !this.hasBackUp) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import cash.z.ecc.android.feedback.Report.Tap.LANDING_BACKUP_SKIPPED_2
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.LANDING_BACKUP_SKIPPED_3
|
import cash.z.ecc.android.feedback.Report.Tap.LANDING_BACKUP_SKIPPED_3
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.LANDING_NEW
|
import cash.z.ecc.android.feedback.Report.Tap.LANDING_NEW
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.LANDING_RESTORE
|
import cash.z.ecc.android.feedback.Report.Tap.LANDING_RESTORE
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||||
import cash.z.ecc.android.ui.base.BaseFragment
|
import cash.z.ecc.android.ui.base.BaseFragment
|
||||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITHOUT_BACKUP
|
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITHOUT_BACKUP
|
||||||
|
@ -134,17 +135,17 @@ class LandingFragment : BaseFragment<FragmentLandingBinding>() {
|
||||||
// AKA import wallet
|
// AKA import wallet
|
||||||
private fun onUseDevWallet() {
|
private fun onUseDevWallet() {
|
||||||
val seedPhrase: String
|
val seedPhrase: String
|
||||||
val birthday: Int
|
val birthday: BlockHeight
|
||||||
|
|
||||||
// new testnet dev wallet
|
// new testnet dev wallet
|
||||||
when (ZcashWalletApp.instance.defaultNetwork) {
|
when (ZcashWalletApp.instance.defaultNetwork) {
|
||||||
ZcashNetwork.Mainnet -> {
|
ZcashNetwork.Mainnet -> {
|
||||||
seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||||
birthday = 991645 // 663174
|
birthday = BlockHeight.new(ZcashNetwork.Mainnet, 991645) // 663174
|
||||||
}
|
}
|
||||||
ZcashNetwork.Testnet -> {
|
ZcashNetwork.Testnet -> {
|
||||||
seedPhrase = "quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten"
|
seedPhrase = "quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten"
|
||||||
birthday = 1330190
|
birthday = BlockHeight.new(ZcashNetwork.Testnet, 1330190)
|
||||||
}
|
}
|
||||||
else -> throw RuntimeException("No developer wallet exists for network ${ZcashWalletApp.instance.defaultNetwork}")
|
else -> throw RuntimeException("No developer wallet exists for network ${ZcashWalletApp.instance.defaultNetwork}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import cash.z.ecc.android.feedback.Report.Tap.RESTORE_BACK
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.RESTORE_CLEAR
|
import cash.z.ecc.android.feedback.Report.Tap.RESTORE_CLEAR
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.RESTORE_DONE
|
import cash.z.ecc.android.feedback.Report.Tap.RESTORE_DONE
|
||||||
import cash.z.ecc.android.feedback.Report.Tap.RESTORE_SUCCESS
|
import cash.z.ecc.android.feedback.Report.Tap.RESTORE_SUCCESS
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.ui.base.BaseFragment
|
import cash.z.ecc.android.ui.base.BaseFragment
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.tylersuehr.chips.Chip
|
import com.tylersuehr.chips.Chip
|
||||||
|
@ -133,18 +134,18 @@ class RestoreFragment : BaseFragment<FragmentRestoreBinding>(), View.OnKeyListen
|
||||||
}
|
}
|
||||||
var birthday = binding.root.findViewById<TextView>(R.id.input_birthdate).text.toString()
|
var birthday = binding.root.findViewById<TextView>(R.id.input_birthdate).text.toString()
|
||||||
.let { birthdateString ->
|
.let { birthdateString ->
|
||||||
if (birthdateString.isNullOrEmpty()) activation else birthdateString.toInt()
|
if (birthdateString.isNullOrEmpty()) activation.value else birthdateString.toLong()
|
||||||
}.coerceAtLeast(activation)
|
}.coerceAtLeast(activation.value)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
walletSetup.validatePhrase(seedPhrase)
|
walletSetup.validatePhrase(seedPhrase)
|
||||||
importWallet(seedPhrase, birthday)
|
importWallet(seedPhrase, BlockHeight.new(ZcashWalletApp.instance.defaultNetwork, birthday))
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
mainActivity?.showInvalidSeedPhraseError(t)
|
mainActivity?.showInvalidSeedPhraseError(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun importWallet(seedPhrase: String, birthday: Int) {
|
private fun importWallet(seedPhrase: String, birthday: BlockHeight?) {
|
||||||
mainActivity?.reportFunnel(Restore.ImportStarted)
|
mainActivity?.reportFunnel(Restore.ImportStarted)
|
||||||
mainActivity?.hideKeyboard()
|
mainActivity?.hideKeyboard()
|
||||||
mainActivity?.apply {
|
mainActivity?.apply {
|
||||||
|
|
|
@ -10,14 +10,11 @@ import cash.z.ecc.android.feedback.Report
|
||||||
import cash.z.ecc.android.lockbox.LockBox
|
import cash.z.ecc.android.lockbox.LockBox
|
||||||
import cash.z.ecc.android.sdk.Initializer
|
import cash.z.ecc.android.sdk.Initializer
|
||||||
import cash.z.ecc.android.sdk.exception.InitializerException
|
import cash.z.ecc.android.sdk.exception.InitializerException
|
||||||
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||||
import cash.z.ecc.android.sdk.tool.WalletBirthdayTool
|
|
||||||
import cash.z.ecc.android.sdk.type.UnifiedViewingKey
|
import cash.z.ecc.android.sdk.type.UnifiedViewingKey
|
||||||
import cash.z.ecc.android.sdk.type.WalletBirthday
|
|
||||||
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
import cash.z.ecc.android.sdk.type.ZcashNetwork
|
||||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.NO_SEED
|
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.*
|
||||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITHOUT_BACKUP
|
|
||||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.WalletSetupState.SEED_WITH_BACKUP
|
|
||||||
import cash.z.ecc.android.util.twig
|
import cash.z.ecc.android.util.twig
|
||||||
import cash.z.ecc.kotlin.mnemonic.Mnemonics
|
import cash.z.ecc.kotlin.mnemonic.Mnemonics
|
||||||
import com.bugsnag.android.Bugsnag
|
import com.bugsnag.android.Bugsnag
|
||||||
|
@ -62,10 +59,13 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() {
|
||||||
mnemonics.validate(seedPhrase.toCharArray())
|
mnemonics.validate(seedPhrase.toCharArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadBirthdayHeight(): Int? {
|
fun loadBirthdayHeight(): BlockHeight? {
|
||||||
val h: Int? = lockBox[Const.Backup.BIRTHDAY_HEIGHT]
|
val h: Int? = lockBox[Const.Backup.BIRTHDAY_HEIGHT]
|
||||||
twig("Loaded birthday with key ${Const.Backup.BIRTHDAY_HEIGHT} and found $h")
|
twig("Loaded birthday with key ${Const.Backup.BIRTHDAY_HEIGHT} and found $h")
|
||||||
return h
|
h?.let {
|
||||||
|
return BlockHeight.new(ZcashWalletApp.instance.defaultNetwork, it.toLong())
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun newWallet(): Initializer {
|
suspend fun newWallet(): Initializer {
|
||||||
|
@ -77,10 +77,10 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() {
|
||||||
return openStoredWallet()
|
return openStoredWallet()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun importWallet(seedPhrase: String, birthdayHeight: Int): Initializer {
|
suspend fun importWallet(seedPhrase: String, birthdayHeight: BlockHeight?): Initializer {
|
||||||
val network = ZcashWalletApp.instance.defaultNetwork
|
val network = ZcashWalletApp.instance.defaultNetwork
|
||||||
twig("Importing ${network.networkName} wallet. Requested birthday: $birthdayHeight")
|
twig("Importing ${network.networkName} wallet. Requested birthday: $birthdayHeight")
|
||||||
storeWallet(seedPhrase.toCharArray(), network, loadNearestBirthday(network, birthdayHeight))
|
storeWallet(seedPhrase.toCharArray(), network, birthdayHeight ?: loadNearestBirthday(network))
|
||||||
return openStoredWallet()
|
return openStoredWallet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,16 +167,15 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun onMissingBirthday(network: ZcashNetwork): Int = failWith(InitializerException.MissingBirthdayException) {
|
private suspend fun onMissingBirthday(network: ZcashNetwork): BlockHeight = failWith(InitializerException.MissingBirthdayException) {
|
||||||
twig("Recover Birthday: falling back to sapling birthday")
|
twig("Recover Birthday: falling back to sapling birthday")
|
||||||
loadNearestBirthday(network, network.saplingActivationHeight).height
|
loadNearestBirthday(network)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadNearestBirthday(network: ZcashNetwork, birthdayHeight: Int? = null) =
|
private suspend fun loadNearestBirthday(network: ZcashNetwork) =
|
||||||
WalletBirthdayTool.loadNearest(
|
BlockHeight.ofLatestCheckpoint(
|
||||||
ZcashWalletApp.instance,
|
ZcashWalletApp.instance,
|
||||||
network,
|
network,
|
||||||
birthdayHeight
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -192,7 +191,7 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() {
|
||||||
private suspend fun storeWallet(
|
private suspend fun storeWallet(
|
||||||
seedPhraseChars: CharArray,
|
seedPhraseChars: CharArray,
|
||||||
network: ZcashNetwork,
|
network: ZcashNetwork,
|
||||||
birthday: WalletBirthday
|
birthday: BlockHeight
|
||||||
) {
|
) {
|
||||||
check(!lockBox.getBoolean(Const.Backup.HAS_SEED)) {
|
check(!lockBox.getBoolean(Const.Backup.HAS_SEED)) {
|
||||||
"Error! Cannot store a seed when one already exists! This would overwrite the" +
|
"Error! Cannot store a seed when one already exists! This would overwrite the" +
|
||||||
|
@ -210,9 +209,9 @@ class WalletSetupViewModel @Inject constructor() : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun storeBirthday(birthday: WalletBirthday) = withContext(IO) {
|
private suspend fun storeBirthday(birthday: BlockHeight) = withContext(IO) {
|
||||||
twig("Storing birthday ${birthday.height} with and key ${Const.Backup.BIRTHDAY_HEIGHT}")
|
twig("Storing birthday ${birthday.value} with and key ${Const.Backup.BIRTHDAY_HEIGHT}")
|
||||||
lockBox[Const.Backup.BIRTHDAY_HEIGHT] = birthday.height
|
lockBox[Const.Backup.BIRTHDAY_HEIGHT] = birthday.value
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun storeSeedPhrase(seedPhrase: CharArray) = withContext(IO) {
|
private suspend fun storeSeedPhrase(seedPhrase: CharArray) = withContext(IO) {
|
||||||
|
|
|
@ -83,7 +83,7 @@ object Deps {
|
||||||
object Zcash {
|
object Zcash {
|
||||||
const val ANDROID_WALLET_PLUGINS = "cash.z.ecc.android:zcash-android-wallet-plugins:1.0.0"
|
const val ANDROID_WALLET_PLUGINS = "cash.z.ecc.android:zcash-android-wallet-plugins:1.0.0"
|
||||||
const val KOTLIN_BIP39 = "cash.z.ecc.android:kotlin-bip39:1.0.1"
|
const val KOTLIN_BIP39 = "cash.z.ecc.android:kotlin-bip39:1.0.1"
|
||||||
const val SDK = "cash.z.ecc.android:zcash-android-sdk:1.7.0-beta01"
|
const val SDK = "cash.z.ecc.android:zcash-android-sdk:1.8.0-beta01-SNAPSHOT"
|
||||||
}
|
}
|
||||||
object Misc {
|
object Misc {
|
||||||
const val LOTTIE = "com.airbnb.android:lottie:3.7.0"
|
const val LOTTIE = "com.airbnb.android:lottie:3.7.0"
|
||||||
|
|
|
@ -18,13 +18,13 @@ dependencyResolutionManagement {
|
||||||
maven("https://jitpack.io")
|
maven("https://jitpack.io")
|
||||||
jcenter()
|
jcenter()
|
||||||
// Uncomment to use a snapshot version of the SDK, e.g. when the SDK version ends in -SNAPSHOT
|
// Uncomment to use a snapshot version of the SDK, e.g. when the SDK version ends in -SNAPSHOT
|
||||||
//maven("https://oss.sonatype.org/content/repositories/snapshots") {
|
maven("https://oss.sonatype.org/content/repositories/snapshots") {
|
||||||
// if (isRepoRestrictionEnabled) {
|
if (isRepoRestrictionEnabled) {
|
||||||
// content {
|
content {
|
||||||
// includeGroup("cash.z.ecc.android")
|
includeGroup("cash.z.ecc.android")
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue