Adjust `Synchronizer.proposeShielding` API
- Returns `null` when there are no funds to shield or the shielding threshold is not met. - Throws an exception if there are funds to shield in more than one transparent receiver within the account. - Has an optional parameter for specifying which transparent receiver to shield funds from. This commit only alters the API to support the above; the functional changes require modifying the FFI and Rust backend, which will happen in a separate commit.
This commit is contained in:
parent
7508fce6b6
commit
fffbd857fc
|
@ -619,8 +619,13 @@ actor ZcashRustBackend: ZcashRustBackendWelding {
|
|||
func proposeShielding(
|
||||
account: Int32,
|
||||
memo: MemoBytes?,
|
||||
shieldingThreshold: Zatoshi
|
||||
) async throws -> FfiProposal {
|
||||
shieldingThreshold: Zatoshi,
|
||||
transparentReceiver: String?
|
||||
) async throws -> FfiProposal? {
|
||||
if transparentReceiver != nil {
|
||||
throw ZcashError.rustScanBlocks("TODO: Implement transparentReceiver support in FFI")
|
||||
}
|
||||
|
||||
globalDBLock.lock()
|
||||
let proposal = zcashlc_propose_shielding(
|
||||
dbData.0,
|
||||
|
|
|
@ -212,14 +212,22 @@ protocol ZcashRustBackendWelding {
|
|||
/// that can then be authorized and made ready for submission to the network with
|
||||
/// `createProposedTransaction`.
|
||||
///
|
||||
/// Returns the proposal, or `nil` if the transparent balance that would be shielded
|
||||
/// is zero or below `shieldingThreshold`.
|
||||
///
|
||||
/// - parameter account: index of the given account
|
||||
/// - Parameter memo: the `Memo` for this transaction
|
||||
/// - Parameter transparentReceiver: a specific transparent receiver within the account
|
||||
/// that should be the source of transparent funds. Default is `nil` which
|
||||
/// will select whichever of the account's transparent receivers has funds
|
||||
/// to shield.
|
||||
/// - Throws: `rustShieldFunds` if rust layer returns error.
|
||||
func proposeShielding(
|
||||
account: Int32,
|
||||
memo: MemoBytes?,
|
||||
shieldingThreshold: Zatoshi
|
||||
) async throws -> FfiProposal
|
||||
shieldingThreshold: Zatoshi,
|
||||
transparentReceiver: String?
|
||||
) async throws -> FfiProposal?
|
||||
|
||||
/// Creates a transaction from the given proposal.
|
||||
/// - Parameter proposal: the transaction proposal.
|
||||
|
|
|
@ -176,14 +176,22 @@ public protocol Synchronizer: AnyObject {
|
|||
/// - Parameter accountIndex: the account for which to shield funds.
|
||||
/// - Parameter shieldingThreshold: the minimum transparent balance required before a proposal will be created.
|
||||
/// - Parameter memo: an optional memo to include as part of the proposal's transactions.
|
||||
/// - Parameter transparentReceiver: a specific transparent receiver within the account
|
||||
/// that should be the source of transparent funds. Default is `nil` which
|
||||
/// will select whichever of the account's transparent receivers has funds
|
||||
/// to shield.
|
||||
///
|
||||
/// Returns the proposal, or `nil` if the transparent balance that would be shielded
|
||||
/// is zero or below `shieldingThreshold`.
|
||||
///
|
||||
/// If `prepare()` hasn't already been called since creation of the synchronizer instance or since the last wipe then this method throws
|
||||
/// `SynchronizerErrors.notPrepared`.
|
||||
func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: Memo
|
||||
) async throws -> Proposal
|
||||
memo: Memo,
|
||||
transparentReceiver: TransparentAddress?
|
||||
) async throws -> Proposal?
|
||||
|
||||
/// Creates the transactions in the given proposal.
|
||||
///
|
||||
|
|
|
@ -86,10 +86,16 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
|||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: Memo,
|
||||
completion: @escaping (Result<Proposal, Error>) -> Void
|
||||
transparentReceiver: TransparentAddress? = nil,
|
||||
completion: @escaping (Result<Proposal?, Error>) -> Void
|
||||
) {
|
||||
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||
try await self.synchronizer.proposeShielding(accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
||||
try await self.synchronizer.proposeShielding(
|
||||
accountIndex: accountIndex,
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memo: memo,
|
||||
transparentReceiver: transparentReceiver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,10 +83,16 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
|||
public func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: Memo
|
||||
) -> SinglePublisher<Proposal, Error> {
|
||||
memo: Memo,
|
||||
transparentReceiver: TransparentAddress? = nil
|
||||
) -> SinglePublisher<Proposal?, Error> {
|
||||
AsyncToCombineGateway.executeThrowingAction() {
|
||||
try await self.synchronizer.proposeShielding(accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
||||
try await self.synchronizer.proposeShielding(
|
||||
accountIndex: accountIndex,
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memo: memo,
|
||||
transparentReceiver: transparentReceiver
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -282,13 +282,19 @@ public class SDKSynchronizer: Synchronizer {
|
|||
return proposal
|
||||
}
|
||||
|
||||
public func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo) async throws -> Proposal {
|
||||
public func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: Memo,
|
||||
transparentReceiver: TransparentAddress? = nil
|
||||
) async throws -> Proposal? {
|
||||
try throwIfUnprepared()
|
||||
|
||||
let proposal = try await transactionEncoder.proposeShielding(
|
||||
accountIndex: accountIndex,
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memoBytes: memo.asMemoBytes()
|
||||
memoBytes: memo.asMemoBytes(),
|
||||
transparentReceiver: transparentReceiver?.stringEncoded
|
||||
)
|
||||
|
||||
return proposal
|
||||
|
@ -384,11 +390,12 @@ public class SDKSynchronizer: Synchronizer {
|
|||
throw ZcashError.synchronizerShieldFundsInsuficientTransparentFunds
|
||||
}
|
||||
|
||||
let proposal = try await transactionEncoder.proposeShielding(
|
||||
guard let proposal = try await transactionEncoder.proposeShielding(
|
||||
accountIndex: Int(spendingKey.account),
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memoBytes: memo.asMemoBytes()
|
||||
)
|
||||
memoBytes: memo.asMemoBytes(),
|
||||
transparentReceiver: nil
|
||||
) else { throw ZcashError.synchronizerShieldFundsInsuficientTransparentFunds }
|
||||
|
||||
let transactions = try await transactionEncoder.createProposedTransactions(
|
||||
proposal: proposal,
|
||||
|
|
|
@ -40,14 +40,22 @@ protocol TransactionEncoder {
|
|||
/// - Parameter accountIndex: the account for which to shield funds.
|
||||
/// - Parameter shieldingThreshold: the minimum transparent balance required before a proposal will be created.
|
||||
/// - Parameter memoBytes: an optional memo to include as part of the proposal's transactions.
|
||||
/// - Parameter transparentReceiver: a specific transparent receiver within the account
|
||||
/// that should be the source of transparent funds. Default is `nil` which
|
||||
/// will select whichever of the account's transparent receivers has funds
|
||||
/// to shield.
|
||||
///
|
||||
/// Returns the proposal, or `nil` if the transparent balance that would be shielded
|
||||
/// is zero or below `shieldingThreshold`.
|
||||
///
|
||||
/// If `prepare()` hasn't already been called since creation of the synchronizer instance or since the last wipe then this method throws
|
||||
/// `SynchronizerErrors.notPrepared`.
|
||||
func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memoBytes: MemoBytes?
|
||||
) async throws -> Proposal
|
||||
memoBytes: MemoBytes?,
|
||||
transparentReceiver: String?
|
||||
) async throws -> Proposal?
|
||||
|
||||
/// Creates the transactions in the given proposal.
|
||||
///
|
||||
|
|
|
@ -74,13 +74,15 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memoBytes: MemoBytes?
|
||||
) async throws -> Proposal {
|
||||
let proposal = try await rustBackend.proposeShielding(
|
||||
memoBytes: MemoBytes?,
|
||||
transparentReceiver: String? = nil
|
||||
) async throws -> Proposal? {
|
||||
guard let proposal = try await rustBackend.proposeShielding(
|
||||
account: Int32(accountIndex),
|
||||
memo: memoBytes,
|
||||
shieldingThreshold: shieldingThreshold
|
||||
)
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
transparentReceiver: transparentReceiver
|
||||
) else { return nil }
|
||||
|
||||
return Proposal(inner: proposal)
|
||||
}
|
||||
|
|
|
@ -1423,25 +1423,25 @@ class SynchronizerMock: Synchronizer {
|
|||
|
||||
// MARK: - proposeShielding
|
||||
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoThrowableError: Error?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoCallsCount = 0
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoCalled: Bool {
|
||||
return proposeShieldingAccountIndexShieldingThresholdMemoCallsCount > 0
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverThrowableError: Error?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCallsCount = 0
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCalled: Bool {
|
||||
return proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCallsCount > 0
|
||||
}
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoReceivedArguments: (accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo)?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoReturnValue: Proposal!
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoClosure: ((Int, Zatoshi, Memo) async throws -> Proposal)?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReceivedArguments: (accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo, transparentReceiver: TransparentAddress?)?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReturnValue: Proposal?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverClosure: ((Int, Zatoshi, Memo, TransparentAddress?) async throws -> Proposal?)?
|
||||
|
||||
func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo) async throws -> Proposal {
|
||||
if let error = proposeShieldingAccountIndexShieldingThresholdMemoThrowableError {
|
||||
func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo, transparentReceiver: TransparentAddress?) async throws -> Proposal? {
|
||||
if let error = proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverThrowableError {
|
||||
throw error
|
||||
}
|
||||
proposeShieldingAccountIndexShieldingThresholdMemoCallsCount += 1
|
||||
proposeShieldingAccountIndexShieldingThresholdMemoReceivedArguments = (accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
||||
if let closure = proposeShieldingAccountIndexShieldingThresholdMemoClosure {
|
||||
return try await closure(accountIndex, shieldingThreshold, memo)
|
||||
proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCallsCount += 1
|
||||
proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReceivedArguments = (accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo, transparentReceiver: transparentReceiver)
|
||||
if let closure = proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverClosure {
|
||||
return try await closure(accountIndex, shieldingThreshold, memo, transparentReceiver)
|
||||
} else {
|
||||
return proposeShieldingAccountIndexShieldingThresholdMemoReturnValue
|
||||
return proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2828,34 +2828,34 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
|
|||
|
||||
// MARK: - proposeShielding
|
||||
|
||||
var proposeShieldingAccountMemoShieldingThresholdThrowableError: Error?
|
||||
func setProposeShieldingAccountMemoShieldingThresholdThrowableError(_ param: Error?) async {
|
||||
proposeShieldingAccountMemoShieldingThresholdThrowableError = param
|
||||
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError: Error?
|
||||
func setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError(_ param: Error?) async {
|
||||
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError = param
|
||||
}
|
||||
var proposeShieldingAccountMemoShieldingThresholdCallsCount = 0
|
||||
var proposeShieldingAccountMemoShieldingThresholdCalled: Bool {
|
||||
return proposeShieldingAccountMemoShieldingThresholdCallsCount > 0
|
||||
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCallsCount = 0
|
||||
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCalled: Bool {
|
||||
return proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCallsCount > 0
|
||||
}
|
||||
var proposeShieldingAccountMemoShieldingThresholdReceivedArguments: (account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi)?
|
||||
var proposeShieldingAccountMemoShieldingThresholdReturnValue: FfiProposal!
|
||||
func setProposeShieldingAccountMemoShieldingThresholdReturnValue(_ param: FfiProposal) async {
|
||||
proposeShieldingAccountMemoShieldingThresholdReturnValue = param
|
||||
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReceivedArguments: (account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi, transparentReceiver: String?)?
|
||||
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue: FfiProposal?
|
||||
func setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue(_ param: FfiProposal?) async {
|
||||
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue = param
|
||||
}
|
||||
var proposeShieldingAccountMemoShieldingThresholdClosure: ((Int32, MemoBytes?, Zatoshi) async throws -> FfiProposal)?
|
||||
func setProposeShieldingAccountMemoShieldingThresholdClosure(_ param: ((Int32, MemoBytes?, Zatoshi) async throws -> FfiProposal)?) async {
|
||||
proposeShieldingAccountMemoShieldingThresholdClosure = param
|
||||
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure: ((Int32, MemoBytes?, Zatoshi, String?) async throws -> FfiProposal?)?
|
||||
func setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure(_ param: ((Int32, MemoBytes?, Zatoshi, String?) async throws -> FfiProposal?)?) async {
|
||||
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure = param
|
||||
}
|
||||
|
||||
func proposeShielding(account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi) async throws -> FfiProposal {
|
||||
if let error = proposeShieldingAccountMemoShieldingThresholdThrowableError {
|
||||
func proposeShielding(account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi, transparentReceiver: String?) async throws -> FfiProposal? {
|
||||
if let error = proposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError {
|
||||
throw error
|
||||
}
|
||||
proposeShieldingAccountMemoShieldingThresholdCallsCount += 1
|
||||
proposeShieldingAccountMemoShieldingThresholdReceivedArguments = (account: account, memo: memo, shieldingThreshold: shieldingThreshold)
|
||||
if let closure = proposeShieldingAccountMemoShieldingThresholdClosure {
|
||||
return try await closure(account, memo, shieldingThreshold)
|
||||
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCallsCount += 1
|
||||
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReceivedArguments = (account: account, memo: memo, shieldingThreshold: shieldingThreshold, transparentReceiver: transparentReceiver)
|
||||
if let closure = proposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure {
|
||||
return try await closure(account, memo, shieldingThreshold, transparentReceiver)
|
||||
} else {
|
||||
return proposeShieldingAccountMemoShieldingThresholdReturnValue
|
||||
return proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ class RustBackendMockHelper {
|
|||
await rustBackendMock.setGetNearestRewindHeightHeightReturnValue(-1)
|
||||
await rustBackendMock.setPutUnspentTransparentOutputTxidIndexScriptValueHeightClosure() { _, _, _, _, _ in }
|
||||
await rustBackendMock.setProposeTransferAccountToValueMemoThrowableError(ZcashError.rustCreateToAddress("mocked error"))
|
||||
await rustBackendMock.setProposeShieldingAccountMemoShieldingThresholdThrowableError(ZcashError.rustShieldFunds("mocked error"))
|
||||
await rustBackendMock.setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError(ZcashError.rustShieldFunds("mocked error"))
|
||||
await rustBackendMock.setCreateProposedTransactionProposalUskThrowableError(ZcashError.rustCreateToAddress("mocked error"))
|
||||
await rustBackendMock.setDecryptAndStoreTransactionTxBytesMinedHeightThrowableError(ZcashError.rustDecryptAndStoreTransaction("mock fail"))
|
||||
|
||||
|
|
Loading…
Reference in New Issue