Add Fee field to Transaction, ConfirmedTransaction, ReceivedTransactions and Pen
dingTransactions. Update Notes DAOs with new fields. Make Zatoshi Codable add tests for Recipient.forEncodedAddress
This commit is contained in:
parent
849083ffd9
commit
789cf01188
|
@ -82,6 +82,7 @@ private extension MigrationManager {
|
|||
createdTable.column(PendingTransactionSQLDAO.TableColumns.value)
|
||||
createdTable.column(PendingTransactionSQLDAO.TableColumns.raw)
|
||||
createdTable.column(PendingTransactionSQLDAO.TableColumns.memo)
|
||||
createdTable.column(PendingTransactionSQLDAO.TableColumns.fee)
|
||||
}
|
||||
|
||||
try pendingDb.connection().transaction(.immediate) {
|
||||
|
@ -112,7 +113,8 @@ private extension MigrationManager {
|
|||
txid BLOB,
|
||||
value INTEGER NOT NULL,
|
||||
raw BLOB,
|
||||
memo BLOB
|
||||
memo BLOB,
|
||||
fee INTEGER
|
||||
);
|
||||
|
||||
INSERT INTO pending_transactions
|
||||
|
@ -132,7 +134,8 @@ private extension MigrationManager {
|
|||
txid,
|
||||
value,
|
||||
raw,
|
||||
memo
|
||||
memo,
|
||||
NULL
|
||||
FROM pending_transactions_old;
|
||||
|
||||
DROP TABLE pending_transactions_old
|
||||
|
|
|
@ -21,6 +21,7 @@ struct ReceivedNote: ReceivedNoteEntity, Codable {
|
|||
case value
|
||||
case memo
|
||||
case spent
|
||||
case tx
|
||||
}
|
||||
var id: Int
|
||||
var diversifier: Data
|
||||
|
@ -33,6 +34,7 @@ struct ReceivedNote: ReceivedNoteEntity, Codable {
|
|||
var value: Int
|
||||
var memo: Data?
|
||||
var spent: Int?
|
||||
var tx: Int
|
||||
}
|
||||
|
||||
class ReceivedNotesSQLDAO: ReceivedNoteRepository {
|
||||
|
@ -77,8 +79,9 @@ struct SentNote: SentNoteEntity, Codable {
|
|||
case transactionId = "tx"
|
||||
case outputPool = "output_pool"
|
||||
case outputIndex = "output_index"
|
||||
case account = "from_account"
|
||||
case address = "to_address"
|
||||
case fromAccount = "from_account"
|
||||
case toAddress = "to_address"
|
||||
case toAccount = "to_account"
|
||||
case value
|
||||
case memo
|
||||
}
|
||||
|
@ -87,8 +90,9 @@ struct SentNote: SentNoteEntity, Codable {
|
|||
var transactionId: Int
|
||||
var outputPool: Int
|
||||
var outputIndex: Int
|
||||
var account: Int
|
||||
var address: String
|
||||
var fromAccount: Int
|
||||
var toAddress: String
|
||||
var toAccount: Int
|
||||
var value: Int
|
||||
var memo: Data?
|
||||
}
|
||||
|
@ -126,19 +130,5 @@ class SentNotesSQLDAO: SentNotesRepository {
|
|||
try row.decode()
|
||||
}
|
||||
.first
|
||||
// try dbProvider.connection().run("""
|
||||
// SELECT sent_notes.id_note as id,
|
||||
// sent_notes.tx as transactionId,
|
||||
// sent_notes.output_index as outputIndex,
|
||||
// sent_notes.account as account,
|
||||
// sent_notes.to_address as address,
|
||||
// sent_notes.value as value,
|
||||
// sent_notes.memo as memo
|
||||
// FROM sent_note JOIN transactions
|
||||
// WHERE sent_note.tx = transactions.id_tx AND
|
||||
// transactions.txid = \(Blob(bytes: byRawTransactionId.bytes))
|
||||
// """).map({ row -> SentNoteEntity in
|
||||
// try row.decode()
|
||||
// }).first
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
case value
|
||||
case memo
|
||||
case rawTransactionId = "txid"
|
||||
case fee
|
||||
}
|
||||
|
||||
var recipient: PendingTransactionRecipient
|
||||
|
@ -43,7 +44,8 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
var value: Zatoshi
|
||||
var memo: Data?
|
||||
var rawTransactionId: Data?
|
||||
|
||||
var fee: Zatoshi?
|
||||
|
||||
static func from(entity: PendingTransactionEntity) -> PendingTransaction {
|
||||
PendingTransaction(
|
||||
recipient: entity.recipient,
|
||||
|
@ -60,10 +62,11 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
id: entity.id,
|
||||
value: entity.value,
|
||||
memo: entity.memo == nil ? Data(MemoBytes.empty().bytes) : entity.memo,
|
||||
rawTransactionId: entity.raw
|
||||
rawTransactionId: entity.raw,
|
||||
fee: entity.fee
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
init(
|
||||
recipient: PendingTransactionRecipient,
|
||||
accountIndex: Int,
|
||||
|
@ -79,7 +82,8 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
id: Int?,
|
||||
value: Zatoshi,
|
||||
memo: Data?,
|
||||
rawTransactionId: Data?
|
||||
rawTransactionId: Data?,
|
||||
fee: Zatoshi?
|
||||
) {
|
||||
self.recipient = recipient
|
||||
self.accountIndex = accountIndex
|
||||
|
@ -96,23 +100,27 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
self.value = value
|
||||
self.memo = memo
|
||||
self.rawTransactionId = rawTransactionId
|
||||
self.fee = fee
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
|
||||
let toAddress: String? = try container.decodeIfPresent(String.self, forKey: .toAddress)
|
||||
let toInternalAccount: Int? = try container.decodeIfPresent(Int.self, forKey: .toInternalAccount)
|
||||
|
||||
|
||||
switch (toAddress, toInternalAccount) {
|
||||
case let (.some(address), nil):
|
||||
self.recipient = .address(Recipient.forEncodedAddress(encoded: address)!.0)
|
||||
guard let recipient = Recipient.forEncodedAddress(encoded: address) else {
|
||||
throw StorageError.malformedEntity(fields: ["toAddress"])
|
||||
}
|
||||
self.recipient = .address(recipient.0)
|
||||
case let (nil, .some(accountId)):
|
||||
self.recipient = .internalAccount(UInt32(accountId))
|
||||
default:
|
||||
throw StorageError.malformedEntity(fields: ["toAddress", "toInternalAccount"])
|
||||
}
|
||||
|
||||
|
||||
self.accountIndex = try container.decode(Int.self, forKey: .accountIndex)
|
||||
self.minedHeight = try container.decode(BlockHeight.self, forKey: .minedHeight)
|
||||
self.expiryHeight = try container.decode(BlockHeight.self, forKey: .expiryHeight)
|
||||
|
@ -124,16 +132,17 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
self.createTime = try container.decode(TimeInterval.self, forKey: .createTime)
|
||||
self.raw = try container.decodeIfPresent(Data.self, forKey: .raw)
|
||||
self.id = try container.decodeIfPresent(Int.self, forKey: .id)
|
||||
|
||||
|
||||
let zatoshiValue = try container.decode(Int64.self, forKey: .value)
|
||||
self.value = Zatoshi(zatoshiValue)
|
||||
self.memo = try container.decodeIfPresent(Data.self, forKey: .memo)
|
||||
self.rawTransactionId = try container.decodeIfPresent(Data.self, forKey: .rawTransactionId)
|
||||
self.fee = try container.decodeIfPresent(Zatoshi.self, forKey: .fee)
|
||||
}
|
||||
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
|
||||
var toAddress: String?
|
||||
var accountId: Int?
|
||||
switch (self.recipient) {
|
||||
|
@ -142,8 +151,9 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
case .internalAccount(let acct):
|
||||
accountId = Int(acct)
|
||||
}
|
||||
|
||||
try container.encode(toAddress, forKey: .toAddress)
|
||||
try container.encode(accountId, forKey: .toInternalAccount)
|
||||
try container.encodeIfPresent(accountId, forKey: .toInternalAccount)
|
||||
try container.encode(self.accountIndex, forKey: .accountIndex)
|
||||
try container.encode(self.minedHeight, forKey: .minedHeight)
|
||||
try container.encode(self.expiryHeight, forKey: .expiryHeight)
|
||||
|
@ -158,8 +168,9 @@ struct PendingTransaction: PendingTransactionEntity, Decodable, Encodable {
|
|||
try container.encode(self.value.amount, forKey: .value)
|
||||
try container.encodeIfPresent(self.memo, forKey: .memo)
|
||||
try container.encodeIfPresent(self.rawTransactionId, forKey: .rawTransactionId)
|
||||
try container.encodeIfPresent(self.fee, forKey: .fee)
|
||||
}
|
||||
|
||||
|
||||
func isSameTransactionId<T>(other: T) -> Bool where T: RawIdentifiable {
|
||||
self.rawTransactionId == other.rawTransactionId
|
||||
}
|
||||
|
@ -182,7 +193,8 @@ extension PendingTransaction {
|
|||
id: nil,
|
||||
value: value,
|
||||
memo: Data(memo.bytes),
|
||||
rawTransactionId: nil
|
||||
rawTransactionId: nil,
|
||||
fee: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -205,12 +217,13 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
|||
static var value = Expression<Zatoshi>("value")
|
||||
static var memo = Expression<Blob?>("memo")
|
||||
static var rawTransactionId = Expression<Blob?>("txid")
|
||||
static var fee = Expression<Zatoshi?>("fee")
|
||||
}
|
||||
|
||||
|
||||
static let table = Table("pending_transactions")
|
||||
|
||||
var dbProvider: ConnectionProvider
|
||||
|
||||
|
||||
init(dbProvider: ConnectionProvider) {
|
||||
self.dbProvider = dbProvider
|
||||
}
|
||||
|
@ -226,7 +239,7 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
|||
guard let id = pendingTx.id else {
|
||||
throw StorageError.malformedEntity(fields: ["id"])
|
||||
}
|
||||
|
||||
|
||||
let updatedRows = try dbProvider.connection().run(Self.table.filter(TableColumns.id == id).update(pendingTx))
|
||||
if updatedRows == 0 {
|
||||
LoggerProxy.error("attempted to update pending transactions but no rows were updated")
|
||||
|
@ -237,7 +250,7 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
|||
guard let id = transaction.id else {
|
||||
throw StorageError.malformedEntity(fields: ["id"])
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
try dbProvider.connection().run(Self.table.filter(TableColumns.id == id).delete())
|
||||
} catch {
|
||||
|
@ -251,7 +264,7 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
|||
guard let txId = pendingTx.id else {
|
||||
throw StorageError.malformedEntity(fields: ["id"])
|
||||
}
|
||||
|
||||
|
||||
try dbProvider.connection().run(Self.table.filter(TableColumns.id == txId).update(pendingTx))
|
||||
}
|
||||
|
||||
|
@ -259,10 +272,10 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
|||
guard let row = try dbProvider.connection().pluck(Self.table.filter(TableColumns.id == id).limit(1)) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
let pendingTx: PendingTransaction = try row.decode()
|
||||
|
||||
|
||||
return pendingTx
|
||||
} catch {
|
||||
throw StorageError.operationFailed
|
||||
|
@ -273,7 +286,7 @@ class PendingTransactionSQLDAO: PendingTransactionRepository {
|
|||
let allTxs: [PendingTransaction] = try dbProvider.connection().prepare(Self.table).map { row in
|
||||
try row.decode()
|
||||
}
|
||||
|
||||
|
||||
return allTxs
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ enum TransactionBuilder {
|
|||
case memo
|
||||
case noteId
|
||||
case blockTimeInSeconds
|
||||
case fee
|
||||
}
|
||||
|
||||
enum ReceivedColumns: Int {
|
||||
|
@ -33,6 +34,7 @@ enum TransactionBuilder {
|
|||
case memo
|
||||
case noteId
|
||||
case blockTimeInSeconds
|
||||
case fee
|
||||
}
|
||||
|
||||
enum TransactionEntityColumns: Int {
|
||||
|
@ -42,6 +44,7 @@ enum TransactionBuilder {
|
|||
case txid
|
||||
case expiryHeight
|
||||
case raw
|
||||
case fee
|
||||
}
|
||||
|
||||
static func createTransactionEntity(txId: Data, rawTransaction: RawTransaction) -> TransactionEntity {
|
||||
|
@ -52,7 +55,8 @@ enum TransactionBuilder {
|
|||
transactionIndex: nil,
|
||||
expiryHeight: nil,
|
||||
minedHeight: Int(exactly: rawTransaction.height),
|
||||
raw: rawTransaction.data
|
||||
raw: rawTransaction.data,
|
||||
fee: nil
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -73,7 +77,8 @@ enum TransactionBuilder {
|
|||
transactionIndex: bindings[TransactionEntityColumns.txIndex.rawValue] as? Int,
|
||||
expiryHeight: bindings[TransactionEntityColumns.expiryHeight.rawValue] as? Int,
|
||||
minedHeight: bindings[TransactionEntityColumns.minedHeight.rawValue] as? Int,
|
||||
raw: rawData
|
||||
raw: rawData,
|
||||
fee: (bindings[TransactionEntityColumns.fee.rawValue] as? Int?)?.flatMap({ Zatoshi(Int64($0)) })
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -110,7 +115,7 @@ enum TransactionBuilder {
|
|||
if let txIdBlob = bindings[ConfirmedColumns.rawTransactionId.rawValue] as? Blob {
|
||||
transactionId = Data(blob: txIdBlob)
|
||||
}
|
||||
|
||||
|
||||
return ConfirmedTransaction(
|
||||
toAddress: toAddress,
|
||||
expiryHeight: expiryHeight,
|
||||
|
@ -122,7 +127,8 @@ enum TransactionBuilder {
|
|||
id: Int(id),
|
||||
value: Zatoshi(value),
|
||||
memo: memo,
|
||||
rawTransactionId: transactionId
|
||||
rawTransactionId: transactionId,
|
||||
fee: (bindings[ConfirmedColumns.fee.rawValue] as? Int).map({ Zatoshi(Int64($0)) })
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -163,7 +169,8 @@ enum TransactionBuilder {
|
|||
id: Int(id),
|
||||
value: Zatoshi(value),
|
||||
memo: memo,
|
||||
rawTransactionId: transactionId
|
||||
rawTransactionId: transactionId,
|
||||
fee: (bindings[ReceivedColumns.fee.rawValue] as? Int).map({ Zatoshi(Int64($0)) })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ struct Transaction: TransactionEntity, Decodable {
|
|||
case expiryHeight = "expiry_height"
|
||||
case minedHeight = "block"
|
||||
case raw
|
||||
case fee
|
||||
}
|
||||
|
||||
var id: Int?
|
||||
|
@ -26,6 +27,7 @@ struct Transaction: TransactionEntity, Decodable {
|
|||
var expiryHeight: BlockHeight?
|
||||
var minedHeight: BlockHeight?
|
||||
var raw: Data?
|
||||
var fee: Zatoshi?
|
||||
}
|
||||
|
||||
struct ConfirmedTransaction: ConfirmedTransactionEntity {
|
||||
|
@ -40,6 +42,7 @@ struct ConfirmedTransaction: ConfirmedTransactionEntity {
|
|||
var value: Zatoshi
|
||||
var memo: Data?
|
||||
var rawTransactionId: Data?
|
||||
var fee: Zatoshi?
|
||||
}
|
||||
|
||||
class TransactionSQLDAO: TransactionRepository {
|
||||
|
@ -51,6 +54,7 @@ class TransactionSQLDAO: TransactionRepository {
|
|||
static var expiryHeight = Expression<Int?>(Transaction.CodingKeys.expiryHeight.rawValue)
|
||||
static var minedHeight = Expression<Int?>(Transaction.CodingKeys.minedHeight.rawValue)
|
||||
static var raw = Expression<Blob?>(Transaction.CodingKeys.raw.rawValue)
|
||||
static var fee = Expression<Zatoshi?>(Transaction.CodingKeys.fee.rawValue)
|
||||
}
|
||||
|
||||
var dbProvider: ConnectionProvider
|
||||
|
@ -119,7 +123,8 @@ extension TransactionSQLDAO {
|
|||
sent_notes.value AS value,
|
||||
sent_notes.memo AS memo,
|
||||
sent_notes.id_note AS noteId,
|
||||
blocks.time AS blockTimeInSeconds
|
||||
blocks.time AS blockTimeInSeconds,
|
||||
transactions.fee AS fee
|
||||
FROM transactions
|
||||
INNER JOIN sent_notes
|
||||
ON transactions.id_tx = sent_notes.tx
|
||||
|
@ -153,7 +158,8 @@ extension TransactionSQLDAO {
|
|||
received_notes.value AS value,
|
||||
received_notes.memo AS memo,
|
||||
received_notes.id_note AS noteId,
|
||||
blocks.time AS blockTimeInSeconds
|
||||
blocks.time AS blockTimeInSeconds,
|
||||
transactions.fee AS fee
|
||||
|
||||
FROM transactions
|
||||
LEFT JOIN received_notes
|
||||
|
@ -197,7 +203,8 @@ extension TransactionSQLDAO {
|
|||
WHEN sent_notes.id_note IS NOT NULL THEN sent_notes.id_note
|
||||
ELSE received_notes.id_note
|
||||
end AS noteId,
|
||||
blocks.time AS blockTimeInSeconds
|
||||
blocks.time AS blockTimeInSeconds,
|
||||
transactions.fee AS fee
|
||||
FROM transactions
|
||||
LEFT JOIN received_notes
|
||||
ON transactions.id_tx = received_notes.tx
|
||||
|
@ -244,7 +251,8 @@ extension TransactionSQLDAO {
|
|||
WHEN sent_notes.id_note IS NOT NULL THEN sent_notes.id_note
|
||||
ELSE received_notes.id_note
|
||||
end AS noteId,
|
||||
blocks.time AS blockTimeInSeconds
|
||||
blocks.time AS blockTimeInSeconds,
|
||||
transactions.fee AS fee
|
||||
FROM transactions
|
||||
LEFT JOIN received_notes
|
||||
ON transactions.id_tx = received_notes.tx
|
||||
|
@ -274,7 +282,8 @@ extension TransactionSQLDAO {
|
|||
transactions.tx_index AS transactionIndex,
|
||||
transactions.txid AS rawTransactionId,
|
||||
transactions.expiry_height AS expiryHeight,
|
||||
transactions.raw AS raw
|
||||
transactions.raw AS raw,
|
||||
transactions.fee AS fee
|
||||
FROM transactions
|
||||
WHERE \(range.start.height) <= minedheight
|
||||
AND minedheight <= \(range.end.height)
|
||||
|
@ -310,7 +319,8 @@ extension TransactionSQLDAO {
|
|||
WHEN sent_notes.id_note IS NOT NULL THEN sent_notes.id_note
|
||||
ELSE received_notes.id_note
|
||||
end AS noteId,
|
||||
blocks.time AS blockTimeInSeconds
|
||||
blocks.time AS blockTimeInSeconds,
|
||||
transactions.fee AS fee
|
||||
FROM transactions
|
||||
LEFT JOIN received_notes
|
||||
ON transactions.id_tx = received_notes.tx
|
||||
|
@ -355,7 +365,8 @@ extension TransactionSQLDAO {
|
|||
WHEN sent_notes.id_note IS NOT NULL THEN sent_notes.id_note
|
||||
ELSE received_notes.id_note
|
||||
end AS noteId,
|
||||
blocks.time AS blockTimeInSeconds
|
||||
blocks.time AS blockTimeInSeconds,
|
||||
transactions.fee AS fee
|
||||
FROM transactions
|
||||
LEFT JOIN received_notes
|
||||
ON transactions.id_tx = received_notes.tx
|
||||
|
|
|
@ -188,7 +188,8 @@ public extension PendingTransactionEntity {
|
|||
transactionIndex: -1,
|
||||
expiryHeight: self.expiryHeight,
|
||||
minedHeight: self.minedHeight,
|
||||
raw: self.raw
|
||||
raw: self.raw,
|
||||
fee: self.fee
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +206,8 @@ public extension ConfirmedTransactionEntity {
|
|||
transactionIndex: self.transactionIndex,
|
||||
expiryHeight: self.expiryHeight,
|
||||
minedHeight: self.minedHeight,
|
||||
raw: self.raw
|
||||
raw: self.raw,
|
||||
fee: self.fee
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ protocol SentNoteEntity {
|
|||
var id: Int { get set }
|
||||
var transactionId: Int { get set }
|
||||
var outputIndex: Int { get set }
|
||||
var account: Int { get set }
|
||||
var address: String { get set }
|
||||
var fromAccount: Int { get set }
|
||||
var toAddress: String { get set }
|
||||
var value: Int { get set }
|
||||
var memo: Data? { get set }
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ extension SentNoteEntity {
|
|||
guard lhs.id == rhs.id,
|
||||
lhs.transactionId == rhs.transactionId,
|
||||
lhs.outputIndex == rhs.outputIndex,
|
||||
lhs.account == rhs.account,
|
||||
lhs.address == rhs.address,
|
||||
lhs.fromAccount == rhs.fromAccount,
|
||||
lhs.toAddress == rhs.toAddress,
|
||||
lhs.value == rhs.value,
|
||||
lhs.memo == rhs.memo else { return false }
|
||||
return true
|
||||
|
@ -33,8 +33,8 @@ extension SentNoteEntity {
|
|||
hasher.combine(id)
|
||||
hasher.combine(transactionId)
|
||||
hasher.combine(outputIndex)
|
||||
hasher.combine(account)
|
||||
hasher.combine(address)
|
||||
hasher.combine(fromAccount)
|
||||
hasher.combine(toAddress)
|
||||
hasher.combine(value)
|
||||
if let memo = memo {
|
||||
hasher.combine(memo)
|
||||
|
|
|
@ -93,6 +93,8 @@ public protocol AbstractTransaction {
|
|||
data containing the memo if any
|
||||
*/
|
||||
var memo: Data? { get set }
|
||||
|
||||
var fee: Zatoshi? { get set }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -280,7 +280,7 @@ public struct WalletBalance: Equatable {
|
|||
public var verified: Zatoshi
|
||||
public var total: Zatoshi
|
||||
|
||||
public init(verified: Zatoshi, total: Zatoshi) {
|
||||
public init(verified: Zatoshi, total: Zatoshi) {
|
||||
self.verified = verified
|
||||
self.total = total
|
||||
}
|
||||
|
|
|
@ -89,3 +89,20 @@ public extension NSDecimalNumber {
|
|||
self.roundedZec.stringValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension Zatoshi: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case amount
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.amount = try values.decode(Int64.self, forKey: .amount)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(self.amount, forKey: .amount)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,4 +188,14 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
func testGetMetadataFromAddress() throws {
|
||||
|
||||
let recipientAddress = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
||||
|
||||
let metadata = ZcashRustBackend.getAddressMetadata(recipientAddress)
|
||||
|
||||
XCTAssertEqual(metadata?.networkType, .mainnet)
|
||||
XCTAssertEqual(metadata?.addressType, .sapling)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,4 +31,16 @@ final class RecipientTests: XCTestCase {
|
|||
|
||||
XCTAssertEqual(try Recipient(transparentString, network: .mainnet), .transparent(expectedTransparentAddress))
|
||||
}
|
||||
|
||||
func testRecipentFromEncoding() throws {
|
||||
let address = "zs17mg40levjezevuhdp5pqrd52zere7r7vrjgdwn5sj4xsqtm20euwahv9anxmwr3y3kmwuz8k55a"
|
||||
|
||||
let recipient = Recipient.forEncodedAddress(
|
||||
encoded: address
|
||||
)
|
||||
|
||||
XCTAssertEqual(recipient?.0, .sapling(SaplingAddress(validatedEncoding: address)))
|
||||
XCTAssertEqual(recipient?.1, .mainnet)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue