Replace `Synchronizer.getAddress()` with `Synchronizer.getCurrentAddress()`
The SDK now exposes UAs primarily, with additional methods for obtaining corresponding Sapling and transparent addresses for legacy compatibility. The `Account` DAO is also fixed to use the migrated `accounts` table format. The demo app now shows the current UA and the legacy Sapling and transparent addresses. Closes zcash/zcash-android-wallet-sdk#677.
This commit is contained in:
parent
f69cacb9e6
commit
597cc43886
|
@ -5,6 +5,9 @@ Change Log
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- `cash.z.ecc.android.sdk`:
|
- `cash.z.ecc.android.sdk`:
|
||||||
|
- `Synchronizer.getCurrentAddress`
|
||||||
|
- `Synchronizer.getLegacySaplingAddress`
|
||||||
|
- `Synchronizer.getLegacyTransparentAddress`
|
||||||
- `Synchronizer.isValidUnifiedAddr`
|
- `Synchronizer.isValidUnifiedAddr`
|
||||||
- `cash.z.ecc.android.sdk.model`:
|
- `cash.z.ecc.android.sdk.model`:
|
||||||
- `FirstClassByteArray`
|
- `FirstClassByteArray`
|
||||||
|
@ -37,6 +40,10 @@ Change Log
|
||||||
all transparent secret keys within an account) instead of a transparent secret key.
|
all transparent secret keys within an account) instead of a transparent secret key.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
- `cash.z.ecc.android.sdk`:
|
||||||
|
- `Synchronizer.getAddress` (use `Synchronizer.getCurrentAddress` instead).
|
||||||
|
- `Synchronizer.getShieldedAddress` (use `Synchronizer.getLegacySaplingAddress` instead).
|
||||||
|
- `Synchronizer.getTransparentAddress` (use `Synchronizer.getLegacyTransparentAddress` instead).
|
||||||
- `cash.z.ecc.android.sdk.type.UnifiedViewingKey`
|
- `cash.z.ecc.android.sdk.type.UnifiedViewingKey`
|
||||||
- This type had a bug where the `extpub` field actually was storing a plain transparent
|
- This type had a bug where the `extpub` field actually was storing a plain transparent
|
||||||
public key, and not the extended public key as intended. This made it incompatible
|
public key, and not the extended public key as intended. This made it incompatible
|
||||||
|
|
|
@ -76,7 +76,7 @@ class SampleCodeTest {
|
||||||
// ///////////////////////////////////////////////////
|
// ///////////////////////////////////////////////////
|
||||||
// Get Address
|
// Get Address
|
||||||
@Test fun getAddress() = runBlocking {
|
@Test fun getAddress() = runBlocking {
|
||||||
val address = synchronizer.getAddress()
|
val address = synchronizer.getCurrentAddress()
|
||||||
assertFalse(address.isBlank())
|
assertFalse(address.isBlank())
|
||||||
log("Address: $address")
|
log("Address: $address")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,15 @@ import android.view.LayoutInflater
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import cash.z.ecc.android.bip39.Mnemonics
|
import cash.z.ecc.android.bip39.Mnemonics
|
||||||
import cash.z.ecc.android.bip39.toSeed
|
import cash.z.ecc.android.bip39.toSeed
|
||||||
|
import cash.z.ecc.android.sdk.Initializer
|
||||||
|
import cash.z.ecc.android.sdk.Synchronizer
|
||||||
import cash.z.ecc.android.sdk.demoapp.BaseDemoFragment
|
import cash.z.ecc.android.sdk.demoapp.BaseDemoFragment
|
||||||
import cash.z.ecc.android.sdk.demoapp.databinding.FragmentGetAddressBinding
|
import cash.z.ecc.android.sdk.demoapp.databinding.FragmentGetAddressBinding
|
||||||
import cash.z.ecc.android.sdk.demoapp.ext.requireApplicationContext
|
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.model.LightWalletEndpoint
|
||||||
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
import cash.z.ecc.android.sdk.model.defaultForNetwork
|
||||||
import cash.z.ecc.android.sdk.tool.DerivationTool
|
import cash.z.ecc.android.sdk.tool.DerivationTool
|
||||||
import cash.z.ecc.android.sdk.type.UnifiedFullViewingKey
|
import cash.z.ecc.android.sdk.type.UnifiedFullViewingKey
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -21,6 +25,7 @@ import kotlinx.coroutines.runBlocking
|
||||||
*/
|
*/
|
||||||
class GetAddressFragment : BaseDemoFragment<FragmentGetAddressBinding>() {
|
class GetAddressFragment : BaseDemoFragment<FragmentGetAddressBinding>() {
|
||||||
|
|
||||||
|
private lateinit var synchronizer: Synchronizer
|
||||||
private lateinit var viewingKey: UnifiedFullViewingKey
|
private lateinit var viewingKey: UnifiedFullViewingKey
|
||||||
private lateinit var seed: ByteArray
|
private lateinit var seed: ByteArray
|
||||||
|
|
||||||
|
@ -36,28 +41,46 @@ class GetAddressFragment : BaseDemoFragment<FragmentGetAddressBinding>() {
|
||||||
// have the seed stored
|
// have the seed stored
|
||||||
seed = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
seed = Mnemonics.MnemonicCode(seedPhrase).toSeed()
|
||||||
|
|
||||||
// the derivation tool can be used for generating keys and addresses
|
// converting seed into viewingKey
|
||||||
viewingKey = runBlocking {
|
viewingKey = runBlocking {
|
||||||
DerivationTool.deriveUnifiedFullViewingKeys(
|
DerivationTool.deriveUnifiedFullViewingKeys(
|
||||||
seed,
|
seed,
|
||||||
ZcashNetwork.fromResources(requireApplicationContext())
|
ZcashNetwork.fromResources(requireApplicationContext())
|
||||||
).first()
|
).first()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// using the ViewingKey to initialize
|
||||||
|
runBlocking {
|
||||||
|
Initializer.new(requireApplicationContext(), null) {
|
||||||
|
val network = ZcashNetwork.fromResources(requireApplicationContext())
|
||||||
|
it.newWallet(
|
||||||
|
viewingKey,
|
||||||
|
network = network,
|
||||||
|
lightWalletEndpoint = LightWalletEndpoint.defaultForNetwork(network)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.let { initializer ->
|
||||||
|
synchronizer = Synchronizer.newBlocking(initializer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun displayAddress() {
|
private fun displayAddress() {
|
||||||
// a full fledged app would just get the address from the synchronizer
|
|
||||||
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
|
viewLifecycleOwner.lifecycleScope.launchWhenStarted {
|
||||||
val uaddress = DerivationTool.deriveUnifiedAddress(
|
val uaddress = synchronizer.getCurrentAddress()
|
||||||
seed,
|
val sapling = synchronizer.getLegacySaplingAddress()
|
||||||
ZcashNetwork.fromResources(requireApplicationContext())
|
val transparent = synchronizer.getLegacyTransparentAddress()
|
||||||
)
|
binding.textInfo.text = """
|
||||||
binding.textInfo.text = "address:\n$uaddress"
|
Unified Address:
|
||||||
}
|
$uaddress
|
||||||
}
|
|
||||||
|
|
||||||
// TODO [#677]: Show an example with the synchronizer
|
Legacy Sapling:
|
||||||
// TODO [#677]: https://github.com/zcash/zcash-android-wallet-sdk/issues/677
|
$sapling
|
||||||
|
|
||||||
|
Legacy transparent:
|
||||||
|
$transparent
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Android Lifecycle overrides
|
// Android Lifecycle overrides
|
||||||
|
|
|
@ -2028,6 +2028,7 @@ dependencies = [
|
||||||
"schemer",
|
"schemer",
|
||||||
"secp256k1",
|
"secp256k1",
|
||||||
"secrecy",
|
"secrecy",
|
||||||
|
"zcash_address",
|
||||||
"zcash_client_backend",
|
"zcash_client_backend",
|
||||||
"zcash_client_sqlite",
|
"zcash_client_sqlite",
|
||||||
"zcash_primitives",
|
"zcash_primitives",
|
||||||
|
|
|
@ -21,6 +21,7 @@ log-panics = "2.0.0"
|
||||||
schemer = "0.2"
|
schemer = "0.2"
|
||||||
secp256k1 = "0.21"
|
secp256k1 = "0.21"
|
||||||
secrecy = "0.8"
|
secrecy = "0.8"
|
||||||
|
zcash_address = "0.1"
|
||||||
zcash_client_backend = { version = "0.5", features = ["transparent-inputs", "unstable"] }
|
zcash_client_backend = { version = "0.5", features = ["transparent-inputs", "unstable"] }
|
||||||
zcash_client_sqlite = { version = "0.3", features = ["transparent-inputs", "unstable"] }
|
zcash_client_sqlite = { version = "0.3", features = ["transparent-inputs", "unstable"] }
|
||||||
zcash_primitives = "0.7"
|
zcash_primitives = "0.7"
|
||||||
|
@ -30,6 +31,7 @@ zcash_proofs = "0.7"
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
group = { git = "https://github.com/zkcrypto/group.git", rev = "a7f3ceb2373e9fe536996f7b4d55c797f3e667f0" }
|
group = { git = "https://github.com/zkcrypto/group.git", rev = "a7f3ceb2373e9fe536996f7b4d55c797f3e667f0" }
|
||||||
orchard = { git = 'https://github.com/zcash/orchard.git', rev='f206b3f5d4e31bba75d03d9d03d5fa25825a9384' }
|
orchard = { git = 'https://github.com/zcash/orchard.git', rev='f206b3f5d4e31bba75d03d9d03d5fa25825a9384' }
|
||||||
|
zcash_address = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||||
zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||||
zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||||
zcash_note_encryption = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
zcash_note_encryption = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffadf5a0120a74d70d281974d079ccd58c600' }
|
||||||
|
@ -38,6 +40,7 @@ zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffad
|
||||||
|
|
||||||
## Uncomment this to test librustzcash changes locally
|
## Uncomment this to test librustzcash changes locally
|
||||||
#[patch.crates-io]
|
#[patch.crates-io]
|
||||||
|
#zcash_address = { path = '../../clones/librustzcash/components/zcash_address' }
|
||||||
#zcash_client_backend = { path = '../../clones/librustzcash/zcash_client_backend' }
|
#zcash_client_backend = { path = '../../clones/librustzcash/zcash_client_backend' }
|
||||||
#zcash_client_sqlite = { path = '../../clones/librustzcash/zcash_client_sqlite' }
|
#zcash_client_sqlite = { path = '../../clones/librustzcash/zcash_client_sqlite' }
|
||||||
#zcash_primitives = { path = '../../clones/librustzcash/zcash_primitives' }
|
#zcash_primitives = { path = '../../clones/librustzcash/zcash_primitives' }
|
||||||
|
@ -45,6 +48,7 @@ zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='774ffad
|
||||||
|
|
||||||
## Uncomment this to test someone else's librustzcash changes in a branch
|
## Uncomment this to test someone else's librustzcash changes in a branch
|
||||||
#[patch.crates-io]
|
#[patch.crates-io]
|
||||||
|
#zcash_address = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
||||||
#zcash_client_backend = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
#zcash_client_backend = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
||||||
#zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
#zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
||||||
#zcash_primitives = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
#zcash_primitives = { git = "https://github.com/zcash/librustzcash", branch = "branch-name" }
|
||||||
|
|
|
@ -357,7 +357,7 @@ class SdkSynchronizer internal constructor(
|
||||||
|
|
||||||
suspend fun refreshUtxos() {
|
suspend fun refreshUtxos() {
|
||||||
twig("refreshing utxos", -1)
|
twig("refreshing utxos", -1)
|
||||||
refreshUtxos(getTransparentAddress())
|
refreshUtxos(getLegacyTransparentAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -379,7 +379,7 @@ class SdkSynchronizer internal constructor(
|
||||||
|
|
||||||
suspend fun refreshTransparentBalance() {
|
suspend fun refreshTransparentBalance() {
|
||||||
twig("refreshing transparent balance")
|
twig("refreshing transparent balance")
|
||||||
_transparentBalances.value = processor.getUtxoCacheBalance(getTransparentAddress())
|
_transparentBalances.value = processor.getUtxoCacheBalance(getLegacyTransparentAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun isValidAddress(address: String): Boolean {
|
suspend fun isValidAddress(address: String): Boolean {
|
||||||
|
@ -637,20 +637,22 @@ class SdkSynchronizer internal constructor(
|
||||||
|
|
||||||
override suspend fun cancelSpend(pendingId: Long) = txManager.cancel(pendingId)
|
override suspend fun cancelSpend(pendingId: Long) = txManager.cancel(pendingId)
|
||||||
|
|
||||||
// TODO(str4d): Rename this to getCurrentAddress (and remove/add in changelog).
|
|
||||||
/**
|
/**
|
||||||
* Returns the current Unified Address for this account.
|
* Returns the current Unified Address for this account.
|
||||||
*/
|
*/
|
||||||
override suspend fun getAddress(accountId: Int): String = getShieldedAddress(accountId)
|
override suspend fun getCurrentAddress(accountId: Int): String =
|
||||||
|
processor.getCurrentAddress(accountId)
|
||||||
|
|
||||||
override suspend fun getShieldedAddress(accountId: Int): String =
|
/**
|
||||||
processor.getShieldedAddress(accountId)
|
* Returns the legacy Sapling address corresponding to the current Unified Address for this account.
|
||||||
|
*/
|
||||||
|
override suspend fun getLegacySaplingAddress(accountId: Int): String =
|
||||||
|
processor.getLegacySaplingAddress(accountId)
|
||||||
|
|
||||||
// TODO(str4d): Change this to do the right thing.
|
|
||||||
/**
|
/**
|
||||||
* Returns the legacy transparent address corresponding to the current Unified Address for this account.
|
* Returns the legacy transparent address corresponding to the current Unified Address for this account.
|
||||||
*/
|
*/
|
||||||
override suspend fun getTransparentAddress(accountId: Int): String =
|
override suspend fun getLegacyTransparentAddress(accountId: Int): String =
|
||||||
processor.getTransparentAddress(accountId)
|
processor.getTransparentAddress(accountId)
|
||||||
|
|
||||||
override fun sendToAddress(
|
override fun sendToAddress(
|
||||||
|
@ -692,7 +694,7 @@ class SdkSynchronizer internal constructor(
|
||||||
val tAddr =
|
val tAddr =
|
||||||
DerivationTool.deriveTransparentAddressFromAccountPrivateKey(transparentAccountPrivateKey, network)
|
DerivationTool.deriveTransparentAddressFromAccountPrivateKey(transparentAccountPrivateKey, network)
|
||||||
val tBalance = processor.getUtxoCacheBalance(tAddr)
|
val tBalance = processor.getUtxoCacheBalance(tAddr)
|
||||||
val zAddr = getAddress(0)
|
val zAddr = getCurrentAddress(0)
|
||||||
|
|
||||||
// Emit the placeholder transaction, then switch to monitoring the database
|
// Emit the placeholder transaction, then switch to monitoring the database
|
||||||
txManager.initSpend(tBalance.available, zAddr, memo, 0).let { placeHolderTx ->
|
txManager.initSpend(tBalance.available, zAddr, memo, 0).let { placeHolderTx ->
|
||||||
|
|
|
@ -5,7 +5,6 @@ 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.BlockHeight
|
import cash.z.ecc.android.sdk.model.BlockHeight
|
||||||
import cash.z.ecc.android.sdk.model.UnifiedSpendingKey
|
|
||||||
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.model.ZcashNetwork
|
import cash.z.ecc.android.sdk.model.ZcashNetwork
|
||||||
|
@ -188,35 +187,34 @@ interface Synchronizer {
|
||||||
// suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey
|
// suspend fun createAccount(seed: ByteArray): UnifiedSpendingKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the shielded address for the given account. This is syntactic sugar for
|
* Gets the current unified address for the given account.
|
||||||
* [getShieldedAddress] because we use z-addrs by default.
|
|
||||||
*
|
*
|
||||||
* @param accountId the optional accountId whose address is of interest. By default, the first
|
* @param accountId the optional accountId whose address is of interest. By default, the first
|
||||||
* account is used.
|
* account is used.
|
||||||
*
|
*
|
||||||
* @return the shielded address for the given account.
|
* @return the current unified address for the given account.
|
||||||
*/
|
*/
|
||||||
suspend fun getAddress(accountId: Int = 0) = getShieldedAddress(accountId)
|
suspend fun getCurrentAddress(accountId: Int = 0): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the shielded address for the given account.
|
* Gets the legacy Sapling address corresponding to the current unified address for the given account.
|
||||||
*
|
*
|
||||||
* @param accountId the optional accountId whose address is of interest. By default, the first
|
* @param accountId the optional accountId whose address is of interest. By default, the first
|
||||||
* account is used.
|
* account is used.
|
||||||
*
|
*
|
||||||
* @return the shielded address for the given account.
|
* @return a legacy Sapling address for the given account.
|
||||||
*/
|
*/
|
||||||
suspend fun getShieldedAddress(accountId: Int = 0): String
|
suspend fun getLegacySaplingAddress(accountId: Int = 0): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the transparent address for the given account.
|
* Gets the legacy transparent address corresponding to the current unified address for the given account.
|
||||||
*
|
*
|
||||||
* @param accountId the optional accountId whose address is of interest. By default, the first
|
* @param accountId the optional accountId whose address is of interest. By default, the first
|
||||||
* account is used.
|
* account is used.
|
||||||
*
|
*
|
||||||
* @return the address for the given account.
|
* @return a legacy transparent address for the given account.
|
||||||
*/
|
*/
|
||||||
suspend fun getTransparentAddress(accountId: Int = 0): String
|
suspend fun getLegacyTransparentAddress(accountId: Int = 0): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends zatoshi.
|
* Sends zatoshi.
|
||||||
|
|
|
@ -1023,17 +1023,34 @@ class CompactBlockProcessor internal constructor(
|
||||||
rustBackend.createAccount(seed)
|
rustBackend.createAccount(seed)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get address corresponding to the given account for this wallet.
|
* Get the current unified address for the given wallet account.
|
||||||
*
|
*
|
||||||
* @return the address of this wallet.
|
* @return the current unified address of this account.
|
||||||
*/
|
*/
|
||||||
suspend fun getShieldedAddress(accountId: Int = 0) =
|
suspend fun getCurrentAddress(accountId: Int = 0) =
|
||||||
repository.getAccount(accountId)?.rawShieldedAddress
|
rustBackend.getCurrentAddress(accountId)
|
||||||
?: throw InitializerException.MissingAddressException("shielded")
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the legacy Sapling address corresponding to the current unified address for the given wallet account.
|
||||||
|
*
|
||||||
|
* @return a Sapling address.
|
||||||
|
*/
|
||||||
|
suspend fun getLegacySaplingAddress(accountId: Int = 0) =
|
||||||
|
rustBackend.getSaplingReceiver(
|
||||||
|
rustBackend.getCurrentAddress(accountId)
|
||||||
|
)
|
||||||
|
?: throw InitializerException.MissingAddressException("legacy Sapling")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the legacy transparent address corresponding to the current unified address for the given wallet account.
|
||||||
|
*
|
||||||
|
* @return a transparent address.
|
||||||
|
*/
|
||||||
suspend fun getTransparentAddress(accountId: Int = 0) =
|
suspend fun getTransparentAddress(accountId: Int = 0) =
|
||||||
repository.getAccount(accountId)?.rawTransparentAddress
|
rustBackend.getTransparentReceiver(
|
||||||
?: throw InitializerException.MissingAddressException("transparent")
|
rustBackend.getCurrentAddress(accountId)
|
||||||
|
)
|
||||||
|
?: throw InitializerException.MissingAddressException("legacy transparent")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the latest balance info. Defaults to the first account.
|
* Calculates the latest balance info. Defaults to the first account.
|
||||||
|
|
|
@ -12,10 +12,5 @@ data class Account(
|
||||||
val account: Int? = 0,
|
val account: Int? = 0,
|
||||||
|
|
||||||
@ColumnInfo(name = "ufvk")
|
@ColumnInfo(name = "ufvk")
|
||||||
val unifiedFullViewingKey: String? = "",
|
val unifiedFullViewingKey: String? = ""
|
||||||
|
|
||||||
val address: String? = "",
|
|
||||||
|
|
||||||
@ColumnInfo(name = "transparent_address")
|
|
||||||
val transparentAddress: String? = ""
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -231,17 +231,6 @@ interface SentDao {
|
||||||
interface AccountDao {
|
interface AccountDao {
|
||||||
@Query("SELECT COUNT(account) FROM accounts")
|
@Query("SELECT COUNT(account) FROM accounts")
|
||||||
suspend fun count(): Int
|
suspend fun count(): Int
|
||||||
|
|
||||||
@Query(
|
|
||||||
"""
|
|
||||||
SELECT account AS accountId,
|
|
||||||
transparent_address AS rawTransparentAddress,
|
|
||||||
address AS rawShieldedAddress
|
|
||||||
FROM accounts
|
|
||||||
WHERE account = :id
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
suspend fun findAccountById(id: Int): UnifiedAddressAccount?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -94,8 +94,6 @@ internal class PagedTransactionRepository private constructor(
|
||||||
|
|
||||||
override suspend fun count() = transactions.count()
|
override suspend fun count() = transactions.count()
|
||||||
|
|
||||||
override suspend fun getAccount(accountId: Int) = accounts.findAccountById(accountId)
|
|
||||||
|
|
||||||
override suspend fun getAccountCount() = accounts.count()
|
override suspend fun getAccountCount() = accounts.count()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -85,8 +85,6 @@ interface TransactionRepository {
|
||||||
|
|
||||||
suspend fun count(): Int
|
suspend fun count(): Int
|
||||||
|
|
||||||
suspend fun getAccount(accountId: Int): UnifiedAddressAccount?
|
|
||||||
|
|
||||||
suspend fun getAccountCount(): Int
|
suspend fun getAccountCount(): Int
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -109,12 +109,9 @@ internal class RustBackend private constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getTransparentAddress(account: Int, index: Int): String {
|
override fun getTransparentReceiver(ua: String) = getTransparentReceiverForUnifiedAddress(ua)
|
||||||
throw NotImplementedError(
|
|
||||||
"TODO: implement this at the zcash_client_sqlite level. But for now, use " +
|
override fun getSaplingReceiver(ua: String) = getSaplingReceiverForUnifiedAddress(ua)
|
||||||
"DerivationTool, instead to derive addresses from seeds"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getBalance(account: Int): Zatoshi {
|
override suspend fun getBalance(account: Int): Zatoshi {
|
||||||
val longValue = withContext(SdkDispatchers.DATABASE_IO) {
|
val longValue = withContext(SdkDispatchers.DATABASE_IO) {
|
||||||
|
@ -426,6 +423,12 @@ internal class RustBackend private constructor(
|
||||||
networkId: Int
|
networkId: Int
|
||||||
): String
|
): String
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun getTransparentReceiverForUnifiedAddress(ua: String): String?
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
private external fun getSaplingReceiverForUnifiedAddress(ua: String): String?
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun isValidShieldedAddress(addr: String, networkId: Int): Boolean
|
private external fun isValidShieldedAddress(addr: String, networkId: Int): Boolean
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,9 @@ internal interface RustBackendWelding {
|
||||||
|
|
||||||
suspend fun getCurrentAddress(account: Int = 0): String
|
suspend fun getCurrentAddress(account: Int = 0): String
|
||||||
|
|
||||||
suspend fun getTransparentAddress(account: Int = 0, index: Int = 0): String
|
fun getTransparentReceiver(ua: String): String?
|
||||||
|
|
||||||
|
fun getSaplingReceiver(ua: String): String?
|
||||||
|
|
||||||
suspend fun getBalance(account: Int = 0): Zatoshi
|
suspend fun getBalance(account: Int = 0): Zatoshi
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,10 @@ use log::Level;
|
||||||
use schemer::MigratorError;
|
use schemer::MigratorError;
|
||||||
use secp256k1::PublicKey;
|
use secp256k1::PublicKey;
|
||||||
use secrecy::SecretVec;
|
use secrecy::SecretVec;
|
||||||
|
use zcash_address::{ToAddress, ZcashAddress};
|
||||||
use zcash_client_backend::keys::UnifiedSpendingKey;
|
use zcash_client_backend::keys::UnifiedSpendingKey;
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
address::RecipientAddress,
|
address::{RecipientAddress, UnifiedAddress},
|
||||||
data_api::{
|
data_api::{
|
||||||
chain::{scan_cached_blocks, validate_chain},
|
chain::{scan_cached_blocks, validate_chain},
|
||||||
error::Error,
|
error::Error,
|
||||||
|
@ -490,6 +491,91 @@ pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getCurrentA
|
||||||
unwrap_exc_or(&env, res, ptr::null_mut())
|
unwrap_exc_or(&env, res, ptr::null_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UnifiedAddressParser(UnifiedAddress);
|
||||||
|
|
||||||
|
impl zcash_address::TryFromRawAddress for UnifiedAddressParser {
|
||||||
|
type Error = failure::Error;
|
||||||
|
|
||||||
|
fn try_from_raw_unified(
|
||||||
|
data: zcash_address::unified::Address,
|
||||||
|
) -> Result<Self, zcash_address::ConversionError<Self::Error>> {
|
||||||
|
data.try_into()
|
||||||
|
.map(UnifiedAddressParser)
|
||||||
|
.map_err(|e| format_err!("Invalid Unified Address: {}", e).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the transparent receiver within the given Unified Address, if any.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getTransparentReceiverForUnifiedAddress(
|
||||||
|
env: JNIEnv<'_>,
|
||||||
|
_: JClass<'_>,
|
||||||
|
ua: JString<'_>,
|
||||||
|
) -> jstring {
|
||||||
|
let res = panic::catch_unwind(|| {
|
||||||
|
let ua_str = utils::java_string_to_rust(&env, ua);
|
||||||
|
|
||||||
|
let (network, ua) = match ZcashAddress::try_from_encoded(&ua_str) {
|
||||||
|
Ok(addr) => addr
|
||||||
|
.convert::<(_, UnifiedAddressParser)>()
|
||||||
|
.map_err(|e| format_err!("Not a Unified Address: {}", e)),
|
||||||
|
Err(e) => return Err(format_err!("Invalid Zcash address: {}", e)),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if let Some(taddr) = ua.0.transparent() {
|
||||||
|
let taddr = match taddr {
|
||||||
|
TransparentAddress::PublicKey(data) => {
|
||||||
|
ZcashAddress::from_transparent_p2pkh(network, *data)
|
||||||
|
}
|
||||||
|
TransparentAddress::Script(data) => {
|
||||||
|
ZcashAddress::from_transparent_p2sh(network, *data)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let output = env
|
||||||
|
.new_string(taddr.encode())
|
||||||
|
.expect("Couldn't create Java string!");
|
||||||
|
Ok(output.into_inner())
|
||||||
|
} else {
|
||||||
|
Err(format_err!(
|
||||||
|
"Unified Address doesn't contain a transparent receiver"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
unwrap_exc_or(&env, res, ptr::null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the Sapling receiver within the given Unified Address, if any.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_getSaplingReceiverForUnifiedAddress(
|
||||||
|
env: JNIEnv<'_>,
|
||||||
|
_: JClass<'_>,
|
||||||
|
ua: JString<'_>,
|
||||||
|
) -> jstring {
|
||||||
|
let res = panic::catch_unwind(|| {
|
||||||
|
let ua_str = utils::java_string_to_rust(&env, ua);
|
||||||
|
|
||||||
|
let (network, ua) = match ZcashAddress::try_from_encoded(&ua_str) {
|
||||||
|
Ok(addr) => addr
|
||||||
|
.convert::<(_, UnifiedAddressParser)>()
|
||||||
|
.map_err(|e| format_err!("Not a Unified Address: {}", e)),
|
||||||
|
Err(e) => return Err(format_err!("Invalid Zcash address: {}", e)),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if let Some(addr) = ua.0.sapling() {
|
||||||
|
let output = env
|
||||||
|
.new_string(ZcashAddress::from_sapling(network, addr.to_bytes()).encode())
|
||||||
|
.expect("Couldn't create Java string!");
|
||||||
|
Ok(output.into_inner())
|
||||||
|
} else {
|
||||||
|
Err(format_err!(
|
||||||
|
"Unified Address doesn't contain a Sapling receiver"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
unwrap_exc_or(&env, res, ptr::null_mut())
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShieldedAddress(
|
pub unsafe extern "C" fn Java_cash_z_ecc_android_sdk_jni_RustBackend_isValidShieldedAddress(
|
||||||
env: JNIEnv<'_>,
|
env: JNIEnv<'_>,
|
||||||
|
|
Loading…
Reference in New Issue