diff --git a/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/Backend.kt b/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/Backend.kt index eb68e94f..d4dbf199 100644 --- a/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/Backend.kt +++ b/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/Backend.kt @@ -30,6 +30,7 @@ interface Backend { suspend fun proposeShielding( account: Int, + shieldingThreshold: Long, memo: ByteArray? = byteArrayOf() ): ProposalUnsafe diff --git a/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/jni/RustBackend.kt b/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/jni/RustBackend.kt index 5cc71682..ec74a843 100644 --- a/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/jni/RustBackend.kt +++ b/backend-lib/src/main/java/cash/z/ecc/android/sdk/internal/jni/RustBackend.kt @@ -307,6 +307,7 @@ class RustBackend private constructor( override suspend fun proposeShielding( account: Int, + shieldingThreshold: Long, memo: ByteArray? ): ProposalUnsafe { return withContext(SdkDispatchers.DATABASE_IO) { @@ -314,6 +315,7 @@ class RustBackend private constructor( proposeShielding( dataDbFile.absolutePath, account, + shieldingThreshold, memo ?: ByteArray(0), networkId = networkId, useZip317Fees = IS_USE_ZIP_317_FEES @@ -584,6 +586,7 @@ class RustBackend private constructor( private external fun proposeShielding( dbDataPath: String, account: Int, + shieldingThreshold: Long, memo: ByteArray, networkId: Int, useZip317Fees: Boolean diff --git a/backend-lib/src/main/rust/lib.rs b/backend-lib/src/main/rust/lib.rs index 98c53545..b721f04e 100644 --- a/backend-lib/src/main/rust/lib.rs +++ b/backend-lib/src/main/rust/lib.rs @@ -1480,6 +1480,7 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh _: JClass<'local>, db_data: JString<'local>, account: jint, + shielding_threshold: jlong, memo: JByteArray<'local>, network_id: jint, use_zip317_fees: jboolean, @@ -1489,6 +1490,8 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh let network = parse_network(network_id as u32)?; let mut db_data = wallet_db(env, network, db_data)?; let account = account_id_from_jint(account)?; + let shielding_threshold = NonNegativeAmount::from_nonnegative_i64(shielding_threshold) + .map_err(|()| format_err!("Invalid shielding threshold, out of range"))?; let memo_bytes = env.convert_byte_array(memo).unwrap(); let min_confirmations = 0; @@ -1520,8 +1523,6 @@ pub extern "C" fn Java_cash_z_ecc_android_sdk_internal_jni_RustBackend_proposeSh let input_selector = zip317_helper(Some(MemoBytes::from(&memo)), use_zip317_fees); - let shielding_threshold = NonNegativeAmount::from_u64(100000).unwrap(); - let proposal = propose_shielding::<_, _, _, Infallible>( &mut db_data, &network, diff --git a/darkside-test-lib/src/androidTest/java/cash/z/ecc/android/sdk/darkside/test/TestWallet.kt b/darkside-test-lib/src/androidTest/java/cash/z/ecc/android/sdk/darkside/test/TestWallet.kt index 73ea19dd..65dd0f66 100644 --- a/darkside-test-lib/src/androidTest/java/cash/z/ecc/android/sdk/darkside/test/TestWallet.kt +++ b/darkside-test-lib/src/androidTest/java/cash/z/ecc/android/sdk/darkside/test/TestWallet.kt @@ -130,7 +130,7 @@ class TestWallet( synchronizer.getTransparentBalance(transparentAddress).let { walletBalance -> if (walletBalance.value > 0L) { synchronizer.createProposedTransactions( - synchronizer.proposeShielding(shieldedSpendingKey.account), + synchronizer.proposeShielding(shieldedSpendingKey.account, Zatoshi(100000)), shieldedSpendingKey ) } diff --git a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/getbalance/GetBalanceFragment.kt b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/getbalance/GetBalanceFragment.kt index f5ce17fe..9145ca9a 100644 --- a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/getbalance/GetBalanceFragment.kt +++ b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/demos/getbalance/GetBalanceFragment.kt @@ -47,6 +47,7 @@ class GetBalanceFragment : BaseDemoFragment() { reportTraceEvent(SyncBlockchainBenchmarkTrace.Event.BALANCE_SCREEN_END) } + @Suppress("MagicNumber") override fun onViewCreated( view: View, savedInstanceState: Bundle? @@ -68,7 +69,7 @@ class GetBalanceFragment : BaseDemoFragment() { ) sharedViewModel.synchronizerFlow.value?.let { synchronizer -> synchronizer.createProposedTransactions( - synchronizer.proposeShielding(usk.account), + synchronizer.proposeShielding(usk.account, Zatoshi(100000)), usk ) } diff --git a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt index 91d7f6fc..417bd083 100644 --- a/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt +++ b/demo-app/src/main/java/cash/z/ecc/android/sdk/demoapp/ui/screen/home/viewmodel/WalletViewModel.kt @@ -217,6 +217,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application) * * Observe the result via [sendState]. */ + @Suppress("MagicNumber") fun shieldFunds() { if (sendState.value is SendState.Sending) { return @@ -230,7 +231,7 @@ class WalletViewModel(application: Application) : AndroidViewModel(application) val spendingKey = spendingKey.filterNotNull().first() kotlin.runCatching { synchronizer.createProposedTransactions( - synchronizer.proposeShielding(spendingKey.account), + synchronizer.proposeShielding(spendingKey.account, Zatoshi(100000)), spendingKey ) } diff --git a/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/util/TestWallet.kt b/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/util/TestWallet.kt index f6d57a67..a6ef3e45 100644 --- a/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/util/TestWallet.kt +++ b/sdk-lib/src/androidTest/java/cash/z/ecc/android/sdk/util/TestWallet.kt @@ -132,7 +132,10 @@ class TestWallet( Twig.debug { "FOUND utxo balance of total: $walletBalance" } if (walletBalance.value > 0L) { - synchronizer.createProposedTransactions(synchronizer.proposeShielding(spendingKey.account), spendingKey) + synchronizer.createProposedTransactions( + synchronizer.proposeShielding(spendingKey.account, Zatoshi(100000)), + spendingKey + ) } } diff --git a/sdk-lib/src/androidTest/java/cash/z/ecc/fixture/FakeRustBackend.kt b/sdk-lib/src/androidTest/java/cash/z/ecc/fixture/FakeRustBackend.kt index 631c8d98..90efd678 100644 --- a/sdk-lib/src/androidTest/java/cash/z/ecc/fixture/FakeRustBackend.kt +++ b/sdk-lib/src/androidTest/java/cash/z/ecc/fixture/FakeRustBackend.kt @@ -88,6 +88,7 @@ internal class FakeRustBackend( override suspend fun proposeShielding( account: Int, + shieldingThreshold: Long, memo: ByteArray? ): ProposalUnsafe { TODO("Not yet implemented") diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt index 2300d173..91d4eac0 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/SdkSynchronizer.kt @@ -569,8 +569,9 @@ class SdkSynchronizer private constructor( @Throws(TransactionEncoderException::class) override suspend fun proposeShielding( account: Account, + shieldingThreshold: Zatoshi, memo: String - ): Proposal = txManager.proposeShielding(account, memo) + ): Proposal = txManager.proposeShielding(account, shieldingThreshold, memo) @Throws(TransactionEncoderException::class) override suspend fun createProposedTransactions( @@ -635,7 +636,7 @@ class SdkSynchronizer private constructor( message = "Upcoming SDK 2.1 will create multiple transactions at once for some recipients.", replaceWith = ReplaceWith( - "createProposedTransactions(proposeShielding(usk.account, memo), usk)" + "createProposedTransactions(proposeShielding(usk.account, shieldingThreshold, memo), usk)" ) ) @Throws(TransactionEncoderException::class, TransactionSubmitException::class) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt index e8620f4e..914b7ecc 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/Synchronizer.kt @@ -190,10 +190,13 @@ interface Synchronizer { * Creates a proposal for shielding any transparent funds received by the given account. * * @param account the account for which to shield funds. + * @param shieldingThreshold the minimum transparent balance required before a + * proposal will be created. * @param memo the optional memo to include as part of the proposal's transactions. */ suspend fun proposeShielding( account: Account, + shieldingThreshold: Zatoshi, memo: String = ZcashSdk.DEFAULT_SHIELD_FUNDS_MEMO_PREFIX ): Proposal @@ -244,7 +247,7 @@ interface Synchronizer { message = "Upcoming SDK 2.1 will create multiple transactions at once for some recipients.", replaceWith = ReplaceWith( - "createProposedTransactions(proposeShielding(usk.account, memo), usk)" + "createProposedTransactions(proposeShielding(usk.account, shieldingThreshold, memo), usk)" ) ) suspend fun shieldFunds( diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackend.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackend.kt index fa36afa4..a8a3a272 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackend.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackend.kt @@ -34,6 +34,7 @@ internal interface TypesafeBackend { suspend fun proposeShielding( account: Account, + shieldingThreshold: Long, memo: ByteArray? = byteArrayOf() ): Proposal diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackendImpl.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackendImpl.kt index d519e677..58afb413 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackendImpl.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/TypesafeBackendImpl.kt @@ -53,11 +53,13 @@ internal class TypesafeBackendImpl(private val backend: Backend) : TypesafeBacke override suspend fun proposeShielding( account: Account, + shieldingThreshold: Long, memo: ByteArray? ): Proposal = Proposal.fromUnsafe( backend.proposeShielding( account.value, + shieldingThreshold, memo ) ) diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManager.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManager.kt index 7552c730..0e4ca96b 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManager.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManager.kt @@ -56,10 +56,13 @@ internal interface OutboundTransactionManager { * Creates a proposal for shielding any transparent funds received by the given account. * * @param account the account for which to shield funds. + * @param shieldingThreshold the minimum transparent balance required before a + * proposal will be created. * @param memo the optional memo to include as part of the proposal's transactions. */ suspend fun proposeShielding( account: Account, + shieldingThreshold: Zatoshi, memo: String ): Proposal diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManagerImpl.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManagerImpl.kt index c0c4adbd..3d5143b3 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManagerImpl.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/OutboundTransactionManagerImpl.kt @@ -52,8 +52,9 @@ internal class OutboundTransactionManagerImpl( override suspend fun proposeShielding( account: Account, + shieldingThreshold: Zatoshi, memo: String - ): Proposal = encoder.proposeShielding(account, memo.toByteArray()) + ): Proposal = encoder.proposeShielding(account, shieldingThreshold, memo.toByteArray()) override suspend fun createProposedTransactions( proposal: Proposal, diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoder.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoder.kt index 437781e4..cd1845d4 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoder.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoder.kt @@ -61,10 +61,13 @@ internal interface TransactionEncoder { * Creates a proposal for shielding any transparent funds sent to the given account. * * @param account the account for which to shield funds. + * @param shieldingThreshold the minimum transparent balance required before a + * proposal will be created. * @param memo the optional memo to include as part of the proposal's transactions. */ suspend fun proposeShielding( account: Account, + shieldingThreshold: Zatoshi, memo: ByteArray? = byteArrayOf() ): Proposal diff --git a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoderImpl.kt b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoderImpl.kt index 34e82718..9509dca3 100644 --- a/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoderImpl.kt +++ b/sdk-lib/src/main/java/cash/z/ecc/android/sdk/internal/transaction/TransactionEncoderImpl.kt @@ -96,11 +96,12 @@ internal class TransactionEncoderImpl( override suspend fun proposeShielding( account: Account, + shieldingThreshold: Zatoshi, memo: ByteArray? ): Proposal { @Suppress("TooGenericExceptionCaught") return try { - backend.proposeShielding(account, memo) + backend.proposeShielding(account, shieldingThreshold.value, memo) } catch (t: Throwable) { // TODO [#680]: if this error matches: Insufficient balance (have 0, need 1000 including fee) // then consider custom error that says no UTXOs existed to shield @@ -229,6 +230,7 @@ internal class TransactionEncoderImpl( } } + @Suppress("MagicNumber") private suspend fun createShieldingSpend( usk: UnifiedSpendingKey, memo: ByteArray? = byteArrayOf() @@ -237,7 +239,7 @@ internal class TransactionEncoderImpl( return try { saplingParamTool.ensureParams(saplingParamTool.properties.paramsDirectory) Twig.debug { "params exist! attempting to shield..." } - val proposal = backend.proposeShielding(usk.account, memo) + val proposal = backend.proposeShielding(usk.account, 100000, memo) backend.createProposedTransaction(proposal, usk) } catch (t: Throwable) { // TODO [#680]: if this error matches: Insufficient balance (have 0, need 1000 including fee)