Refactor code to build on top of Proposal API
This commit is contained in:
parent
41841c9458
commit
a9e8a40267
|
@ -35,19 +35,39 @@ public protocol CombineSynchronizer {
|
||||||
func getUnifiedAddress(accountIndex: Int) -> SinglePublisher<UnifiedAddress, Error>
|
func getUnifiedAddress(accountIndex: Int) -> SinglePublisher<UnifiedAddress, Error>
|
||||||
func getTransparentAddress(accountIndex: Int) -> SinglePublisher<TransparentAddress, Error>
|
func getTransparentAddress(accountIndex: Int) -> SinglePublisher<TransparentAddress, Error>
|
||||||
|
|
||||||
|
@available(*, deprecated, message: "Upcoming SDK 2.1 will create multiple transactions at once for some recipients. use `proposeTransfer` instead")
|
||||||
func sendToAddress(
|
func sendToAddress(
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
toAddress: Recipient,
|
toAddress: Recipient,
|
||||||
memo: Memo?
|
memo: Memo?
|
||||||
) -> SinglePublisher<ZcashTransaction.Overview, Error>
|
) -> SinglePublisher<ZcashTransaction.Overview, Error>
|
||||||
|
|
||||||
|
@available(*, deprecated, message: "Upcoming SDK 2.1 will create multiple transactions at once for some recipients. use `proposeShielding:` instead")
|
||||||
func shieldFunds(
|
func shieldFunds(
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
memo: Memo,
|
memo: Memo,
|
||||||
shieldingThreshold: Zatoshi
|
shieldingThreshold: Zatoshi
|
||||||
) -> SinglePublisher<ZcashTransaction.Overview, Error>
|
) -> SinglePublisher<ZcashTransaction.Overview, Error>
|
||||||
|
|
||||||
|
func proposeTransfer(
|
||||||
|
accountIndex: Int,
|
||||||
|
recipient: Recipient,
|
||||||
|
amount: Zatoshi,
|
||||||
|
memo: Memo?
|
||||||
|
) -> SinglePublisher<Proposal, Error>
|
||||||
|
|
||||||
|
func proposeShielding(
|
||||||
|
accountIndex: Int,
|
||||||
|
shieldingThreshold: Zatoshi,
|
||||||
|
memo: Memo
|
||||||
|
) -> SinglePublisher<Proposal, Error>
|
||||||
|
|
||||||
|
func proposefulfillingPaymentURI(
|
||||||
|
_ uri: String,
|
||||||
|
accountIndex: Int
|
||||||
|
) -> SinglePublisher<Proposal, Error>
|
||||||
|
|
||||||
var allTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> { get }
|
var allTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> { get }
|
||||||
var sentTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> { get }
|
var sentTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> { get }
|
||||||
var receivedTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> { get }
|
var receivedTransactions: SinglePublisher<[ZcashTransaction.Overview], Never> { get }
|
||||||
|
|
|
@ -225,16 +225,16 @@ public protocol Synchronizer: AnyObject {
|
||||||
memo: Memo?
|
memo: Memo?
|
||||||
) async throws -> ZcashTransaction.Overview
|
) async throws -> ZcashTransaction.Overview
|
||||||
|
|
||||||
/// Attempts to fulfill a [ZIP-321](https://zips.z.cash/zip-0321) payment URI using the given `UnifiedSpendingKey`
|
/// Attempts to propose fulfilling a [ZIP-321](https://zips.z.cash/zip-0321) payment URI using the given `accountIndex`
|
||||||
/// - Parameter uri: a valid ZIP-321 payment URI
|
/// - Parameter uri: a valid ZIP-321 payment URI
|
||||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` that allows spends to occur.
|
/// - Parameter accountIndex: the account index that allows spends to occur.
|
||||||
///
|
///
|
||||||
/// - NOTE: If `prepare()` hasn't already been called since creating of synchronizer instance or since the last wipe then this method throws
|
/// - NOTE: If `prepare()` hasn't already been called since creating of synchronizer instance or since the last wipe then this method throws
|
||||||
/// `SynchronizerErrors.notPrepared`.
|
/// `SynchronizerErrors.notPrepared`.
|
||||||
func fulfillPaymentURI(
|
func proposefulfillingPaymentURI(
|
||||||
_ uri: String,
|
_ uri: String,
|
||||||
spendingKey: UnifiedSpendingKey
|
accountIndex: Int
|
||||||
) async throws -> ZcashTransaction.Overview
|
) async throws -> Proposal
|
||||||
|
|
||||||
/// Shields transparent funds from the given private key into the best shielded pool of the account associated to the given `UnifiedSpendingKey`.
|
/// Shields transparent funds from the given private key into the best shielded pool of the account associated to the given `UnifiedSpendingKey`.
|
||||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` that allows to spend transparent funds
|
/// - Parameter spendingKey: the `UnifiedSpendingKey` that allows to spend transparent funds
|
||||||
|
|
|
@ -90,6 +90,18 @@ extension CombineSDKSynchronizer: CombineSynchronizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func proposefulfillingPaymentURI(
|
||||||
|
_ uri: String,
|
||||||
|
accountIndex: Int
|
||||||
|
) -> SinglePublisher<Proposal, Error> {
|
||||||
|
AsyncToCombineGateway.executeThrowingAction() {
|
||||||
|
try await self.synchronizer.proposefulfillingPaymentURI(
|
||||||
|
uri,
|
||||||
|
accountIndex: accountIndex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func createProposedTransactions(
|
public func createProposedTransactions(
|
||||||
proposal: Proposal,
|
proposal: Proposal,
|
||||||
spendingKey: UnifiedSpendingKey
|
spendingKey: UnifiedSpendingKey
|
||||||
|
|
|
@ -291,14 +291,29 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
) async throws -> Proposal? {
|
) async throws -> Proposal? {
|
||||||
try throwIfUnprepared()
|
try throwIfUnprepared()
|
||||||
|
|
||||||
let proposal = try await transactionEncoder.proposeShielding(
|
return try await transactionEncoder.proposeShielding(
|
||||||
accountIndex: accountIndex,
|
accountIndex: accountIndex,
|
||||||
shieldingThreshold: shieldingThreshold,
|
shieldingThreshold: shieldingThreshold,
|
||||||
memoBytes: memo.asMemoBytes(),
|
memoBytes: memo.asMemoBytes(),
|
||||||
transparentReceiver: transparentReceiver?.stringEncoded
|
transparentReceiver: transparentReceiver?.stringEncoded
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return proposal
|
public func proposefulfillingPaymentURI(
|
||||||
|
_ uri: String,
|
||||||
|
accountIndex: Int
|
||||||
|
) async throws -> Proposal {
|
||||||
|
do {
|
||||||
|
try throwIfUnprepared()
|
||||||
|
return try await transactionEncoder.proposeFulfillingPaymentFromURI(
|
||||||
|
uri,
|
||||||
|
accountIndex: accountIndex
|
||||||
|
)
|
||||||
|
} catch ZcashError.rustCreateToAddress(let e) {
|
||||||
|
throw ZcashError.rustProposeTransferFromURI(e)
|
||||||
|
} catch {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createProposedTransactions(
|
public func createProposedTransactions(
|
||||||
|
@ -344,25 +359,6 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func fulfillPaymentURI(_ uri: String, spendingKey: UnifiedSpendingKey) async throws -> ZcashTransaction.Overview {
|
|
||||||
do {
|
|
||||||
let transaction = try await transactionEncoder.createTransactionFromPaymentURI(
|
|
||||||
uri,
|
|
||||||
spendingKey: spendingKey
|
|
||||||
)
|
|
||||||
|
|
||||||
let encodedTransaction = try transaction.encodedTransaction()
|
|
||||||
|
|
||||||
try await transactionEncoder.submit(transaction: encodedTransaction)
|
|
||||||
|
|
||||||
return transaction
|
|
||||||
} catch ZcashError.rustCreateToAddress(let e) {
|
|
||||||
throw ZcashError.rustProposeTransferFromURI(e)
|
|
||||||
} catch {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func sendToAddress(
|
public func sendToAddress(
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// TransactionEncoder.swift
|
// TransactionEncoder.swift
|
||||||
// ZcashLightClientKit
|
// ZcashLightClientKit
|
||||||
//
|
//
|
||||||
// Created by Francisco Gindre on 11/20/19.
|
// Created by Francisco Gindre on 2019-11-20.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
@ -72,20 +72,20 @@ protocol TransactionEncoder {
|
||||||
spendingKey: UnifiedSpendingKey
|
spendingKey: UnifiedSpendingKey
|
||||||
) async throws -> [ZcashTransaction.Overview]
|
) async throws -> [ZcashTransaction.Overview]
|
||||||
|
|
||||||
/// Creates a transaction to fulfill a [ZIP-321](https://zips.z.cash/zip-0321), throwing an exception whenever things are missing. When the provided wallet implementation
|
/// Creates a transaction proposal to fulfill a [ZIP-321](https://zips.z.cash/zip-0321), 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
|
/// doesn't throw an exception, we wrap the issue into a descriptive exception ourselves (rather than using
|
||||||
/// double-bangs for things).
|
/// double-bangs for things).
|
||||||
///
|
///
|
||||||
/// - Parameters:
|
/// - Parameters:
|
||||||
/// - Parameter uri: a valid ZIP-321 payment URI.
|
/// - Parameter uri: a valid ZIP-321 payment URI.
|
||||||
/// - Parameter spendingKey: a `UnifiedSpendingKey` containing the spending key
|
/// - Parameter accountIndex: the index of the account the proposal should be made from.
|
||||||
/// - Throws:
|
/// - Throws:
|
||||||
/// - `walletTransEncoderCreateTransactionMissingSaplingParams` if the sapling parameters aren't downloaded.
|
/// - `walletTransEncoderCreateTransactionMissingSaplingParams` if the sapling parameters aren't downloaded.
|
||||||
/// - Some `ZcashError.rust*` if the creation of transaction fails.
|
/// - Some `ZcashError.rust*` if the creation of transaction fails.
|
||||||
func createTransactionFromPaymentURI(
|
func proposeFulfillingPaymentFromURI(
|
||||||
_ uri: String,
|
_ uri: String,
|
||||||
spendingKey: UnifiedSpendingKey
|
accountIndex: Int
|
||||||
) async throws -> ZcashTransaction.Overview
|
) async throws -> Proposal
|
||||||
|
|
||||||
/// submits a transaction to the Zcash peer-to-peer network.
|
/// submits a transaction to the Zcash peer-to-peer network.
|
||||||
/// - Parameter transaction: a transaction overview
|
/// - Parameter transaction: a transaction overview
|
||||||
|
|
|
@ -87,39 +87,15 @@ class WalletTransactionEncoder: TransactionEncoder {
|
||||||
return Proposal(inner: proposal)
|
return Proposal(inner: proposal)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTransactionFromPaymentURI(
|
func proposeFulfillingPaymentFromURI(
|
||||||
_ uri: String,
|
_ uri: String,
|
||||||
spendingKey: UnifiedSpendingKey
|
accountIndex: Int
|
||||||
) async throws -> ZcashTransaction.Overview {
|
) async throws -> Proposal {
|
||||||
let txId = try await createSpendFromPaymentURI(
|
|
||||||
uri,
|
|
||||||
spendingKey: spendingKey
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.debug("transaction id: \(txId)")
|
|
||||||
return try await repository.find(rawID: txId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSpendFromPaymentURI(
|
|
||||||
_ uri: String,
|
|
||||||
spendingKey: UnifiedSpendingKey
|
|
||||||
) async throws -> Data {
|
|
||||||
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.proposeTransferFromURI(
|
let proposal = try await rustBackend.proposeTransferFromURI(
|
||||||
uri,
|
uri,
|
||||||
account: Int32(spendingKey.account)
|
account: Int32(accountIndex)
|
||||||
)
|
)
|
||||||
|
return Proposal(inner: proposal)
|
||||||
let txId = try await rustBackend.createProposedTransaction(
|
|
||||||
proposal: proposal,
|
|
||||||
usk: spendingKey
|
|
||||||
)
|
|
||||||
|
|
||||||
return txId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createProposedTransactions(
|
func createProposedTransactions(
|
||||||
|
|
|
@ -101,7 +101,7 @@ class PaymentURIFulfillmentTests: ZcashTestCase {
|
||||||
sleep(1)
|
sleep(1)
|
||||||
|
|
||||||
let sendExpectation = XCTestExpectation(description: "send expectation")
|
let sendExpectation = XCTestExpectation(description: "send expectation")
|
||||||
var pendingEntity: ZcashTransaction.Overview?
|
var proposal: ZcashTransaction.Overview?
|
||||||
|
|
||||||
/*
|
/*
|
||||||
2. send transaction to recipient address
|
2. send transaction to recipient address
|
||||||
|
@ -111,24 +111,38 @@ class PaymentURIFulfillmentTests: ZcashTestCase {
|
||||||
let paymentURI = "zcash:\(Environment.testRecipientAddress)?amount=0.0002&memo=\(memo)&message=Thank%20you%20for%20your%20purchase&label=Your%20Purchase"
|
let paymentURI = "zcash:\(Environment.testRecipientAddress)?amount=0.0002&memo=\(memo)&message=Thank%20you%20for%20your%20purchase&label=Your%20Purchase"
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let pendingTx = try await coordinator.synchronizer.fulfillPaymentURI(
|
let proposal = try await coordinator.synchronizer.proposefulfillingPaymentURI(
|
||||||
paymentURI,
|
paymentURI,
|
||||||
spendingKey: self.coordinator.spendingKey
|
accountIndex: 0
|
||||||
)
|
)
|
||||||
|
|
||||||
pendingEntity = pendingTx
|
let transactions = try await coordinator.synchronizer.createProposedTransactions(
|
||||||
|
proposal: proposal,
|
||||||
|
spendingKey: coordinator.spendingKey
|
||||||
|
)
|
||||||
|
|
||||||
|
for try await tx in transactions {
|
||||||
|
switch tx {
|
||||||
|
case .grpcFailure(_, let error):
|
||||||
|
XCTFail("transaction failed to submit with error:\(error.localizedDescription)")
|
||||||
|
return
|
||||||
|
case .success(txId: let txId):
|
||||||
|
continue
|
||||||
|
case .submitFailure(txId: let txId, code: let code, description: let description):
|
||||||
|
XCTFail("transaction failed to submit with code: \(code) - description: \(description)")
|
||||||
|
return
|
||||||
|
case .notAttempted(txId: let txId):
|
||||||
|
XCTFail("transaction not attempted")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
sendExpectation.fulfill()
|
sendExpectation.fulfill()
|
||||||
} catch {
|
} catch {
|
||||||
await handleError(error)
|
await handleError(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
await fulfillment(of: [sendExpectation], timeout: 11)
|
await fulfillment(of: [sendExpectation], timeout: 13)
|
||||||
|
|
||||||
guard pendingEntity != nil else {
|
|
||||||
XCTFail("no pending transaction after sending")
|
|
||||||
try await coordinator.stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
3. getIncomingTransaction
|
3. getIncomingTransaction
|
||||||
|
@ -304,13 +318,13 @@ class PaymentURIFulfillmentTests: ZcashTestCase {
|
||||||
let paymentURI = "zcash:zecIsGreat17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a?amount=0.0002&memo=\(memo)&message=Thank%20you%20for%20your%20purchase&label=Your%20Purchase"
|
let paymentURI = "zcash:zecIsGreat17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a?amount=0.0002&memo=\(memo)&message=Thank%20you%20for%20your%20purchase&label=Your%20Purchase"
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let _ = try await coordinator.synchronizer.fulfillPaymentURI(
|
let _ = try await coordinator.synchronizer.proposefulfillingPaymentURI(
|
||||||
paymentURI,
|
paymentURI,
|
||||||
spendingKey: self.coordinator.spendingKey
|
accountIndex: 0
|
||||||
)
|
)
|
||||||
|
|
||||||
XCTFail("`fulfillPaymentURI` should have failed")
|
XCTFail("`fulfillPaymentURI` should have failed")
|
||||||
} catch ZcashError.rustCreateToAddress {
|
} catch ZcashError.rustProposeTransferFromURI {
|
||||||
XCTAssertTrue(true)
|
XCTAssertTrue(true)
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("Expected ZcashError.rustCreateToAddress but got \(error.localizedDescription)")
|
XCTFail("Expected ZcashError.rustCreateToAddress but got \(error.localizedDescription)")
|
||||||
|
|
|
@ -1493,27 +1493,27 @@ class SynchronizerMock: Synchronizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - fulfillPaymentURI
|
// MARK: - proposefulfillingPaymentURI
|
||||||
|
|
||||||
var fulfillPaymentURISpendingKeyThrowableError: Error?
|
var proposefulfillingPaymentURIAccountIndexThrowableError: Error?
|
||||||
var fulfillPaymentURISpendingKeyCallsCount = 0
|
var proposefulfillingPaymentURIAccountIndexCallsCount = 0
|
||||||
var fulfillPaymentURISpendingKeyCalled: Bool {
|
var proposefulfillingPaymentURIAccountIndexCalled: Bool {
|
||||||
return fulfillPaymentURISpendingKeyCallsCount > 0
|
return proposefulfillingPaymentURIAccountIndexCallsCount > 0
|
||||||
}
|
}
|
||||||
var fulfillPaymentURISpendingKeyReceivedArguments: (uri: String, spendingKey: UnifiedSpendingKey)?
|
var proposefulfillingPaymentURIAccountIndexReceivedArguments: (uri: String, accountIndex: Int)?
|
||||||
var fulfillPaymentURISpendingKeyReturnValue: ZcashTransaction.Overview!
|
var proposefulfillingPaymentURIAccountIndexReturnValue: Proposal!
|
||||||
var fulfillPaymentURISpendingKeyClosure: ((String, UnifiedSpendingKey) async throws -> ZcashTransaction.Overview)?
|
var proposefulfillingPaymentURIAccountIndexClosure: ((String, Int) async throws -> Proposal)?
|
||||||
|
|
||||||
func fulfillPaymentURI(_ uri: String, spendingKey: UnifiedSpendingKey) async throws -> ZcashTransaction.Overview {
|
func proposefulfillingPaymentURI(_ uri: String, accountIndex: Int) async throws -> Proposal {
|
||||||
if let error = fulfillPaymentURISpendingKeyThrowableError {
|
if let error = proposefulfillingPaymentURIAccountIndexThrowableError {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
fulfillPaymentURISpendingKeyCallsCount += 1
|
proposefulfillingPaymentURIAccountIndexCallsCount += 1
|
||||||
fulfillPaymentURISpendingKeyReceivedArguments = (uri: uri, spendingKey: spendingKey)
|
proposefulfillingPaymentURIAccountIndexReceivedArguments = (uri: uri, accountIndex: accountIndex)
|
||||||
if let closure = fulfillPaymentURISpendingKeyClosure {
|
if let closure = proposefulfillingPaymentURIAccountIndexClosure {
|
||||||
return try await closure(uri, spendingKey)
|
return try await closure(uri, accountIndex)
|
||||||
} else {
|
} else {
|
||||||
return fulfillPaymentURISpendingKeyReturnValue
|
return proposefulfillingPaymentURIAccountIndexReturnValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue