Cleanup and bugfixes.
- Corrected logic for splitting address into 8 parts - Corrected bug in loading seed phrase
This commit is contained in:
parent
cdcc39121b
commit
e1bbf1b6e8
|
@ -40,6 +40,8 @@ class WalletDetailFragment : BaseFragment<FragmentDetailBinding>() {
|
|||
mainActivity?.showSnackbar("Feedback not yet implemented.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun onViewLogs() {
|
||||
loadLogFileAsText().let { logText ->
|
||||
if (logText == null) {
|
||||
|
|
|
@ -16,10 +16,14 @@ import cash.z.ecc.android.ext.onClickNavTo
|
|||
import cash.z.ecc.android.ext.onClickNavUp
|
||||
import cash.z.ecc.android.ui.base.BaseFragment
|
||||
import cash.z.ecc.android.ui.util.AddressPartNumberSpan
|
||||
import cash.z.wallet.sdk.ext.twig
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import kotlinx.android.synthetic.main.fragment_receive.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.round
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ReceiveFragment : BaseFragment<FragmentReceiveBinding>() {
|
||||
override fun inflate(inflater: LayoutInflater): FragmentReceiveBinding =
|
||||
|
@ -51,23 +55,39 @@ class ReceiveFragment : BaseFragment<FragmentReceiveBinding>() {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
lifecycleScope.launch {
|
||||
onAddressLoaded("zs1qduvdyuv83pyygjvc4cfcuc2wj5flnqn730iigf0tjct8k5ccs9y30p96j2gvn9gzyxm6q0vj12c4")
|
||||
resumedScope.launch {
|
||||
mainActivity?.synchronizer?.getAddress()?.let { address ->
|
||||
onAddressLoaded(address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAddressLoaded(address: String) {
|
||||
Log.e("TWIG", "onAddressLoaded: $address length: ${address.length}")
|
||||
twig("address loaded: $address length: ${address.length}")
|
||||
qrecycler.load(address)
|
||||
.withQuietZoneSize(3)
|
||||
.withCorrectionLevel(QRecycler.CorrectionLevel.MEDIUM)
|
||||
.into(receive_qr_code)
|
||||
|
||||
address.chunked(address.length/8).forEachIndexed { i, part ->
|
||||
address.distribute(8) { i, part ->
|
||||
setAddressPart(i, part)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> String.distribute(chunks: Int, block: (Int, String) -> T) {
|
||||
val charsPerChunk = length / 8.0
|
||||
val wholeCharsPerChunk = charsPerChunk.toInt()
|
||||
val chunksWithExtra = ((charsPerChunk - wholeCharsPerChunk) * chunks).roundToInt()
|
||||
repeat(chunks) { i ->
|
||||
val part = if (i < chunksWithExtra) {
|
||||
substring(i * (wholeCharsPerChunk + 1), (i + 1) * (wholeCharsPerChunk + 1))
|
||||
} else {
|
||||
substring(i * wholeCharsPerChunk + chunksWithExtra, (i + 1) * wholeCharsPerChunk + chunksWithExtra)
|
||||
}
|
||||
block(i, part)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAddressPart(index: Int, addressPart: String) {
|
||||
Log.e("TWIG", "setting address for part $index) $addressPart")
|
||||
val thinSpace = "\u2005" // 0.25 em space
|
||||
|
|
|
@ -15,18 +15,21 @@ import cash.z.ecc.android.R
|
|||
import cash.z.ecc.android.ZcashWalletApp
|
||||
import cash.z.ecc.android.databinding.FragmentBackupBinding
|
||||
import cash.z.ecc.android.di.annotation.FragmentScope
|
||||
import cash.z.ecc.android.ext.onClick
|
||||
import cash.z.ecc.android.feedback.Report.MetricType.SEED_PHRASE_LOADED
|
||||
import cash.z.ecc.android.feedback.measure
|
||||
import cash.z.ecc.android.lockbox.LockBox
|
||||
import cash.z.ecc.android.ui.base.BaseFragment
|
||||
import cash.z.ecc.android.ui.setup.WalletSetupViewModel.LockBoxKey
|
||||
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.ui.util.AddressPartNumberSpan
|
||||
import cash.z.ecc.kotlin.mnemonic.Mnemonics
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
class BackupFragment : BaseFragment<FragmentBackupBinding>() {
|
||||
|
@ -79,7 +82,7 @@ class BackupFragment : BaseFragment<FragmentBackupBinding>() {
|
|||
mainActivity?.navController?.popBackStack(R.id.wallet_setup_navigation, true)
|
||||
}
|
||||
|
||||
private fun applySpan(vararg textViews: TextView) {
|
||||
private fun applySpan(vararg textViews: TextView) = lifecycleScope.launch {
|
||||
val words = loadSeedWords()
|
||||
val thinSpace = "\u2005" // 0.25 em space
|
||||
textViews.forEachIndexed { index, textView ->
|
||||
|
@ -92,11 +95,14 @@ class BackupFragment : BaseFragment<FragmentBackupBinding>() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun loadSeedWords(): List<CharArray> {
|
||||
val lockBox = LockBox(ZcashWalletApp.instance)
|
||||
val mnemonics = Mnemonics()
|
||||
val seed = lockBox.getBytes(LockBoxKey.SEED)!!
|
||||
return mnemonics.nextMnemonicList(seed)
|
||||
private suspend fun loadSeedWords(): List<CharArray> = withContext(Dispatchers.IO) {
|
||||
mainActivity!!.feedback.measure(SEED_PHRASE_LOADED) {
|
||||
val lockBox = LockBox(ZcashWalletApp.instance)
|
||||
val mnemonics = Mnemonics()
|
||||
val seedPhrase = lockBox.getCharsUtf8(LockBoxKey.SEED_PHRASE)!!
|
||||
val result = mnemonics.toWordList(seedPhrase)
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,28 +13,28 @@
|
|||
<!-- TODO: redo these keylines to match the designs, exactly -->
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guieline_bottom_buttons"
|
||||
android:id="@+id/guideline_bottom_buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_percent="0.7017784" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guieline_keyline_start"
|
||||
android:id="@+id/guideline_keyline_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.054" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guieline_keyline_end"
|
||||
android:id="@+id/guideline_keyline_end"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_percent="0.946" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/guieline_keyline_bottom"
|
||||
android:id="@+id/guideline_keyline_bottom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
|
@ -73,7 +73,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="Backup\nWallet"
|
||||
android:textColor="@color/text_light"
|
||||
app:layout_constraintEnd_toEndOf="@id/guieline_keyline_end"
|
||||
app:layout_constraintEnd_toEndOf="@id/guideline_keyline_end"
|
||||
app:layout_constraintTop_toTopOf="@id/back_button" />
|
||||
|
||||
<View
|
||||
|
@ -81,10 +81,10 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:background="@drawable/background_banner_large"
|
||||
app:layout_constraintEnd_toEndOf="@id/guieline_keyline_end"
|
||||
app:layout_constraintStart_toStartOf="@id/guieline_keyline_start"
|
||||
app:layout_constraintTop_toBottomOf="@id/guieline_bottom_buttons"
|
||||
app:layout_constraintBottom_toBottomOf="@id/guieline_keyline_bottom"/>
|
||||
app:layout_constraintEnd_toEndOf="@id/guideline_keyline_end"
|
||||
app:layout_constraintStart_toStartOf="@id/guideline_keyline_start"
|
||||
app:layout_constraintTop_toBottomOf="@id/guideline_bottom_buttons"
|
||||
app:layout_constraintBottom_toBottomOf="@id/guideline_keyline_bottom"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_feedback"
|
||||
|
@ -97,8 +97,8 @@
|
|||
android:layout_marginStart="24dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/guieline_keyline_start"
|
||||
app:layout_constraintEnd_toEndOf="@id/guieline_keyline_end"
|
||||
app:layout_constraintStart_toStartOf="@id/guideline_keyline_start"
|
||||
app:layout_constraintEnd_toEndOf="@id/guideline_keyline_end"
|
||||
app:layout_constraintVertical_bias="0.8"/>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
@ -109,7 +109,7 @@
|
|||
android:text="View Logs"
|
||||
android:textColor="@color/text_light"
|
||||
app:layout_constraintTop_toBottomOf="@id/button_feedback"
|
||||
app:layout_constraintBottom_toBottomOf="@id/guieline_keyline_bottom"
|
||||
app:layout_constraintBottom_toBottomOf="@id/guideline_keyline_bottom"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintVertical_bias="0.2"/>
|
||||
|
|
|
@ -9,7 +9,7 @@ interface MnemonicProvider {
|
|||
/**
|
||||
* Generate a random seed.
|
||||
*/
|
||||
fun nextSeed(): ByteArray
|
||||
fun nextEntropy(): ByteArray
|
||||
|
||||
/**
|
||||
* Generate a random 24-word mnemonic phrase.
|
||||
|
|
|
@ -12,19 +12,19 @@ import javax.inject.Inject
|
|||
// which expects a string so for that reason, we just use Strings here)
|
||||
class Mnemonics @Inject constructor(): MnemonicProvider {
|
||||
|
||||
override fun nextSeed(): ByteArray {
|
||||
override fun nextEntropy(): ByteArray {
|
||||
return ByteArray(Words.TWENTY_FOUR.byteLength()).apply {
|
||||
SecureRandom().nextBytes(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun nextMnemonic(): CharArray {
|
||||
return nextMnemonic(nextSeed())
|
||||
return nextMnemonic(nextEntropy())
|
||||
}
|
||||
|
||||
override fun nextMnemonic(seed: ByteArray): CharArray {
|
||||
override fun nextMnemonic(entropy: ByteArray): CharArray {
|
||||
return StringBuilder().let { builder ->
|
||||
MnemonicGenerator(English.INSTANCE).createMnemonic(seed) { c ->
|
||||
MnemonicGenerator(English.INSTANCE).createMnemonic(entropy) { c ->
|
||||
builder.append(c)
|
||||
}
|
||||
builder.toString().toCharArray()
|
||||
|
@ -32,12 +32,12 @@ class Mnemonics @Inject constructor(): MnemonicProvider {
|
|||
}
|
||||
|
||||
override fun nextMnemonicList(): List<CharArray> {
|
||||
return nextMnemonicList(nextSeed())
|
||||
return nextMnemonicList(nextEntropy())
|
||||
}
|
||||
|
||||
override fun nextMnemonicList(seed: ByteArray): List<CharArray> {
|
||||
override fun nextMnemonicList(entropy: ByteArray): List<CharArray> {
|
||||
return WordListBuilder().let { builder ->
|
||||
MnemonicGenerator(English.INSTANCE).createMnemonic(seed) { c ->
|
||||
MnemonicGenerator(English.INSTANCE).createMnemonic(entropy) { c ->
|
||||
builder.append(c)
|
||||
}
|
||||
builder.wordList
|
||||
|
@ -46,7 +46,7 @@ class Mnemonics @Inject constructor(): MnemonicProvider {
|
|||
|
||||
override fun toSeed(mnemonic: CharArray): ByteArray {
|
||||
// TODO: either find another library that allows for doing this without strings or modify this code to leverage SecureCharBuffer (which doesn't work well with SeedCalculator.calculateSeed, which expects a string so for that reason, we just use Strings here)
|
||||
return SeedCalculator().calculateSeed(mnemonic.toString(), "")
|
||||
return SeedCalculator().calculateSeed(String(mnemonic), "")
|
||||
}
|
||||
|
||||
override fun toWordList(mnemonic: CharArray): List<CharArray> {
|
||||
|
|
Loading…
Reference in New Issue