Expose APIs for working with transaction proposals
Closes Electric-Coin-Company/zcash-swift-wallet-sdk#1204.
This commit is contained in:
parent
2ef0e00385
commit
df9e0ea424
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -4,6 +4,16 @@ All notable changes to this library will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
# Unreleased
|
||||
|
||||
## Added
|
||||
|
||||
### [#1204] Expose APIs for working with transaction proposals
|
||||
New `Synchronizer` APIs that enable constructing a proposal for transferring or
|
||||
shielding funds, and then creating transactions from a proposal. The intermediate
|
||||
proposal can be used to determine the required fee, before committing to producing
|
||||
transactions.
|
||||
|
||||
# 2.0.10 - 2024-02-12
|
||||
|
||||
## Added
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Proposal.swift
|
||||
//
|
||||
//
|
||||
// Created by Jack Grigg on 20/02/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A data structure that describes a series of transactions to be created.
|
||||
public struct Proposal {
|
||||
let inner: FfiProposal
|
||||
|
||||
/// Returns the total fee to be paid across all proposed transactions, in zatoshis.
|
||||
public func totalFeeRequired() -> Zatoshi {
|
||||
return Zatoshi(Int64(inner.balance.feeRequired))
|
||||
}
|
||||
}
|
|
@ -154,7 +154,53 @@ public protocol Synchronizer: AnyObject {
|
|||
/// - Parameter accountIndex: the optional accountId whose address is of interest. By default, the first account is used.
|
||||
/// - Returns the address or nil if account index is incorrect
|
||||
func getTransparentAddress(accountIndex: Int) async throws -> TransparentAddress
|
||||
|
||||
|
||||
/// Creates a proposal for transferring funds to the given recipient.
|
||||
///
|
||||
/// - Parameter accountIndex: the account from which to transfer funds.
|
||||
/// - Parameter recipient: the recipient's address.
|
||||
/// - Parameter amount: the amount to send in Zatoshi.
|
||||
/// - Parameter memo: an optional memo to include as part of the proposal's transactions. Use `nil` when sending to transparent receivers otherwise the function will throw an error.
|
||||
///
|
||||
/// 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 proposeTransfer(
|
||||
accountIndex: Int,
|
||||
recipient: Recipient,
|
||||
amount: Zatoshi,
|
||||
memo: Memo?
|
||||
) async throws -> Proposal
|
||||
|
||||
/// Creates a proposal for shielding any transparent funds received by the given account.
|
||||
///
|
||||
/// - 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.
|
||||
///
|
||||
/// 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
|
||||
|
||||
/// Creates the transactions in the given proposal.
|
||||
///
|
||||
/// - Parameter proposal: the proposal for which to create transactions.
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` associated with the account for which the proposal was created.
|
||||
///
|
||||
/// Returns a stream of objects for the transactions that were created as part of the
|
||||
/// proposal, indicating whether they were submitted to the network or if an error
|
||||
/// occurred.
|
||||
///
|
||||
/// 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 createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
spendingKey: UnifiedSpendingKey
|
||||
) async throws -> AsyncThrowingStream<TransactionSubmitResult, Error>
|
||||
|
||||
/// Sends zatoshi.
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` that allows spends to occur.
|
||||
/// - Parameter zatoshi: the amount to send in Zatoshi.
|
||||
|
@ -433,6 +479,19 @@ public enum RewindPolicy {
|
|||
case quick
|
||||
}
|
||||
|
||||
/// The result of submitting a transaction to the network.
|
||||
///
|
||||
/// - success: the transaction was successfully submitted to the mempool.
|
||||
/// - grpcFailure: the transaction failed to reach the lightwalletd server.
|
||||
/// - submitFailure: the transaction reached the lightwalletd server but failed to enter the mempool.
|
||||
/// - notAttempted: the transaction was created and is in the local wallet, but was not submitted to the network.
|
||||
public enum TransactionSubmitResult {
|
||||
case success(txId: Data)
|
||||
case grpcFailure(txId: Data, error: LightWalletServiceError)
|
||||
case submitFailure(txId: Data, code: Int, description: String)
|
||||
case notAttempted(txId: Data)
|
||||
}
|
||||
|
||||
extension InternalSyncStatus {
|
||||
public static func == (lhs: InternalSyncStatus, rhs: InternalSyncStatus) -> Bool {
|
||||
switch (lhs, rhs) {
|
||||
|
|
|
@ -70,6 +70,39 @@ extension ClosureSDKSynchronizer: ClosureSynchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
public func proposeTransfer(
|
||||
accountIndex: Int,
|
||||
recipient: Recipient,
|
||||
amount: Zatoshi,
|
||||
memo: Memo?,
|
||||
completion: @escaping (Result<Proposal, Error>) -> Void
|
||||
) {
|
||||
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||
try await self.synchronizer.proposeTransfer(accountIndex: accountIndex, recipient: recipient, amount: amount, memo: memo)
|
||||
}
|
||||
}
|
||||
|
||||
public func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: Memo,
|
||||
completion: @escaping (Result<Proposal, Error>) -> Void
|
||||
) {
|
||||
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||
try await self.synchronizer.proposeShielding(accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
||||
}
|
||||
}
|
||||
|
||||
public func createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
completion: @escaping (Result<AsyncThrowingStream<TransactionSubmitResult, Error>, Error>) -> Void
|
||||
) {
|
||||
AsyncToClosureGateway.executeThrowingAction(completion) {
|
||||
try await self.synchronizer.createProposedTransactions(proposal: proposal, spendingKey: spendingKey)
|
||||
}
|
||||
}
|
||||
|
||||
public func sendToAddress(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
|
|
|
@ -69,6 +69,36 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
public func proposeTransfer(
|
||||
accountIndex: Int,
|
||||
recipient: Recipient,
|
||||
amount: Zatoshi,
|
||||
memo: Memo?
|
||||
) -> SinglePublisher<Proposal, Error> {
|
||||
AsyncToCombineGateway.executeThrowingAction() {
|
||||
try await self.synchronizer.proposeTransfer(accountIndex: accountIndex, recipient: recipient, amount: amount, memo: memo)
|
||||
}
|
||||
}
|
||||
|
||||
public func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: Memo
|
||||
) -> SinglePublisher<Proposal, Error> {
|
||||
AsyncToCombineGateway.executeThrowingAction() {
|
||||
try await self.synchronizer.proposeShielding(accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
||||
}
|
||||
}
|
||||
|
||||
public func createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
spendingKey: UnifiedSpendingKey
|
||||
) -> SinglePublisher<AsyncThrowingStream<TransactionSubmitResult, Error>, Error> {
|
||||
AsyncToCombineGateway.executeThrowingAction() {
|
||||
try await self.synchronizer.createProposedTransactions(proposal: proposal, spendingKey: spendingKey)
|
||||
}
|
||||
}
|
||||
|
||||
public func sendToAddress(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
|
|
|
@ -265,6 +265,78 @@ public class SDKSynchronizer: Synchronizer {
|
|||
|
||||
// MARK: Synchronizer methods
|
||||
|
||||
public func proposeTransfer(accountIndex: Int, recipient: Recipient, amount: Zatoshi, memo: Memo?) async throws -> Proposal {
|
||||
try throwIfUnprepared()
|
||||
|
||||
if case Recipient.transparent = recipient, memo != nil {
|
||||
throw ZcashError.synchronizerSendMemoToTransparentAddress
|
||||
}
|
||||
|
||||
let proposal = try await transactionEncoder.proposeTransfer(
|
||||
accountIndex: accountIndex,
|
||||
recipient: recipient.stringEncoded,
|
||||
amount: amount,
|
||||
memoBytes: memo?.asMemoBytes()
|
||||
)
|
||||
|
||||
return proposal
|
||||
}
|
||||
|
||||
public func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo) async throws -> Proposal {
|
||||
try throwIfUnprepared()
|
||||
|
||||
let proposal = try await transactionEncoder.proposeShielding(
|
||||
accountIndex: accountIndex,
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memoBytes: memo.asMemoBytes()
|
||||
)
|
||||
|
||||
return proposal
|
||||
}
|
||||
|
||||
public func createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
spendingKey: UnifiedSpendingKey
|
||||
) async throws -> AsyncThrowingStream<TransactionSubmitResult, Error> {
|
||||
try throwIfUnprepared()
|
||||
|
||||
try await SaplingParameterDownloader.downloadParamsIfnotPresent(
|
||||
spendURL: initializer.spendParamsURL,
|
||||
spendSourceURL: initializer.saplingParamsSourceURL.spendParamFileURL,
|
||||
outputURL: initializer.outputParamsURL,
|
||||
outputSourceURL: initializer.saplingParamsSourceURL.outputParamFileURL,
|
||||
logger: logger
|
||||
)
|
||||
|
||||
let transactions = try await transactionEncoder.createProposedTransactions(
|
||||
proposal: proposal,
|
||||
spendingKey: spendingKey
|
||||
)
|
||||
var iterator = transactions.makeIterator()
|
||||
var submitFailed = false
|
||||
|
||||
return AsyncThrowingStream() {
|
||||
guard let transaction = iterator.next() else { return nil }
|
||||
|
||||
if submitFailed {
|
||||
return .notAttempted(txId: transaction.rawID)
|
||||
} else {
|
||||
let encodedTransaction = try transaction.encodedTransaction()
|
||||
|
||||
do {
|
||||
try await self.transactionEncoder.submit(transaction: encodedTransaction)
|
||||
return TransactionSubmitResult.success(txId: transaction.rawID)
|
||||
} catch ZcashError.serviceSubmitFailed(let error) {
|
||||
submitFailed = true
|
||||
return TransactionSubmitResult.grpcFailure(txId: transaction.rawID, error: error)
|
||||
} catch TransactionEncoderError.submitError(let code, let message) {
|
||||
submitFailed = true
|
||||
return TransactionSubmitResult.submitFailure(txId: transaction.rawID, code: code, description: message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func sendToAddress(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
|
@ -312,13 +384,20 @@ public class SDKSynchronizer: Synchronizer {
|
|||
throw ZcashError.synchronizerShieldFundsInsuficientTransparentFunds
|
||||
}
|
||||
|
||||
let transaction = try await transactionEncoder.createShieldingTransaction(
|
||||
spendingKey: spendingKey,
|
||||
let proposal = try await transactionEncoder.proposeShielding(
|
||||
accountIndex: Int(spendingKey.account),
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memoBytes: memo.asMemoBytes(),
|
||||
from: Int(spendingKey.account)
|
||||
memoBytes: memo.asMemoBytes()
|
||||
)
|
||||
|
||||
let transactions = try await transactionEncoder.createProposedTransactions(
|
||||
proposal: proposal,
|
||||
spendingKey: spendingKey
|
||||
)
|
||||
|
||||
assert(transactions.count == 1, "Rust backend doesn't produce multiple transactions yet")
|
||||
let transaction = transactions[0]
|
||||
|
||||
let encodedTx = try transaction.encodedTransaction()
|
||||
|
||||
try await transactionEncoder.submit(transaction: encodedTx)
|
||||
|
@ -339,14 +418,21 @@ public class SDKSynchronizer: Synchronizer {
|
|||
throw ZcashError.synchronizerSendMemoToTransparentAddress
|
||||
}
|
||||
|
||||
let transaction = try await transactionEncoder.createTransaction(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: zatoshi,
|
||||
to: recipient.stringEncoded,
|
||||
memoBytes: memo?.asMemoBytes(),
|
||||
from: Int(spendingKey.account)
|
||||
let proposal = try await transactionEncoder.proposeTransfer(
|
||||
accountIndex: Int(spendingKey.account),
|
||||
recipient: recipient.stringEncoded,
|
||||
amount: zatoshi,
|
||||
memoBytes: memo?.asMemoBytes()
|
||||
)
|
||||
|
||||
let transactions = try await transactionEncoder.createProposedTransactions(
|
||||
proposal: proposal,
|
||||
spendingKey: spendingKey
|
||||
)
|
||||
|
||||
assert(transactions.count == 1, "Rust backend doesn't produce multiple transactions yet")
|
||||
let transaction = transactions[0]
|
||||
|
||||
let encodedTransaction = try transaction.encodedTransaction()
|
||||
|
||||
try await transactionEncoder.submit(transaction: encodedTransaction)
|
||||
|
|
|
@ -19,44 +19,50 @@ public enum TransactionEncoderError: Error {
|
|||
}
|
||||
|
||||
protocol TransactionEncoder {
|
||||
/// Creates a transaction, throwing an exception whenever things are missing. When the provided wallet implementation
|
||||
/// doesn't throw an exception, we wrap the issue into a descriptive exception ourselves (rather than using
|
||||
/// double-bangs for things).
|
||||
/// Creates a proposal for transferring funds to the given recipient.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - Parameter spendingKey: a `UnifiedSpendingKey` containing the spending key
|
||||
/// - Parameter zatoshi: the amount to send in `Zatoshi`
|
||||
/// - Parameter to: string containing the recipient address
|
||||
/// - Parameter MemoBytes: string containing the memo (optional)
|
||||
/// - Parameter accountIndex: index of the account that will be used to send the funds
|
||||
/// - Parameter accountIndex: the account from which to transfer funds.
|
||||
/// - Parameter recipient: string containing the recipient's address.
|
||||
/// - Parameter amount: the amount to send in Zatoshi.
|
||||
/// - Parameter memoBytes: an optional memo to include as part of the proposal's transactions. Use `nil` when sending to transparent receivers otherwise the function will throw an error.
|
||||
///
|
||||
/// 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 proposeTransfer(
|
||||
accountIndex: Int,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memoBytes: MemoBytes?
|
||||
) async throws -> Proposal
|
||||
|
||||
/// Creates a proposal for shielding any transparent funds received by the given account.
|
||||
///
|
||||
/// - 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.
|
||||
///
|
||||
/// 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
|
||||
|
||||
/// Creates the transactions in the given proposal.
|
||||
///
|
||||
/// - Parameter proposal: the proposal for which to create transactions.
|
||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` associated with the account for which the proposal was created.
|
||||
/// - Throws:
|
||||
/// - `walletTransEncoderCreateTransactionMissingSaplingParams` if the sapling parameters aren't downloaded.
|
||||
/// - Some `ZcashError.rust*` if the creation of transaction fails.
|
||||
func createTransaction(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes?,
|
||||
from accountIndex: Int
|
||||
) async throws -> ZcashTransaction.Overview
|
||||
|
||||
/// Creates a transaction that will attempt to shield transparent funds that are present on the blocks cache .throwing
|
||||
/// an exception whenever things are missing. When the provided wallet implementation doesn't throw an exception,
|
||||
/// we wrap the issue into a descriptive exception ourselves (rather than using double-bangs for things).
|
||||
/// - Some `ZcashError.rust*` if the creation of transaction(s) fails.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - Parameter spendingKey: `UnifiedSpendingKey` to spend the UTXOs
|
||||
/// - Parameter memoBytes: containing the memo (optional)
|
||||
/// - Parameter accountIndex: index of the account that will be used to send the funds
|
||||
/// - Throws:
|
||||
/// - `walletTransEncoderShieldFundsMissingSaplingParams` if the sapling parameters aren't downloaded.
|
||||
/// - Some `ZcashError.rust*` if the creation of transaction fails.
|
||||
func createShieldingTransaction(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memoBytes: MemoBytes?,
|
||||
from accountIndex: Int
|
||||
) async throws -> ZcashTransaction.Overview
|
||||
/// 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 createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
spendingKey: UnifiedSpendingKey
|
||||
) async throws -> [ZcashTransaction.Overview]
|
||||
|
||||
/// submits a transaction to the Zcash peer-to-peer network.
|
||||
/// - Parameter transaction: a transaction overview
|
||||
|
|
|
@ -54,93 +54,52 @@ class WalletTransactionEncoder: TransactionEncoder {
|
|||
logger: initializer.logger
|
||||
)
|
||||
}
|
||||
|
||||
func createTransaction(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes?,
|
||||
from accountIndex: Int
|
||||
) async throws -> ZcashTransaction.Overview {
|
||||
let txId = try await createSpend(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: zatoshi,
|
||||
to: address,
|
||||
memoBytes: memoBytes,
|
||||
from: accountIndex
|
||||
|
||||
func proposeTransfer(
|
||||
accountIndex: Int,
|
||||
recipient: String,
|
||||
amount: Zatoshi,
|
||||
memoBytes: MemoBytes?
|
||||
) async throws -> Proposal {
|
||||
let proposal = try await rustBackend.proposeTransfer(
|
||||
account: Int32(accountIndex),
|
||||
to: recipient,
|
||||
value: amount.amount,
|
||||
memo: memoBytes
|
||||
)
|
||||
|
||||
logger.debug("transaction id: \(txId)")
|
||||
return try await repository.find(rawID: txId)
|
||||
return Proposal(inner: proposal)
|
||||
}
|
||||
|
||||
func createSpend(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
zatoshi: Zatoshi,
|
||||
to address: String,
|
||||
memoBytes: MemoBytes?,
|
||||
from accountIndex: Int
|
||||
) async throws -> Data {
|
||||
|
||||
func proposeShielding(
|
||||
accountIndex: Int,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memoBytes: MemoBytes?
|
||||
) async throws -> Proposal {
|
||||
let proposal = try await rustBackend.proposeShielding(
|
||||
account: Int32(accountIndex),
|
||||
memo: memoBytes,
|
||||
shieldingThreshold: shieldingThreshold
|
||||
)
|
||||
|
||||
return Proposal(inner: proposal)
|
||||
}
|
||||
|
||||
func createProposedTransactions(
|
||||
proposal: Proposal,
|
||||
spendingKey: UnifiedSpendingKey
|
||||
) async throws -> [ZcashTransaction.Overview] {
|
||||
guard ensureParams(spend: self.spendParamsURL, output: self.outputParamsURL) else {
|
||||
throw ZcashError.walletTransEncoderCreateTransactionMissingSaplingParams
|
||||
}
|
||||
|
||||
// TODO: Expose the proposal in a way that enables querying its fee.
|
||||
let proposal = try await rustBackend.proposeTransfer(
|
||||
account: Int32(spendingKey.account),
|
||||
to: address,
|
||||
value: zatoshi.amount,
|
||||
memo: memoBytes
|
||||
)
|
||||
|
||||
let txId = try await rustBackend.createProposedTransaction(
|
||||
proposal: proposal,
|
||||
proposal: proposal.inner,
|
||||
usk: spendingKey
|
||||
)
|
||||
|
||||
return txId
|
||||
}
|
||||
|
||||
func createShieldingTransaction(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memoBytes: MemoBytes?,
|
||||
from accountIndex: Int
|
||||
) async throws -> ZcashTransaction.Overview {
|
||||
let txId = try await createShieldingSpend(
|
||||
spendingKey: spendingKey,
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memo: memoBytes,
|
||||
accountIndex: accountIndex
|
||||
)
|
||||
|
||||
logger.debug("transaction id: \(txId)")
|
||||
return try await repository.find(rawID: txId)
|
||||
}
|
||||
|
||||
func createShieldingSpend(
|
||||
spendingKey: UnifiedSpendingKey,
|
||||
shieldingThreshold: Zatoshi,
|
||||
memo: MemoBytes?,
|
||||
accountIndex: Int
|
||||
) async throws -> Data {
|
||||
guard ensureParams(spend: self.spendParamsURL, output: self.outputParamsURL) else {
|
||||
throw ZcashError.walletTransEncoderShieldFundsMissingSaplingParams
|
||||
}
|
||||
|
||||
// TODO: Expose the proposal in a way that enables querying its fee.
|
||||
let proposal = try await rustBackend.proposeShielding(
|
||||
account: Int32(spendingKey.account),
|
||||
memo: memo,
|
||||
shieldingThreshold: shieldingThreshold
|
||||
)
|
||||
|
||||
let txId = try await rustBackend.createProposedTransaction(
|
||||
proposal: proposal,
|
||||
usk: spendingKey
|
||||
)
|
||||
|
||||
return txId
|
||||
return [try await repository.find(rawID: txId)]
|
||||
}
|
||||
|
||||
func submit(
|
||||
|
|
|
@ -1397,6 +1397,78 @@ class SynchronizerMock: Synchronizer {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - proposeTransfer
|
||||
|
||||
var proposeTransferAccountIndexRecipientAmountMemoThrowableError: Error?
|
||||
var proposeTransferAccountIndexRecipientAmountMemoCallsCount = 0
|
||||
var proposeTransferAccountIndexRecipientAmountMemoCalled: Bool {
|
||||
return proposeTransferAccountIndexRecipientAmountMemoCallsCount > 0
|
||||
}
|
||||
var proposeTransferAccountIndexRecipientAmountMemoReceivedArguments: (accountIndex: Int, recipient: Recipient, amount: Zatoshi, memo: Memo?)?
|
||||
var proposeTransferAccountIndexRecipientAmountMemoReturnValue: Proposal!
|
||||
var proposeTransferAccountIndexRecipientAmountMemoClosure: ((Int, Recipient, Zatoshi, Memo?) async throws -> Proposal)?
|
||||
|
||||
func proposeTransfer(accountIndex: Int, recipient: Recipient, amount: Zatoshi, memo: Memo?) async throws -> Proposal {
|
||||
if let error = proposeTransferAccountIndexRecipientAmountMemoThrowableError {
|
||||
throw error
|
||||
}
|
||||
proposeTransferAccountIndexRecipientAmountMemoCallsCount += 1
|
||||
proposeTransferAccountIndexRecipientAmountMemoReceivedArguments = (accountIndex: accountIndex, recipient: recipient, amount: amount, memo: memo)
|
||||
if let closure = proposeTransferAccountIndexRecipientAmountMemoClosure {
|
||||
return try await closure(accountIndex, recipient, amount, memo)
|
||||
} else {
|
||||
return proposeTransferAccountIndexRecipientAmountMemoReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - proposeShielding
|
||||
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoThrowableError: Error?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoCallsCount = 0
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoCalled: Bool {
|
||||
return proposeShieldingAccountIndexShieldingThresholdMemoCallsCount > 0
|
||||
}
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoReceivedArguments: (accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo)?
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoReturnValue: Proposal!
|
||||
var proposeShieldingAccountIndexShieldingThresholdMemoClosure: ((Int, Zatoshi, Memo) async throws -> Proposal)?
|
||||
|
||||
func proposeShielding(accountIndex: Int, shieldingThreshold: Zatoshi, memo: Memo) async throws -> Proposal {
|
||||
if let error = proposeShieldingAccountIndexShieldingThresholdMemoThrowableError {
|
||||
throw error
|
||||
}
|
||||
proposeShieldingAccountIndexShieldingThresholdMemoCallsCount += 1
|
||||
proposeShieldingAccountIndexShieldingThresholdMemoReceivedArguments = (accountIndex: accountIndex, shieldingThreshold: shieldingThreshold, memo: memo)
|
||||
if let closure = proposeShieldingAccountIndexShieldingThresholdMemoClosure {
|
||||
return try await closure(accountIndex, shieldingThreshold, memo)
|
||||
} else {
|
||||
return proposeShieldingAccountIndexShieldingThresholdMemoReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - createProposedTransactions
|
||||
|
||||
var createProposedTransactionsProposalSpendingKeyThrowableError: Error?
|
||||
var createProposedTransactionsProposalSpendingKeyCallsCount = 0
|
||||
var createProposedTransactionsProposalSpendingKeyCalled: Bool {
|
||||
return createProposedTransactionsProposalSpendingKeyCallsCount > 0
|
||||
}
|
||||
var createProposedTransactionsProposalSpendingKeyReceivedArguments: (proposal: Proposal, spendingKey: UnifiedSpendingKey)?
|
||||
var createProposedTransactionsProposalSpendingKeyReturnValue: AsyncThrowingStream<TransactionSubmitResult, Error>!
|
||||
var createProposedTransactionsProposalSpendingKeyClosure: ((Proposal, UnifiedSpendingKey) async throws -> AsyncThrowingStream<TransactionSubmitResult, Error>)?
|
||||
|
||||
func createProposedTransactions(proposal: Proposal, spendingKey: UnifiedSpendingKey) async throws -> AsyncThrowingStream<TransactionSubmitResult, Error> {
|
||||
if let error = createProposedTransactionsProposalSpendingKeyThrowableError {
|
||||
throw error
|
||||
}
|
||||
createProposedTransactionsProposalSpendingKeyCallsCount += 1
|
||||
createProposedTransactionsProposalSpendingKeyReceivedArguments = (proposal: proposal, spendingKey: spendingKey)
|
||||
if let closure = createProposedTransactionsProposalSpendingKeyClosure {
|
||||
return try await closure(proposal, spendingKey)
|
||||
} else {
|
||||
return createProposedTransactionsProposalSpendingKeyReturnValue
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - sendToAddress
|
||||
|
||||
var sendToAddressSpendingKeyZatoshiToAddressMemoThrowableError: Error?
|
||||
|
|
Loading…
Reference in New Issue