Modify PendingTransactionEntity to be able to represent internal shielding tx.
This commit is contained in:
parent
91ea6f5476
commit
f5d7aa0f17
|
@ -5,8 +5,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/grpc/grpc-swift.git",
|
"location" : "https://github.com/grpc/grpc-swift.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "87cecdeb2aae6b359b754d0dc7099e8237cf1824",
|
"revision" : "4c63368b7462305903507e8acebd77264c0fb695",
|
||||||
"version" : "1.11.0"
|
"version" : "1.8.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -18,31 +18,13 @@
|
||||||
"version" : "0.13.3"
|
"version" : "0.13.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"identity" : "swift-atomics",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/apple/swift-atomics.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "919eb1d83e02121cdb434c7bfc1f0c66ef17febe",
|
|
||||||
"version" : "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"identity" : "swift-collections",
|
|
||||||
"kind" : "remoteSourceControl",
|
|
||||||
"location" : "https://github.com/apple/swift-collections.git",
|
|
||||||
"state" : {
|
|
||||||
"revision" : "f504716c27d2e5d4144fa4794b12129301d17729",
|
|
||||||
"version" : "1.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"identity" : "swift-log",
|
"identity" : "swift-log",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-log.git",
|
"location" : "https://github.com/apple/swift-log.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "6fe203dc33195667ce1759bf0182975e4653ba1c",
|
"revision" : "5d66f7ba25daf4f94100e7022febf3c75e37a6c7",
|
||||||
"version" : "1.4.4"
|
"version" : "1.4.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -50,8 +32,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio.git",
|
"location" : "https://github.com/apple/swift-nio.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "bc4c55b9f9584f09eb971d67d956e28d08caa9d0",
|
"revision" : "124119f0bb12384cef35aa041d7c3a686108722d",
|
||||||
"version" : "2.43.1"
|
"version" : "2.40.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -59,8 +41,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio-extras.git",
|
"location" : "https://github.com/apple/swift-nio-extras.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "6c84d247754ad77487a6f0694273b89b83efd056",
|
"revision" : "a75e92bde3683241c15df3dd905b7a6dcac4d551",
|
||||||
"version" : "1.14.0"
|
"version" : "1.12.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -68,8 +50,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio-http2.git",
|
"location" : "https://github.com/apple/swift-nio-http2.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "00576e6f1efa5c46dca2ca3081dc56dd233b402d",
|
"revision" : "108ac15087ea9b79abb6f6742699cf31de0e8772",
|
||||||
"version" : "1.23.0"
|
"version" : "1.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -77,8 +59,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio-ssl.git",
|
"location" : "https://github.com/apple/swift-nio-ssl.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "ba7c0d7f82affc518147ea61d240330bf7f7ea9b",
|
"revision" : "42436a25ff32c390465567f5c089a9a8ce8d7baf",
|
||||||
"version" : "2.22.1"
|
"version" : "2.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -86,8 +68,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio-transport-services.git",
|
"location" : "https://github.com/apple/swift-nio-transport-services.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "b6e37a0d442745760d6ed0195d8f283d3ce0414a",
|
"revision" : "2cb54f91ddafc90832c5fa247faf5798d0a7c204",
|
||||||
"version" : "1.14.1"
|
"version" : "1.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -95,8 +77,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "88c7d15e1242fdb6ecbafbc7926426a19be1e98a",
|
"revision" : "e1499bc69b9040b29184f7f2996f7bab467c1639",
|
||||||
"version" : "1.20.2"
|
"version" : "1.19.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -104,7 +86,7 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "8eefbd8d70356b426d8e1dd7b07d2703a5a8e222"
|
"revision" : "0059f090e655667f9ee5ed3306bd87ca78c7711a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -16,7 +16,7 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.8.0"),
|
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.8.0"),
|
||||||
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.13.0"),
|
.package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.13.0"),
|
||||||
.package(name:"libzcashlc", url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", revision: "8eefbd8d70356b426d8e1dd7b07d2703a5a8e222")
|
.package(name:"libzcashlc", url: "https://github.com/zcash-hackworks/zcash-light-client-ffi", revision: "0059f090e655667f9ee5ed3306bd87ca78c7711a")
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
|
|
|
@ -31,6 +31,14 @@ extension NetworkType {
|
||||||
default: return nil
|
default: return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func forNetworkId(_ id: UInt32) -> NetworkType? {
|
||||||
|
switch id {
|
||||||
|
case 1: return .mainnet
|
||||||
|
case 0: return .testnet
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ZcashNetworkBuilder {
|
public enum ZcashNetworkBuilder {
|
||||||
|
|
|
@ -11,6 +11,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case toAddress = "to_address"
|
case toAddress = "to_address"
|
||||||
|
case toInternalAccount = "to_internal"
|
||||||
case accountIndex = "account_index"
|
case accountIndex = "account_index"
|
||||||
case minedHeight = "mined_height"
|
case minedHeight = "mined_height"
|
||||||
case expiryHeight = "expiry_height"
|
case expiryHeight = "expiry_height"
|
||||||
|
@ -27,7 +28,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
case rawTransactionId = "txid"
|
case rawTransactionId = "txid"
|
||||||
}
|
}
|
||||||
|
|
||||||
var toAddress: String
|
var recipient: PendingTransactionRecipient
|
||||||
var accountIndex: Int
|
var accountIndex: Int
|
||||||
var minedHeight: BlockHeight
|
var minedHeight: BlockHeight
|
||||||
var expiryHeight: BlockHeight
|
var expiryHeight: BlockHeight
|
||||||
|
@ -45,7 +46,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
|
|
||||||
static func from(entity: PendingTransactionEntity) -> PendingTransaction {
|
static func from(entity: PendingTransactionEntity) -> PendingTransaction {
|
||||||
PendingTransaction(
|
PendingTransaction(
|
||||||
toAddress: entity.toAddress,
|
recipient: entity.recipient,
|
||||||
accountIndex: entity.accountIndex,
|
accountIndex: entity.accountIndex,
|
||||||
minedHeight: entity.minedHeight,
|
minedHeight: entity.minedHeight,
|
||||||
expiryHeight: entity.expiryHeight,
|
expiryHeight: entity.expiryHeight,
|
||||||
|
@ -64,7 +65,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
}
|
}
|
||||||
|
|
||||||
init(
|
init(
|
||||||
toAddress: String,
|
recipient: PendingTransactionRecipient,
|
||||||
accountIndex: Int,
|
accountIndex: Int,
|
||||||
minedHeight: BlockHeight,
|
minedHeight: BlockHeight,
|
||||||
expiryHeight: BlockHeight,
|
expiryHeight: BlockHeight,
|
||||||
|
@ -80,7 +81,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
memo: Data?,
|
memo: Data?,
|
||||||
rawTransactionId: Data?
|
rawTransactionId: Data?
|
||||||
) {
|
) {
|
||||||
self.toAddress = toAddress
|
self.recipient = recipient
|
||||||
self.accountIndex = accountIndex
|
self.accountIndex = accountIndex
|
||||||
self.minedHeight = minedHeight
|
self.minedHeight = minedHeight
|
||||||
self.expiryHeight = expiryHeight
|
self.expiryHeight = expiryHeight
|
||||||
|
@ -100,7 +101,18 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
self.toAddress = try container.decode(String.self, forKey: .toAddress)
|
let toAddress: String? = try container.decodeIfPresent(String.self, forKey: .toAddress)
|
||||||
|
let toInternalAccount: UInt32? = try container.decode(UInt32.self, forKey: .toInternalAccount)
|
||||||
|
|
||||||
|
switch (toAddress, toInternalAccount) {
|
||||||
|
case let (.some(address), nil):
|
||||||
|
self.recipient = .address(Recipient.forEncodedAddress(encoded: address)!.0)
|
||||||
|
case let (nil, .some(accountId)):
|
||||||
|
self.recipient = .internalAccount(accountId)
|
||||||
|
default:
|
||||||
|
throw StorageError.malformedEntity(fields: ["toAddress", "toInternalAccount"])
|
||||||
|
}
|
||||||
|
|
||||||
self.accountIndex = try container.decode(Int.self, forKey: .accountIndex)
|
self.accountIndex = try container.decode(Int.self, forKey: .accountIndex)
|
||||||
self.minedHeight = try container.decode(BlockHeight.self, forKey: .minedHeight)
|
self.minedHeight = try container.decode(BlockHeight.self, forKey: .minedHeight)
|
||||||
self.expiryHeight = try container.decode(BlockHeight.self, forKey: .expiryHeight)
|
self.expiryHeight = try container.decode(BlockHeight.self, forKey: .expiryHeight)
|
||||||
|
@ -122,7 +134,18 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
func encode(to encoder: Encoder) throws {
|
func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
try container.encode(self.toAddress, forKey: .toAddress)
|
var toAddress: String?
|
||||||
|
var accountId: UInt32?
|
||||||
|
switch (self.recipient) {
|
||||||
|
case .address(let recipient):
|
||||||
|
toAddress = recipient.stringEncoded
|
||||||
|
case .internalAccount(let acct):
|
||||||
|
accountId = acct
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
try container.encode(toAddress, forKey: .toAddress)
|
||||||
|
try container.encode(accountId, forKey: .toInternalAccount)
|
||||||
try container.encode(self.accountIndex, forKey: .accountIndex)
|
try container.encode(self.accountIndex, forKey: .accountIndex)
|
||||||
try container.encode(self.minedHeight, forKey: .minedHeight)
|
try container.encode(self.minedHeight, forKey: .minedHeight)
|
||||||
try container.encode(self.expiryHeight, forKey: .expiryHeight)
|
try container.encode(self.expiryHeight, forKey: .expiryHeight)
|
||||||
|
@ -145,9 +168,9 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PendingTransaction {
|
extension PendingTransaction {
|
||||||
init(value: Zatoshi, toAddress: String, memo: MemoBytes, account index: Int) {
|
init(value: Zatoshi, recipient: PendingTransactionRecipient, memo: MemoBytes, account index: Int) {
|
||||||
self = PendingTransaction(
|
self = PendingTransaction(
|
||||||
toAddress: toAddress,
|
recipient: recipient,
|
||||||
accountIndex: index,
|
accountIndex: index,
|
||||||
minedHeight: -1,
|
minedHeight: -1,
|
||||||
expiryHeight: -1,
|
expiryHeight: -1,
|
||||||
|
@ -169,6 +192,7 @@ extension PendingTransaction {
|
||||||
class PendingTransactionSQLDAO: PendingTransactionRepository {
|
class PendingTransactionSQLDAO: PendingTransactionRepository {
|
||||||
enum TableColumns {
|
enum TableColumns {
|
||||||
static var toAddress = Expression<String>("to_address")
|
static var toAddress = Expression<String>("to_address")
|
||||||
|
static var toInternalAccount = Expression<String>("to_internal")
|
||||||
static var accountIndex = Expression<Int>("account_index")
|
static var accountIndex = Expression<Int>("account_index")
|
||||||
static var minedHeight = Expression<Int?>("mined_height")
|
static var minedHeight = Expression<Int?>("mined_height")
|
||||||
static var expiryHeight = Expression<Int?>("expiry_height")
|
static var expiryHeight = Expression<Int?>("expiry_height")
|
||||||
|
@ -197,6 +221,7 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
||||||
let statement = table.create(ifNotExists: true) { createdTable in
|
let statement = table.create(ifNotExists: true) { createdTable in
|
||||||
createdTable.column(TableColumns.id, primaryKey: .autoincrement)
|
createdTable.column(TableColumns.id, primaryKey: .autoincrement)
|
||||||
createdTable.column(TableColumns.toAddress)
|
createdTable.column(TableColumns.toAddress)
|
||||||
|
createdTable.column(TableColumns.toInternalAccount)
|
||||||
createdTable.column(TableColumns.accountIndex)
|
createdTable.column(TableColumns.accountIndex)
|
||||||
createdTable.column(TableColumns.minedHeight)
|
createdTable.column(TableColumns.minedHeight)
|
||||||
createdTable.column(TableColumns.expiryHeight)
|
createdTable.column(TableColumns.expiryHeight)
|
||||||
|
|
|
@ -6,6 +6,12 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
public enum PendingTransactionRecipient: Equatable {
|
||||||
|
case address(Recipient)
|
||||||
|
case internalAccount(UInt32)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Represents a sent transaction that has not been confirmed yet on the blockchain
|
Represents a sent transaction that has not been confirmed yet on the blockchain
|
||||||
*/
|
*/
|
||||||
|
@ -13,7 +19,7 @@ public protocol PendingTransactionEntity: SignedTransactionEntity, AbstractTrans
|
||||||
/**
|
/**
|
||||||
recipient address
|
recipient address
|
||||||
*/
|
*/
|
||||||
var toAddress: String { get }
|
var recipient: PendingTransactionRecipient { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
index of the account from which the funds were sent
|
index of the account from which the funds were sent
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
// WalletTypes.swift
|
// WalletTypes.swift
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Created by Francisco Gindre on 4/6/21.
|
// Created by Francisco Gindre on 4/6/21.
|
||||||
//
|
//
|
||||||
|
@ -94,6 +94,34 @@ public struct SaplingExtendedFullViewingKey: Equatable, StringEncoded, Undescrib
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum AddressType: Equatable {
|
||||||
|
case p2pkh
|
||||||
|
case p2sh
|
||||||
|
case sapling
|
||||||
|
case unified
|
||||||
|
|
||||||
|
var id: UInt32 {
|
||||||
|
switch self {
|
||||||
|
case .p2pkh: return 0
|
||||||
|
case .p2sh: return 1
|
||||||
|
case .sapling: return 2
|
||||||
|
case .unified: return 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AddressType {
|
||||||
|
static func forId(_ id: UInt32) -> AddressType? {
|
||||||
|
switch id {
|
||||||
|
case 0: return .p2pkh
|
||||||
|
case 1: return .p2sh
|
||||||
|
case 2: return .sapling
|
||||||
|
case 3: return .unified
|
||||||
|
default: return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A Transparent Address that can be encoded as a String
|
/// A Transparent Address that can be encoded as a String
|
||||||
///
|
///
|
||||||
/// Transactions sent to this address are totally visible in the public
|
/// Transactions sent to this address are totally visible in the public
|
||||||
|
@ -121,7 +149,7 @@ public struct TransparentAddress: Equatable, StringEncoded {
|
||||||
/// Represents a Sapling receiver address. Comonly called zAddress.
|
/// Represents a Sapling receiver address. Comonly called zAddress.
|
||||||
/// This address corresponds to the Zcash Sapling shielded pool.
|
/// This address corresponds to the Zcash Sapling shielded pool.
|
||||||
/// Although this it is fully functional, we encourage developers to
|
/// Although this it is fully functional, we encourage developers to
|
||||||
/// choose `UnifiedAddress` before Sapling or Transparent ones.
|
/// choose `UnifiedAddress` before Sapling or Transparent ones.
|
||||||
public struct SaplingAddress: Equatable, StringEncoded {
|
public struct SaplingAddress: Equatable, StringEncoded {
|
||||||
var encoding: String
|
var encoding: String
|
||||||
|
|
||||||
|
@ -234,6 +262,18 @@ public enum Recipient: Equatable, StringEncoded {
|
||||||
throw KeyEncodingError.invalidEncoding
|
throw KeyEncodingError.invalidEncoding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func forEncodedAddress(encoded: String) -> (Recipient, NetworkType)? {
|
||||||
|
return DerivationTool.getAddressMetadata(encoded).map { m in
|
||||||
|
switch m.addressType {
|
||||||
|
case .p2pkh: return (.transparent(TransparentAddress(validatedEncoding: encoded)),
|
||||||
|
m.networkType)
|
||||||
|
case .p2sh: return (.transparent(TransparentAddress(validatedEncoding: encoded)), m.networkType)
|
||||||
|
case .sapling: return (.sapling(SaplingAddress(validatedEncoding: encoded)), m.networkType)
|
||||||
|
case .unified: return (.unified(UnifiedAddress(validatedEncoding: encoded)), m.networkType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct WalletBalance: Equatable {
|
public struct WalletBalance: Equatable {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Foundation
|
||||||
import libzcashlc
|
import libzcashlc
|
||||||
|
|
||||||
class ZcashRustBackend: ZcashRustBackendWelding {
|
class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
|
|
||||||
static let minimumConfirmations: UInt32 = 10
|
static let minimumConfirmations: UInt32 = 10
|
||||||
|
|
||||||
static func createAccount(dbData: URL, seed: [UInt8], networkType: NetworkType) throws -> UnifiedSpendingKey {
|
static func createAccount(dbData: URL, seed: [UInt8], networkType: NetworkType) throws -> UnifiedSpendingKey {
|
||||||
|
@ -316,6 +317,26 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
||||||
return RustWeldingError.genericError(message: message)
|
return RustWeldingError.genericError(message: message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func getAddressMetadata(_ address: String) -> AddressMetadata? {
|
||||||
|
var networkId: UInt32 = 0
|
||||||
|
var addrId: UInt32 = 0
|
||||||
|
guard zcashlc_get_address_metadata(
|
||||||
|
[CChar](address.utf8CString),
|
||||||
|
&networkId,
|
||||||
|
&addrId
|
||||||
|
) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let network = NetworkType.forNetworkId(networkId),
|
||||||
|
let addrType = AddressType.forId(addrId)
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return AddressMetadata(network: network, addrType: addrType)
|
||||||
|
}
|
||||||
|
|
||||||
static func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress? {
|
static func getTransparentReceiver(for uAddr: UnifiedAddress) throws -> TransparentAddress? {
|
||||||
guard let transparentCStr = zcashlc_get_transparent_receiver_for_unified_address(
|
guard let transparentCStr = zcashlc_get_transparent_receiver_for_unified_address(
|
||||||
[CChar](uAddr.encoding.utf8CString)
|
[CChar](uAddr.encoding.utf8CString)
|
||||||
|
|
|
@ -261,6 +261,10 @@ protocol ZcashRustBackendWelding {
|
||||||
networkType: NetworkType
|
networkType: NetworkType
|
||||||
) throws -> DbInitResult
|
) throws -> DbInitResult
|
||||||
|
|
||||||
|
/// Returns the network and address type for the given Zcash address string,
|
||||||
|
/// if the string represents a valid Zcash address.
|
||||||
|
static func getAddressMetadata(_ address: String) -> AddressMetadata?
|
||||||
|
|
||||||
/// Validates the if the given string is a valid Sapling Address
|
/// Validates the if the given string is a valid Sapling Address
|
||||||
/// - Parameter address: UTF-8 encoded String to validate
|
/// - Parameter address: UTF-8 encoded String to validate
|
||||||
/// - Parameter networkType: network type of this key
|
/// - Parameter networkType: network type of this key
|
||||||
|
|
|
@ -468,11 +468,11 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
} catch {
|
} catch {
|
||||||
throw SynchronizerError.parameterMissing(underlyingError: error)
|
throw SynchronizerError.parameterMissing(underlyingError: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return try await createToAddress(
|
return try await createToAddress(
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
zatoshi: zatoshi,
|
zatoshi: zatoshi,
|
||||||
toAddress: toAddress.stringEncoded,
|
recipient: toAddress,
|
||||||
memo: memo
|
memo: memo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -498,7 +498,7 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
throw ShieldFundsError.shieldingFailed(underlyingError: KeyEncodingError.invalidEncoding)
|
throw ShieldFundsError.shieldingFailed(underlyingError: KeyEncodingError.invalidEncoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
let shieldingSpend = try transactionManager.initSpend(zatoshi: tBalance.verified, toAddress: uAddr.stringEncoded, memo: try memo.asMemoBytes(), from: accountIndex)
|
let shieldingSpend = try transactionManager.initSpend(zatoshi: tBalance.verified, recipient: .unified(uAddr), memo: try memo.asMemoBytes(), from: accountIndex)
|
||||||
|
|
||||||
// TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487
|
// TODO: Task will be removed when this method is changed to async, issue 487, https://github.com/zcash/ZcashLightClientKit/issues/487
|
||||||
let transaction = try await transactionManager.encodeShieldingTransaction(
|
let transaction = try await transactionManager.encodeShieldingTransaction(
|
||||||
|
@ -515,13 +515,13 @@ public class SDKSynchronizer: Synchronizer {
|
||||||
func createToAddress(
|
func createToAddress(
|
||||||
spendingKey: UnifiedSpendingKey,
|
spendingKey: UnifiedSpendingKey,
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
toAddress: String,
|
recipient: Recipient,
|
||||||
memo: Memo
|
memo: Memo
|
||||||
) async throws -> PendingTransactionEntity {
|
) async throws -> PendingTransactionEntity {
|
||||||
do {
|
do {
|
||||||
let spend = try transactionManager.initSpend(
|
let spend = try transactionManager.initSpend(
|
||||||
zatoshi: zatoshi,
|
zatoshi: zatoshi,
|
||||||
toAddress: toAddress,
|
recipient: recipient,
|
||||||
memo: memo.asMemoBytes(),
|
memo: memo.asMemoBytes(),
|
||||||
from: Int(spendingKey.account)
|
from: Int(spendingKey.account)
|
||||||
)
|
)
|
||||||
|
|
|
@ -69,6 +69,10 @@ public class DerivationTool: KeyDeriving {
|
||||||
try rustwelding.getTransparentReceiver(for: unifiedAddress)
|
try rustwelding.getTransparentReceiver(for: unifiedAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func getAddressMetadata(_ addr: String) -> AddressMetadata? {
|
||||||
|
rustwelding.getAddressMetadata(addr)
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a spending key, return the associated viewing key.
|
/// Given a spending key, return the associated viewing key.
|
||||||
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
|
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
|
||||||
/// - Returns: the viewing key that corresponds to the spending key.
|
/// - Returns: the viewing key that corresponds to the spending key.
|
||||||
|
@ -106,6 +110,16 @@ public class DerivationTool: KeyDeriving {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct AddressMetadata {
|
||||||
|
var networkType: NetworkType
|
||||||
|
var addressType: AddressType
|
||||||
|
|
||||||
|
public init(network: NetworkType, addrType: AddressType) {
|
||||||
|
self.networkType = network
|
||||||
|
self.addressType = addrType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension DerivationTool: KeyValidation {
|
extension DerivationTool: KeyValidation {
|
||||||
public func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool {
|
public func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool {
|
||||||
DerivationTool.rustwelding.isValidUnifiedFullViewingKey(ufvk, networkType: networkType)
|
DerivationTool.rustwelding.isValidUnifiedFullViewingKey(ufvk, networkType: networkType)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum TransactionManagerError: Error {
|
enum TransactionManagerError: Error {
|
||||||
case couldNotCreateSpend(toAddress: String, account: Int, zatoshi: Zatoshi)
|
case couldNotCreateSpend(recipient: Recipient, account: Int, zatoshi: Zatoshi)
|
||||||
case encodingFailed(PendingTransactionEntity)
|
case encodingFailed(PendingTransactionEntity)
|
||||||
case updateFailed(PendingTransactionEntity)
|
case updateFailed(PendingTransactionEntity)
|
||||||
case notPending(PendingTransactionEntity)
|
case notPending(PendingTransactionEntity)
|
||||||
|
@ -16,6 +16,7 @@ enum TransactionManagerError: Error {
|
||||||
case internalInconsistency(PendingTransactionEntity)
|
case internalInconsistency(PendingTransactionEntity)
|
||||||
case submitFailed(PendingTransactionEntity, errorCode: Int)
|
case submitFailed(PendingTransactionEntity, errorCode: Int)
|
||||||
case shieldingEncodingFailed(PendingTransactionEntity, reason: String)
|
case shieldingEncodingFailed(PendingTransactionEntity, reason: String)
|
||||||
|
case cannotEncodeInternalTx(PendingTransactionEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PersistentTransactionManager: OutboundTransactionManager {
|
class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
|
@ -40,7 +41,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
|
|
||||||
func initSpend(
|
func initSpend(
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
toAddress: String,
|
recipient: Recipient,
|
||||||
memo: MemoBytes,
|
memo: MemoBytes,
|
||||||
from accountIndex: Int
|
from accountIndex: Int
|
||||||
) throws -> PendingTransactionEntity {
|
) throws -> PendingTransactionEntity {
|
||||||
|
@ -48,14 +49,14 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
by: try repository.create(
|
by: try repository.create(
|
||||||
PendingTransaction(
|
PendingTransaction(
|
||||||
value: zatoshi,
|
value: zatoshi,
|
||||||
toAddress: toAddress,
|
recipient: .address(recipient),
|
||||||
memo: memo,
|
memo: memo,
|
||||||
account: accountIndex
|
account: accountIndex
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
) else {
|
) else {
|
||||||
throw TransactionManagerError.couldNotCreateSpend(
|
throw TransactionManagerError.couldNotCreateSpend(
|
||||||
toAddress: toAddress,
|
recipient: recipient,
|
||||||
account: accountIndex,
|
account: accountIndex,
|
||||||
zatoshi: zatoshi
|
zatoshi: zatoshi
|
||||||
)
|
)
|
||||||
|
@ -102,10 +103,18 @@ class PersistentTransactionManager: OutboundTransactionManager {
|
||||||
pendingTransaction: PendingTransactionEntity
|
pendingTransaction: PendingTransactionEntity
|
||||||
) async throws -> PendingTransactionEntity {
|
) async throws -> PendingTransactionEntity {
|
||||||
do {
|
do {
|
||||||
|
var toAddress: String?
|
||||||
|
switch (pendingTransaction.recipient) {
|
||||||
|
case .address(let addr):
|
||||||
|
toAddress = addr.stringEncoded
|
||||||
|
case .internalAccount(_):
|
||||||
|
throw TransactionManagerError.cannotEncodeInternalTx(pendingTransaction)
|
||||||
|
}
|
||||||
|
|
||||||
let encodedTransaction = try await self.encoder.createTransaction(
|
let encodedTransaction = try await self.encoder.createTransaction(
|
||||||
spendingKey: spendingKey,
|
spendingKey: spendingKey,
|
||||||
zatoshi: pendingTransaction.value,
|
zatoshi: pendingTransaction.value,
|
||||||
to: pendingTransaction.toAddress,
|
to: toAddress!,
|
||||||
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
|
memoBytes: try pendingTransaction.memo.intoMemoBytes(),
|
||||||
from: pendingTransaction.accountIndex
|
from: pendingTransaction.accountIndex
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,7 +16,7 @@ transactions through to completion.
|
||||||
protocol OutboundTransactionManager {
|
protocol OutboundTransactionManager {
|
||||||
func initSpend(
|
func initSpend(
|
||||||
zatoshi: Zatoshi,
|
zatoshi: Zatoshi,
|
||||||
toAddress: String,
|
recipient: Recipient,
|
||||||
memo: MemoBytes,
|
memo: MemoBytes,
|
||||||
from accountIndex: Int
|
from accountIndex: Int
|
||||||
) throws -> PendingTransactionEntity
|
) throws -> PendingTransactionEntity
|
||||||
|
|
|
@ -12,7 +12,7 @@ import XCTest
|
||||||
// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional
|
// swiftlint:disable force_try force_unwrapping implicitly_unwrapped_optional
|
||||||
class PendingTransactionRepositoryTests: XCTestCase {
|
class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
|
let dbUrl = try! TestDbBuilder.pendingTransactionsDbURL()
|
||||||
let recipientAddress = "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6"
|
let recipient = SaplingAddress(validatedEncoding: "ztestsapling1ctuamfer5xjnnrdr3xdazenljx0mu0gutcf9u9e74tr2d3jwjnt0qllzxaplu54hgc2tyjdc2p6")
|
||||||
|
|
||||||
var pendingRepository: PendingTransactionRepository!
|
var pendingRepository: PendingTransactionRepository!
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(transaction.accountIndex, expected.accountIndex)
|
XCTAssertEqual(transaction.accountIndex, expected.accountIndex)
|
||||||
XCTAssertEqual(transaction.value, expected.value)
|
XCTAssertEqual(transaction.value, expected.value)
|
||||||
XCTAssertEqual(transaction.toAddress, expected.toAddress)
|
XCTAssertEqual(transaction.recipient, expected.recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testFindById() {
|
func testFindById() {
|
||||||
|
@ -155,7 +155,7 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
|
|
||||||
XCTAssertEqual(updatedTransaction.encodeAttempts, oldEncodeAttempts + 1)
|
XCTAssertEqual(updatedTransaction.encodeAttempts, oldEncodeAttempts + 1)
|
||||||
XCTAssertEqual(updatedTransaction.submitAttempts, oldSubmitAttempts + 5)
|
XCTAssertEqual(updatedTransaction.submitAttempts, oldSubmitAttempts + 5)
|
||||||
XCTAssertEqual(updatedTransaction.toAddress, stored!.toAddress)
|
XCTAssertEqual(updatedTransaction.recipient, stored!.recipient)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createAndStoreMockedTransaction(with value: Zatoshi = Zatoshi(1000)) -> PendingTransactionEntity {
|
func createAndStoreMockedTransaction(with value: Zatoshi = Zatoshi(1000)) -> PendingTransactionEntity {
|
||||||
|
@ -175,6 +175,6 @@ class PendingTransactionRepositoryTests: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func mockTransaction(with value: Zatoshi = Zatoshi(1000)) -> PendingTransactionEntity {
|
private func mockTransaction(with value: Zatoshi = Zatoshi(1000)) -> PendingTransactionEntity {
|
||||||
PendingTransaction(value: value, toAddress: recipientAddress, memo: .empty(), account: 0)
|
PendingTransaction(value: value, recipient: .address(.sapling(recipient)), memo: .empty(), account: 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,10 @@ extension LightWalletServiceMockResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockRustBackend: ZcashRustBackendWelding {
|
class MockRustBackend: ZcashRustBackendWelding {
|
||||||
|
static func getAddressMetadata(_ address: String) -> ZcashLightClientKit.AddressMetadata? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
static func clearUtxos(dbData: URL, address: ZcashLightClientKit.TransparentAddress, sinceHeight: ZcashLightClientKit.BlockHeight, networkType: ZcashLightClientKit.NetworkType) throws -> Int32 {
|
static func clearUtxos(dbData: URL, address: ZcashLightClientKit.TransparentAddress, sinceHeight: ZcashLightClientKit.BlockHeight, networkType: ZcashLightClientKit.NetworkType) throws -> Int32 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue