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(
|
func proposeShielding(
|
||||||
account: Int32,
|
account: Int32,
|
||||||
memo: MemoBytes?,
|
memo: MemoBytes?,
|
||||||
shieldingThreshold: Zatoshi
|
shieldingThreshold: Zatoshi,
|
||||||
) async throws -> FfiProposal {
|
transparentReceiver: String?
|
||||||
|
) async throws -> FfiProposal? {
|
||||||
|
if transparentReceiver != nil {
|
||||||
|
throw ZcashError.rustScanBlocks("TODO: Implement transparentReceiver support in FFI")
|
||||||
|
}
|
||||||
|
|
||||||
globalDBLock.lock()
|
globalDBLock.lock()
|
||||||
let proposal = zcashlc_propose_shielding(
|
let proposal = zcashlc_propose_shielding(
|
||||||
dbData.0,
|
dbData.0,
|
||||||
|
|
|
@ -212,14 +212,22 @@ protocol ZcashRustBackendWelding {
|
||||||
/// that can then be authorized and made ready for submission to the network with
|
/// that can then be authorized and made ready for submission to the network with
|
||||||
/// `createProposedTransaction`.
|
/// `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 account: index of the given account
|
||||||
/// - Parameter memo: the `Memo` for this transaction
|
/// - 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.
|
/// - Throws: `rustShieldFunds` if rust layer returns error.
|
||||||
func proposeShielding(
|
func proposeShielding(
|
||||||
account: Int32,
|
account: Int32,
|
||||||
memo: MemoBytes?,
|
memo: MemoBytes?,
|
||||||
shieldingThreshold: Zatoshi
|
shieldingThreshold: Zatoshi,
|
||||||
) async throws -> FfiProposal
|
transparentReceiver: String?
|
||||||
|
) async throws -> FfiProposal?
|
||||||
|
|
||||||
/// Creates a transaction from the given proposal.
|
/// Creates a transaction from the given proposal.
|
||||||
/// - Parameter proposal: the transaction proposal.
|
/// - Parameter proposal: the transaction proposal.
|
||||||
|
|
|
@ -176,14 +176,22 @@ public protocol Synchronizer: AnyObject {
|
||||||
/// - Parameter accountIndex: the account for which to shield funds.
|
/// - Parameter accountIndex: the account for which to shield funds.
|
||||||
/// - Parameter shieldingThreshold: the minimum transparent balance required before a proposal will be created.
|
/// - 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 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
|
/// If `prepare()` hasn't already been called since creation of the synchronizer instance or since the last wipe then this method throws
|
||||||
/// `SynchronizerErrors.notPrepared`.
|
/// `SynchronizerErrors.notPrepared`.
|
||||||
func proposeShielding(
|
func proposeShielding(
|
||||||
accountIndex: Int,
|
accountIndex: Int,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi,
|
||||||
memo: Memo
|
memo: Memo,
|
||||||
) async throws -> Proposal
|
transparentReceiver: TransparentAddress?
|
||||||
|
) async throws -> Proposal?
|
||||||
|
|
||||||
/// Creates the transactions in the given proposal.
|
/// Creates the transactions in the given proposal.
|
||||||
///
|
///
|
||||||
|
|
|
@ -86,10 +86,16 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
||||||
accountIndex: Int,
|
accountIndex: Int,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi,
|
||||||
memo: Memo,
|
memo: Memo,
|
||||||
completion: @escaping (Result<Proposal, Error>) -> Void
|
transparentReceiver: TransparentAddress? = nil,
|
||||||
|
completion: @escaping (Result<Proposal?, Error>) -> Void
|
||||||
) {
|
) {
|
||||||
AsyncToClosureGateway.executeThrowingAction(completion) {
|
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(
|
public func proposeShielding(
|
||||||
accountIndex: Int,
|
accountIndex: Int,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi,
|
||||||
memo: Memo
|
memo: Memo,
|
||||||
) -> SinglePublisher<Proposal, Error> {
|
transparentReceiver: TransparentAddress? = nil
|
||||||
|
) -> SinglePublisher<Proposal?, Error> {
|
||||||
AsyncToCombineGateway.executeThrowingAction() {
|
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
|
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()
|
try throwIfUnprepared()
|
||||||
|
|
||||||
let proposal = try await transactionEncoder.proposeShielding(
|
let proposal = try await transactionEncoder.proposeShielding(
|
||||||
accountIndex: accountIndex,
|
accountIndex: accountIndex,
|
||||||
shieldingThreshold: shieldingThreshold,
|
shieldingThreshold: shieldingThreshold,
|
||||||
memoBytes: memo.asMemoBytes()
|
memoBytes: memo.asMemoBytes(),
|
||||||
|
transparentReceiver: transparentReceiver?.stringEncoded
|
||||||
)
|
)
|
||||||
|
|
||||||
return proposal
|
return proposal
|
||||||
|
@ -384,11 +390,12 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
throw ZcashError.synchronizerShieldFundsInsuficientTransparentFunds
|
throw ZcashError.synchronizerShieldFundsInsuficientTransparentFunds
|
||||||
}
|
}
|
||||||
|
|
||||||
let proposal = try await transactionEncoder.proposeShielding(
|
guard let proposal = try await transactionEncoder.proposeShielding(
|
||||||
accountIndex: Int(spendingKey.account),
|
accountIndex: Int(spendingKey.account),
|
||||||
shieldingThreshold: shieldingThreshold,
|
shieldingThreshold: shieldingThreshold,
|
||||||
memoBytes: memo.asMemoBytes()
|
memoBytes: memo.asMemoBytes(),
|
||||||
)
|
transparentReceiver: nil
|
||||||
|
) else { throw ZcashError.synchronizerShieldFundsInsuficientTransparentFunds }
|
||||||
|
|
||||||
let transactions = try await transactionEncoder.createProposedTransactions(
|
let transactions = try await transactionEncoder.createProposedTransactions(
|
||||||
proposal: proposal,
|
proposal: proposal,
|
||||||
|
|
|
@ -40,14 +40,22 @@ protocol TransactionEncoder {
|
||||||
/// - Parameter accountIndex: the account for which to shield funds.
|
/// - Parameter accountIndex: the account for which to shield funds.
|
||||||
/// - Parameter shieldingThreshold: the minimum transparent balance required before a proposal will be created.
|
/// - 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 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
|
/// If `prepare()` hasn't already been called since creation of the synchronizer instance or since the last wipe then this method throws
|
||||||
/// `SynchronizerErrors.notPrepared`.
|
/// `SynchronizerErrors.notPrepared`.
|
||||||
func proposeShielding(
|
func proposeShielding(
|
||||||
accountIndex: Int,
|
accountIndex: Int,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi,
|
||||||
memoBytes: MemoBytes?
|
memoBytes: MemoBytes?,
|
||||||
) async throws -> Proposal
|
transparentReceiver: String?
|
||||||
|
) async throws -> Proposal?
|
||||||
|
|
||||||
/// Creates the transactions in the given proposal.
|
/// Creates the transactions in the given proposal.
|
||||||
///
|
///
|
||||||
|
|
|
@ -74,13 +74,15 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
func proposeShielding(
|
func proposeShielding(
|
||||||
accountIndex: Int,
|
accountIndex: Int,
|
||||||
shieldingThreshold: Zatoshi,
|
shieldingThreshold: Zatoshi,
|
||||||
memoBytes: MemoBytes?
|
memoBytes: MemoBytes?,
|
||||||
) async throws -> Proposal {
|
transparentReceiver: String? = nil
|
||||||
let proposal = try await rustBackend.proposeShielding(
|
) async throws -> Proposal? {
|
||||||
|
guard let proposal = try await rustBackend.proposeShielding(
|
||||||
account: Int32(accountIndex),
|
account: Int32(accountIndex),
|
||||||
memo: memoBytes,
|
memo: memoBytes,
|
||||||
shieldingThreshold: shieldingThreshold
|
shieldingThreshold: shieldingThreshold,
|
||||||
)
|
transparentReceiver: transparentReceiver
|
||||||
|
) else { return nil }
|
||||||
|
|
||||||
return Proposal(inner: proposal)
|
return Proposal(inner: proposal)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1423,25 +1423,25 @@ class SynchronizerMock: Synchronizer {
|
||||||
|
|
||||||
// MARK: - proposeShielding
|
// MARK: - proposeShielding
|
||||||
|
|
||||||
var proposeShieldingAccountIndexShieldingThresholdMemoThrowableError: Error?
|
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverThrowableError: Error?
|
||||||
var proposeShieldingAccountIndexShieldingThresholdMemoCallsCount = 0
|
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCallsCount = 0
|
||||||
var proposeShieldingAccountIndexShieldingThresholdMemoCalled: Bool {
|
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCalled: Bool {
|
||||||
return proposeShieldingAccountIndexShieldingThresholdMemoCallsCount > 0
|
return proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCallsCount > 0
|
||||||
}
|
}
|
||||||
var proposeShieldingAccountIndexShieldingThresholdMemoReceivedArguments: (accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo)?
|
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReceivedArguments: (accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo, transparentReceiver: TransparentAddress?)?
|
||||||
var proposeShieldingAccountIndexShieldingThresholdMemoReturnValue: Proposal!
|
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReturnValue: Proposal?
|
||||||
var proposeShieldingAccountIndexShieldingThresholdMemoClosure: ((Int, Zatoshi, Memo) async throws -> Proposal)?
|
var proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverClosure: ((Int, Zatoshi, Memo, TransparentAddress?) async throws -> Proposal?)?
|
||||||
|
|
||||||
func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo) async throws -> Proposal {
|
func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo, transparentReceiver: TransparentAddress?) async throws -> Proposal? {
|
||||||
if let error = proposeShieldingAccountIndexShieldingThresholdMemoThrowableError {
|
if let error = proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverThrowableError {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
proposeShieldingAccountIndexShieldingThresholdMemoCallsCount += 1
|
proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverCallsCount += 1
|
||||||
proposeShieldingAccountIndexShieldingThresholdMemoReceivedArguments = (accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReceivedArguments = (accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo, transparentReceiver: transparentReceiver)
|
||||||
if let closure = proposeShieldingAccountIndexShieldingThresholdMemoClosure {
|
if let closure = proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverClosure {
|
||||||
return try await closure(accountIndex, shieldingThreshold, memo)
|
return try await closure(accountIndex, shieldingThreshold, memo, transparentReceiver)
|
||||||
} else {
|
} else {
|
||||||
return proposeShieldingAccountIndexShieldingThresholdMemoReturnValue
|
return proposeShieldingAccountIndexShieldingThresholdMemoTransparentReceiverReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2828,34 +2828,34 @@ actor ZcashRustBackendWeldingMock: ZcashRustBackendWelding {
|
||||||
|
|
||||||
// MARK: - proposeShielding
|
// MARK: - proposeShielding
|
||||||
|
|
||||||
var proposeShieldingAccountMemoShieldingThresholdThrowableError: Error?
|
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError: Error?
|
||||||
func setProposeShieldingAccountMemoShieldingThresholdThrowableError(_ param: Error?) async {
|
func setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError(_ param: Error?) async {
|
||||||
proposeShieldingAccountMemoShieldingThresholdThrowableError = param
|
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError = param
|
||||||
}
|
}
|
||||||
var proposeShieldingAccountMemoShieldingThresholdCallsCount = 0
|
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCallsCount = 0
|
||||||
var proposeShieldingAccountMemoShieldingThresholdCalled: Bool {
|
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCalled: Bool {
|
||||||
return proposeShieldingAccountMemoShieldingThresholdCallsCount > 0
|
return proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCallsCount > 0
|
||||||
}
|
}
|
||||||
var proposeShieldingAccountMemoShieldingThresholdReceivedArguments: (account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi)?
|
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReceivedArguments: (account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi, transparentReceiver: String?)?
|
||||||
var proposeShieldingAccountMemoShieldingThresholdReturnValue: FfiProposal!
|
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue: FfiProposal?
|
||||||
func setProposeShieldingAccountMemoShieldingThresholdReturnValue(_ param: FfiProposal) async {
|
func setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue(_ param: FfiProposal?) async {
|
||||||
proposeShieldingAccountMemoShieldingThresholdReturnValue = param
|
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue = param
|
||||||
}
|
}
|
||||||
var proposeShieldingAccountMemoShieldingThresholdClosure: ((Int32, MemoBytes?, Zatoshi) async throws -> FfiProposal)?
|
var proposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure: ((Int32, MemoBytes?, Zatoshi, String?) async throws -> FfiProposal?)?
|
||||||
func setProposeShieldingAccountMemoShieldingThresholdClosure(_ param: ((Int32, MemoBytes?, Zatoshi) async throws -> FfiProposal)?) async {
|
func setProposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure(_ param: ((Int32, MemoBytes?, Zatoshi, String?) async throws -> FfiProposal?)?) async {
|
||||||
proposeShieldingAccountMemoShieldingThresholdClosure = param
|
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure = param
|
||||||
}
|
}
|
||||||
|
|
||||||
func proposeShielding(account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi) async throws -> FfiProposal {
|
func proposeShielding(account: Int32, memo: MemoBytes?, shieldingThreshold: Zatoshi, transparentReceiver: String?) async throws -> FfiProposal? {
|
||||||
if let error = proposeShieldingAccountMemoShieldingThresholdThrowableError {
|
if let error = proposeShieldingAccountMemoShieldingThresholdTransparentReceiverThrowableError {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
proposeShieldingAccountMemoShieldingThresholdCallsCount += 1
|
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverCallsCount += 1
|
||||||
proposeShieldingAccountMemoShieldingThresholdReceivedArguments = (account: account, memo: memo, shieldingThreshold: shieldingThreshold)
|
proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReceivedArguments = (account: account, memo: memo, shieldingThreshold: shieldingThreshold, transparentReceiver: transparentReceiver)
|
||||||
if let closure = proposeShieldingAccountMemoShieldingThresholdClosure {
|
if let closure = proposeShieldingAccountMemoShieldingThresholdTransparentReceiverClosure {
|
||||||
return try await closure(account, memo, shieldingThreshold)
|
return try await closure(account, memo, shieldingThreshold, transparentReceiver)
|
||||||
} else {
|
} else {
|
||||||
return proposeShieldingAccountMemoShieldingThresholdReturnValue
|
return proposeShieldingAccountMemoShieldingThresholdTransparentReceiverReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ class RustBackendMockHelper {
|
||||||
await rustBackendMock.setGetNearestRewindHeightHeightReturnValue(-1)
|
await rustBackendMock.setGetNearestRewindHeightHeightReturnValue(-1)
|
||||||
await rustBackendMock.setPutUnspentTransparentOutputTxidIndexScriptValueHeightClosure() { _, _, _, _, _ in }
|
await rustBackendMock.setPutUnspentTransparentOutputTxidIndexScriptValueHeightClosure() { _, _, _, _, _ in }
|
||||||
await rustBackendMock.setProposeTransferAccountToValueMemoThrowableError(ZcashError.rustCreateToAddress("mocked error"))
|
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.setCreateProposedTransactionProposalUskThrowableError(ZcashError.rustCreateToAddress("mocked error"))
|
||||||
await rustBackendMock.setDecryptAndStoreTransactionTxBytesMinedHeightThrowableError(ZcashError.rustDecryptAndStoreTransaction("mock fail"))
|
await rustBackendMock.setDecryptAndStoreTransactionTxBytesMinedHeightThrowableError(ZcashError.rustDecryptAndStoreTransaction("mock fail"))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue