2019-11-26 14:32:20 -08:00
|
|
|
//
|
|
|
|
// WalletTransactionEncoder.swift
|
|
|
|
// ZcashLightClientKit
|
|
|
|
//
|
|
|
|
// Created by Francisco Gindre on 11/20/19.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
|
|
class WalletTransactionEncoder: TransactionEncoder {
|
2019-12-03 07:19:44 -08:00
|
|
|
|
2019-12-06 04:38:47 -08:00
|
|
|
var rustBackend: ZcashRustBackendWelding.Type
|
2019-11-26 14:32:20 -08:00
|
|
|
var repository: TransactionRepository
|
2019-12-03 07:19:44 -08:00
|
|
|
var queue: DispatchQueue
|
2019-12-16 14:25:45 -08:00
|
|
|
private var outputParamsURL: URL
|
|
|
|
private var spendParamsURL: URL
|
|
|
|
private var dataDbURL: URL
|
2020-12-23 15:01:09 -08:00
|
|
|
private var cacheDbURL: URL
|
2021-07-26 16:22:30 -07:00
|
|
|
private var network: NetworkType
|
2020-06-04 14:36:25 -07:00
|
|
|
|
2019-12-16 14:25:45 -08:00
|
|
|
init(rust: ZcashRustBackendWelding.Type,
|
|
|
|
dataDb: URL,
|
2020-12-23 15:01:09 -08:00
|
|
|
cacheDb: URL,
|
2019-12-16 14:25:45 -08:00
|
|
|
repository: TransactionRepository,
|
|
|
|
outputParams: URL,
|
2021-07-26 16:22:30 -07:00
|
|
|
spendParams: URL,
|
|
|
|
networkType: NetworkType) {
|
2019-12-16 14:25:45 -08:00
|
|
|
|
2019-11-26 14:32:20 -08:00
|
|
|
self.rustBackend = rust
|
2019-12-16 14:25:45 -08:00
|
|
|
self.dataDbURL = dataDb
|
2020-12-23 15:01:09 -08:00
|
|
|
self.cacheDbURL = cacheDb
|
2019-11-26 14:32:20 -08:00
|
|
|
self.repository = repository
|
2019-12-16 14:25:45 -08:00
|
|
|
self.outputParamsURL = outputParams
|
|
|
|
self.spendParamsURL = spendParams
|
2021-07-26 16:22:30 -07:00
|
|
|
self.network = networkType
|
2019-12-03 07:19:44 -08:00
|
|
|
self.queue = DispatchQueue(label: "wallet.transaction.encoder.serial.queue")
|
2019-12-16 14:25:45 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
convenience init(initializer: Initializer) {
|
|
|
|
self.init(rust: initializer.rustBackend,
|
|
|
|
dataDb: initializer.dataDbURL,
|
2020-12-23 15:01:09 -08:00
|
|
|
cacheDb: initializer.cacheDbURL,
|
2020-02-26 08:54:48 -08:00
|
|
|
repository: initializer.transactionRepository,
|
2019-12-16 14:25:45 -08:00
|
|
|
outputParams: initializer.outputParamsURL,
|
2021-07-26 16:22:30 -07:00
|
|
|
spendParams: initializer.spendParamsURL,
|
|
|
|
networkType: initializer.network)
|
2019-12-16 14:25:45 -08:00
|
|
|
|
2019-11-26 14:32:20 -08:00
|
|
|
}
|
|
|
|
|
2019-12-03 07:19:44 -08:00
|
|
|
func createTransaction(spendingKey: String, zatoshi: Int, to: String, memo: String?, from accountIndex: Int) throws -> EncodedTransaction {
|
2019-11-26 14:32:20 -08:00
|
|
|
|
|
|
|
let txId = try createSpend(spendingKey: spendingKey, zatoshi: zatoshi, to: to, memo: memo, from: accountIndex)
|
|
|
|
|
|
|
|
do {
|
|
|
|
let transaction = try repository.findBy(id: txId)
|
|
|
|
|
|
|
|
guard let tx = transaction else {
|
|
|
|
throw TransactionEncoderError.notFound(transactionId: txId)
|
|
|
|
}
|
|
|
|
|
2020-03-09 13:25:27 -07:00
|
|
|
LoggerProxy.debug("sentTransaction id: \(txId)")
|
2019-11-26 14:32:20 -08:00
|
|
|
return EncodedTransaction(transactionId: tx.transactionId , raw: tx.raw)
|
|
|
|
} catch {
|
|
|
|
throw TransactionEncoderError.notFound(transactionId: txId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-03 07:19:44 -08:00
|
|
|
func createTransaction(spendingKey: String, zatoshi: Int, to: String, memo: String?, from accountIndex: Int, result: @escaping TransactionEncoderResultBlock) {
|
2019-11-26 14:32:20 -08:00
|
|
|
|
2019-12-03 07:19:44 -08:00
|
|
|
queue.async { [weak self] in
|
2019-11-26 14:32:20 -08:00
|
|
|
guard let self = self else { return }
|
|
|
|
do {
|
|
|
|
result(.success(try self.createTransaction(spendingKey: spendingKey, zatoshi: zatoshi, to: to, memo: memo, from: accountIndex)))
|
|
|
|
} catch {
|
|
|
|
result(.failure(error))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-03 07:19:44 -08:00
|
|
|
func createSpend(spendingKey: String, zatoshi: Int, to address: String, memo: String?, from accountIndex: Int) throws -> Int {
|
2020-02-11 16:12:36 -08:00
|
|
|
guard ensureParams(spend: self.spendParamsURL, output: self.spendParamsURL) else {
|
2019-11-26 14:32:20 -08:00
|
|
|
throw TransactionEncoderError.missingParams
|
|
|
|
}
|
2020-06-09 17:23:46 -07:00
|
|
|
|
|
|
|
let txId = rustBackend.createToAddress(dbData: self.dataDbURL,
|
|
|
|
account: Int32(accountIndex),
|
|
|
|
extsk: spendingKey,
|
|
|
|
to: address,
|
|
|
|
value: Int64(zatoshi),
|
|
|
|
memo: memo,
|
|
|
|
spendParamsPath: self.spendParamsURL.path,
|
2021-07-26 16:22:30 -07:00
|
|
|
outputParamsPath: self.outputParamsURL.path,
|
|
|
|
networkType: network)
|
2019-11-26 14:32:20 -08:00
|
|
|
|
|
|
|
guard txId > 0 else {
|
|
|
|
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed")
|
|
|
|
}
|
|
|
|
|
2019-12-03 07:19:44 -08:00
|
|
|
return Int(txId)
|
2019-11-26 14:32:20 -08:00
|
|
|
}
|
|
|
|
|
2020-12-23 15:01:09 -08:00
|
|
|
func createShieldingTransaction(spendingKey: String, tSecretKey: String, memo: String?, from accountIndex: Int) throws -> EncodedTransaction {
|
|
|
|
let txId = try createShieldingSpend(spendingKey: spendingKey, tsk: tSecretKey, memo: memo, accountIndex: accountIndex)
|
|
|
|
|
|
|
|
do {
|
|
|
|
let transaction = try repository.findBy(id: txId)
|
|
|
|
|
|
|
|
guard let tx = transaction else {
|
|
|
|
throw TransactionEncoderError.notFound(transactionId: txId)
|
|
|
|
}
|
|
|
|
|
|
|
|
LoggerProxy.debug("sentTransaction id: \(txId)")
|
|
|
|
return EncodedTransaction(transactionId: tx.transactionId , raw: tx.raw)
|
|
|
|
} catch {
|
|
|
|
throw TransactionEncoderError.notFound(transactionId: txId)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createShieldingTransaction(spendingKey: String, tSecretKey: String, memo: String?, from accountIndex: Int, result: @escaping TransactionEncoderResultBlock) {
|
|
|
|
queue.async {
|
|
|
|
result(.failure(RustWeldingError.genericError(message: "not implemented")))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func createShieldingSpend(spendingKey: String, tsk: String, memo: String?, accountIndex: Int) throws -> Int {
|
|
|
|
guard ensureParams(spend: self.spendParamsURL, output: self.spendParamsURL) else {
|
|
|
|
throw TransactionEncoderError.missingParams
|
|
|
|
}
|
|
|
|
|
|
|
|
let txId = rustBackend.shieldFunds(dbCache: self.cacheDbURL,
|
|
|
|
dbData: self.dataDbURL,
|
|
|
|
account: Int32(accountIndex),
|
|
|
|
tsk: tsk,
|
|
|
|
extsk: spendingKey,
|
|
|
|
memo: memo,
|
|
|
|
spendParamsPath: self.spendParamsURL.path,
|
2021-07-26 16:22:30 -07:00
|
|
|
outputParamsPath: self.outputParamsURL.path,
|
|
|
|
networkType: network)
|
2020-12-23 15:01:09 -08:00
|
|
|
|
|
|
|
guard txId > 0 else {
|
|
|
|
throw rustBackend.lastError() ?? RustWeldingError.genericError(message: "create spend failed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return Int(txId)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-11-26 14:32:20 -08:00
|
|
|
func ensureParams(spend: URL, output: URL) -> Bool {
|
|
|
|
|
|
|
|
let readableSpend = FileManager.default.isReadableFile(atPath: spend.path)
|
|
|
|
let readableOutput = FileManager.default.isReadableFile(atPath: output.path)
|
|
|
|
|
|
|
|
return readableSpend && readableOutput // Todo: change this to something that makes sense
|
|
|
|
}
|
2020-06-04 14:36:25 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
Fetch the Transaction Entity from the encoded representation
|
|
|
|
- Parameter encodedTransaction: The encoded transaction to expand
|
|
|
|
- Returns: a TransactionEntity based on the given Encoded Transaction
|
|
|
|
- Throws: a TransactionEncoderError
|
|
|
|
*/
|
|
|
|
func expandEncodedTransaction(_ encodedTransaction: EncodedTransaction) throws -> TransactionEntity {
|
|
|
|
guard let t = try? repository.findBy(rawId: encodedTransaction.transactionId) else {
|
|
|
|
throw TransactionEncoderError.couldNotExpand(txId: encodedTransaction.transactionId)
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|
2019-11-26 14:32:20 -08:00
|
|
|
}
|