2021-04-09 19:29:29 -07:00
|
|
|
package cash.z.ecc.android.sdk.util
|
|
|
|
|
|
|
|
import androidx.test.platform.app.InstrumentationRegistry
|
|
|
|
import cash.z.ecc.android.bip39.Mnemonics
|
|
|
|
import cash.z.ecc.android.bip39.toSeed
|
|
|
|
import cash.z.ecc.android.sdk.SdkSynchronizer
|
|
|
|
import cash.z.ecc.android.sdk.Synchronizer
|
2021-10-13 07:20:13 -07:00
|
|
|
import cash.z.ecc.android.sdk.internal.Twig
|
2021-10-04 04:18:37 -07:00
|
|
|
import cash.z.ecc.android.sdk.internal.service.LightWalletGrpcService
|
2021-11-18 04:10:30 -08:00
|
|
|
import cash.z.ecc.android.sdk.internal.twig
|
2022-10-06 10:44:34 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.Account
|
2022-07-12 05:40:09 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
2022-08-02 06:29:09 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.LightWalletEndpoint
|
|
|
|
import cash.z.ecc.android.sdk.model.Testnet
|
2022-07-07 05:52:07 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.WalletBalance
|
2022-06-21 16:34:42 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.Zatoshi
|
2022-08-02 06:29:09 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
2022-10-19 13:52:54 -07:00
|
|
|
import cash.z.ecc.android.sdk.model.isPending
|
2021-04-09 19:29:29 -07:00
|
|
|
import cash.z.ecc.android.sdk.tool.DerivationTool
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
2022-08-17 06:48:02 -07:00
|
|
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
2021-04-09 19:29:29 -07:00
|
|
|
import kotlinx.coroutines.SupervisorJob
|
|
|
|
import kotlinx.coroutines.delay
|
|
|
|
import kotlinx.coroutines.flow.catch
|
|
|
|
import kotlinx.coroutines.flow.collect
|
|
|
|
import kotlinx.coroutines.flow.first
|
|
|
|
import kotlinx.coroutines.flow.onCompletion
|
|
|
|
import kotlinx.coroutines.flow.takeWhile
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.newFixedThreadPoolContext
|
2021-10-21 13:05:02 -07:00
|
|
|
import kotlinx.coroutines.runBlocking
|
2021-04-09 19:29:29 -07:00
|
|
|
import java.util.concurrent.TimeoutException
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A simple wallet that connects to testnet for integration testing. The intention is that it is
|
|
|
|
* easy to drive and nice to use.
|
|
|
|
*/
|
2022-08-17 06:48:02 -07:00
|
|
|
@OptIn(DelicateCoroutinesApi::class)
|
2021-04-09 19:29:29 -07:00
|
|
|
class TestWallet(
|
2021-04-22 15:52:32 -07:00
|
|
|
val seedPhrase: String,
|
|
|
|
val alias: String = "TestWallet",
|
|
|
|
val network: ZcashNetwork = ZcashNetwork.Testnet,
|
2022-08-02 06:29:09 -07:00
|
|
|
val endpoint: LightWalletEndpoint = LightWalletEndpoint.Testnet,
|
|
|
|
startHeight: BlockHeight? = null
|
2021-04-09 19:29:29 -07:00
|
|
|
) {
|
|
|
|
constructor(
|
|
|
|
backup: Backups,
|
|
|
|
network: ZcashNetwork = ZcashNetwork.Testnet,
|
|
|
|
alias: String = "TestWallet"
|
|
|
|
) : this(
|
|
|
|
backup.seedPhrase,
|
|
|
|
network = network,
|
2021-04-29 12:57:13 -07:00
|
|
|
startHeight = if (network == ZcashNetwork.Mainnet) backup.mainnetBirthday else backup.testnetBirthday,
|
2021-04-09 19:29:29 -07:00
|
|
|
alias = alias
|
|
|
|
)
|
|
|
|
|
|
|
|
val walletScope = CoroutineScope(
|
|
|
|
SupervisorJob() + newFixedThreadPoolContext(3, this.javaClass.simpleName)
|
|
|
|
)
|
2021-10-21 13:05:02 -07:00
|
|
|
|
|
|
|
// Although runBlocking isn't great, this usage is OK because this is only used within the
|
|
|
|
// automated tests
|
|
|
|
|
2021-04-09 19:29:29 -07:00
|
|
|
private val context = InstrumentationRegistry.getInstrumentation().context
|
|
|
|
private val seed: ByteArray = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
2022-10-06 10:44:34 -07:00
|
|
|
private val spendingKey =
|
|
|
|
runBlocking { DerivationTool.deriveUnifiedSpendingKey(seed, network = network, Account.DEFAULT) }
|
2022-05-18 18:04:30 -07:00
|
|
|
private val transparentAccountPrivateKey =
|
2022-10-06 10:44:34 -07:00
|
|
|
runBlocking { DerivationTool.deriveTransparentAccountPrivateKey(seed, network = network, Account.DEFAULT) }
|
2022-10-06 10:48:21 -07:00
|
|
|
val synchronizer: SdkSynchronizer = Synchronizer.newBlocking(
|
|
|
|
context,
|
|
|
|
network,
|
|
|
|
alias,
|
|
|
|
lightWalletEndpoint = endpoint,
|
|
|
|
seed = seed,
|
|
|
|
startHeight
|
|
|
|
) as SdkSynchronizer
|
2021-04-09 19:29:29 -07:00
|
|
|
val service = (synchronizer.processor.downloader.lightWalletService as LightWalletGrpcService)
|
|
|
|
|
2022-06-21 16:34:42 -07:00
|
|
|
val available get() = synchronizer.saplingBalances.value?.available
|
2022-08-04 10:09:19 -07:00
|
|
|
val unifiedAddress =
|
2022-10-06 10:44:34 -07:00
|
|
|
runBlocking { DerivationTool.deriveUnifiedAddress(seed, network = network, Account.DEFAULT) }
|
2021-10-21 13:05:02 -07:00
|
|
|
val transparentAddress =
|
2022-10-06 10:44:34 -07:00
|
|
|
runBlocking { DerivationTool.deriveTransparentAddress(seed, network = network, Account.DEFAULT) }
|
2021-04-09 19:29:29 -07:00
|
|
|
val birthdayHeight get() = synchronizer.latestBirthdayHeight
|
|
|
|
val networkName get() = synchronizer.network.networkName
|
|
|
|
|
|
|
|
suspend fun transparentBalance(): WalletBalance {
|
|
|
|
synchronizer.refreshUtxos(transparentAddress, synchronizer.latestBirthdayHeight)
|
|
|
|
return synchronizer.getTransparentBalance(transparentAddress)
|
|
|
|
}
|
|
|
|
|
|
|
|
suspend fun sync(timeout: Long = -1): TestWallet {
|
|
|
|
val killSwitch = walletScope.launch {
|
|
|
|
if (timeout > 0) {
|
|
|
|
delay(timeout)
|
|
|
|
throw TimeoutException("Failed to sync wallet within ${timeout}ms")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!synchronizer.isStarted) {
|
|
|
|
twig("Starting sync")
|
|
|
|
synchronizer.start(walletScope)
|
|
|
|
} else {
|
|
|
|
twig("Awaiting next SYNCED status")
|
|
|
|
}
|
|
|
|
|
|
|
|
// block until synced
|
|
|
|
synchronizer.status.first { it == Synchronizer.Status.SYNCED }
|
|
|
|
killSwitch.cancel()
|
|
|
|
twig("Synced!")
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
2022-10-06 10:48:21 -07:00
|
|
|
suspend fun send(
|
|
|
|
address: String = transparentAddress,
|
|
|
|
memo: String = "",
|
2022-10-06 10:44:34 -07:00
|
|
|
amount: Zatoshi = Zatoshi(500L)
|
2022-10-06 10:48:21 -07:00
|
|
|
): TestWallet {
|
2021-04-22 15:52:32 -07:00
|
|
|
Twig.sprout("$alias sending")
|
2022-10-06 10:44:34 -07:00
|
|
|
synchronizer.sendToAddress(spendingKey, amount, address, memo)
|
2022-07-12 05:40:09 -07:00
|
|
|
.takeWhile { it.isPending(null) }
|
2021-04-09 19:29:29 -07:00
|
|
|
.collect {
|
|
|
|
twig("Updated transaction: $it")
|
|
|
|
}
|
2021-04-22 15:52:32 -07:00
|
|
|
Twig.clip("$alias sending")
|
2021-04-09 19:29:29 -07:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
2022-07-12 05:40:09 -07:00
|
|
|
suspend fun rewindToHeight(height: BlockHeight): TestWallet {
|
2021-04-26 14:37:30 -07:00
|
|
|
synchronizer.rewindToNearestHeight(height, false)
|
2021-04-09 19:29:29 -07:00
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
suspend fun shieldFunds(): TestWallet {
|
|
|
|
twig("checking $transparentAddress for transactions!")
|
2022-07-12 05:40:09 -07:00
|
|
|
synchronizer.refreshUtxos(transparentAddress, BlockHeight.new(ZcashNetwork.Mainnet, 935000)).let { count ->
|
2021-04-09 19:29:29 -07:00
|
|
|
twig("FOUND $count new UTXOs")
|
|
|
|
}
|
|
|
|
|
|
|
|
synchronizer.getTransparentBalance(transparentAddress).let { walletBalance ->
|
2022-06-21 16:34:42 -07:00
|
|
|
twig("FOUND utxo balance of total: ${walletBalance.total} available: ${walletBalance.available}")
|
2021-04-09 19:29:29 -07:00
|
|
|
|
2022-06-21 16:34:42 -07:00
|
|
|
if (walletBalance.available.value > 0L) {
|
2022-10-06 10:44:34 -07:00
|
|
|
synchronizer.shieldFunds(spendingKey, transparentAccountPrivateKey)
|
2021-04-09 19:29:29 -07:00
|
|
|
.onCompletion { twig("done shielding funds") }
|
|
|
|
.catch { twig("Failed with $it") }
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
suspend fun join(timeout: Long? = null): TestWallet {
|
|
|
|
// block until stopped
|
|
|
|
twig("Staying alive until synchronizer is stopped!")
|
|
|
|
if (timeout != null) {
|
|
|
|
twig("Scheduling a stop in ${timeout}ms")
|
|
|
|
walletScope.launch {
|
|
|
|
delay(timeout)
|
|
|
|
synchronizer.stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
synchronizer.status.first { it == Synchronizer.Status.STOPPED }
|
|
|
|
twig("Stopped!")
|
|
|
|
return this
|
|
|
|
}
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
init {
|
|
|
|
Twig.enabled(true)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-12 05:40:09 -07:00
|
|
|
enum class Backups(val seedPhrase: String, val testnetBirthday: BlockHeight, val mainnetBirthday: BlockHeight) {
|
2021-04-29 12:57:13 -07:00
|
|
|
// TODO: get the proper birthday values for these wallets
|
2022-08-02 06:29:09 -07:00
|
|
|
DEFAULT(
|
|
|
|
"column rhythm acoustic gym cost fit keen maze fence seed mail medal shrimp tell relief clip cannon foster soldier shallow refuse lunar parrot banana",
|
|
|
|
BlockHeight.new(
|
|
|
|
ZcashNetwork.Testnet,
|
|
|
|
1_355_928
|
|
|
|
),
|
|
|
|
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
|
|
|
|
),
|
|
|
|
SAMPLE_WALLET(
|
|
|
|
"input frown warm senior anxiety abuse yard prefer churn reject people glimpse govern glory crumble swallow verb laptop switch trophy inform friend permit purpose",
|
|
|
|
BlockHeight.new(
|
|
|
|
ZcashNetwork.Testnet,
|
|
|
|
1_330_190
|
|
|
|
),
|
|
|
|
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
|
|
|
|
),
|
|
|
|
DEV_WALLET(
|
|
|
|
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread",
|
|
|
|
BlockHeight.new(
|
|
|
|
ZcashNetwork.Testnet,
|
|
|
|
1_000_000
|
|
|
|
),
|
|
|
|
BlockHeight.new(ZcashNetwork.Mainnet, 991645)
|
|
|
|
),
|
|
|
|
ALICE(
|
|
|
|
"quantum whisper lion route fury lunar pelican image job client hundred sauce chimney barely life cliff spirit admit weekend message recipe trumpet impact kitten",
|
|
|
|
BlockHeight.new(
|
|
|
|
ZcashNetwork.Testnet,
|
|
|
|
1_330_190
|
|
|
|
),
|
|
|
|
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
|
|
|
|
),
|
|
|
|
BOB(
|
|
|
|
"canvas wine sugar acquire garment spy tongue odor hole cage year habit bullet make label human unit option top calm neutral try vocal arena",
|
|
|
|
BlockHeight.new(
|
|
|
|
ZcashNetwork.Testnet,
|
|
|
|
1_330_190
|
|
|
|
),
|
|
|
|
BlockHeight.new(ZcashNetwork.Mainnet, 1_000_000)
|
2022-09-20 05:25:56 -07:00
|
|
|
)
|
2021-04-09 19:29:29 -07:00
|
|
|
;
|
|
|
|
}
|
|
|
|
}
|