Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[trello.com/c/4QaDmVkg]: BtcWalletService tests introduced #640

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 102 additions & 58 deletions Adamant.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Adamant/App/DI/AppAssembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ struct AppAssembly: MainThreadAssembly {
))
}.inObjectScope(.container)

// MARK: BitcointTransactionFactoryProtocol
container.register(BitcoinKitTransactionFactoryProtocol.self) { _ in
BitcoinKitTransactionFactory()
}.inObjectScope(.transient)

// MARK: DogeApiService
container.register(DogeApiService.self) { r in
DogeApiService(api: .init(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// BitcoinKitTransactionFactoryProtocol.swift
// Adamant
//
// Created by Christian Benua on 11.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

import BitcoinKit

protocol BitcoinKitTransactionFactoryProtocol {
func createTransaction(
toAddress: Address,
amount: UInt64,
fee: UInt64,
changeAddress: Address,
utxos: [UnspentTransaction],
lockTime: UInt32,
keys: [PrivateKey]
) -> Transaction
}

final class BitcoinKitTransactionFactory: BitcoinKitTransactionFactoryProtocol {
func createTransaction(
toAddress address: Address,
amount: UInt64,
fee: UInt64,
changeAddress: Address,
utxos: [UnspentTransaction],
lockTime: UInt32,
keys: [PrivateKey]
) -> Transaction {
BitcoinKit.Transaction.createNewTransaction(
toAddress: address,
amount: amount,
fee: fee,
changeAddress: changeAddress,
utxos: utxos,
lockTime: lockTime,
keys: keys
)
}
}
11 changes: 10 additions & 1 deletion Adamant/Modules/Wallets/Bitcoin/BtcApiService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,16 @@ final class BtcApiCore: BlockchainHealthCheckableService, Sendable {
}
}

final class BtcApiService: ApiServiceProtocol {
protocol BtcApiServiceProtocol: ApiServiceProtocol {
func request<Output>(
waitsForConnectivity: Bool,
_ request: @Sendable @escaping (APICoreProtocol, NodeOrigin) async -> ApiServiceResult<Output>
) async -> WalletServiceResult<Output>

func getStatusInfo() async -> WalletServiceResult<NodeStatusInfo>
}

final class BtcApiService: BtcApiServiceProtocol {
let api: BlockchainHealthCheckWrapper<BtcApiCore>

@MainActor
Expand Down
14 changes: 14 additions & 0 deletions Adamant/Modules/Wallets/Bitcoin/BtcWallet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,18 @@ final class BtcWallet: WalletAccount, @unchecked Sendable {
self.publicKey = privateKey.publicKey()
self.addressEntity = try addressConverter.convert(publicKey: publicKey, type: .p2pkh)
}

#if DEBUG
@available(*, deprecated, message: "For testing purposes only")
init(
unicId: String,
privateKey: PrivateKey,
address: Address
) {
self.unicId = unicId
self.privateKey = privateKey
self.publicKey = privateKey.publicKey()
self.addressEntity = address
}
#endif
}
3 changes: 2 additions & 1 deletion Adamant/Modules/Wallets/Bitcoin/BtcWalletService+Send.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ extension BtcWalletService: WalletServiceTwoStepSend {

// MARK: 4. Create local transaction

let transaction = BitcoinKit.Transaction.createNewTransaction(
let transaction = btcTransactionFactory.createTransaction(
toAddress: toAddress,
amount: rawAmount,
fee: fee,
changeAddress: wallet.addressEntity,
utxos: utxos,
lockTime: 0,
keys: [key]
)

Expand Down
15 changes: 14 additions & 1 deletion Adamant/Modules/Wallets/Bitcoin/BtcWalletService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ final class BtcWalletService: WalletCoreProtocol, @unchecked Sendable {

// MARK: - Dependencies
var apiService: AdamantApiServiceProtocol!
var btcApiService: BtcApiService!
var btcApiService: BtcApiServiceProtocol!
var btcTransactionFactory: BitcoinKitTransactionFactoryProtocol!
var accountService: AccountService!
var dialogService: DialogService!
var increaseFeeService: IncreaseFeeService!
Expand Down Expand Up @@ -518,6 +519,7 @@ extension BtcWalletService: SwinjectDependentService {
increaseFeeService = container.resolve(IncreaseFeeService.self)
addressConverter = container.resolve(AddressConverterFactory.self)?.make(network: network)
btcApiService = container.resolve(BtcApiService.self)
btcTransactionFactory = container.resolve(BitcoinKitTransactionFactoryProtocol.self)
vibroService = container.resolve(VibroService.self)
coreDataStack = container.resolve(CoreDataStack.self)

Expand Down Expand Up @@ -777,6 +779,17 @@ extension BtcWalletService: PrivateKeyGenerator {
}
}

// MARK: test helpers

#if DEBUG
extension BtcWalletService {
@available(*, deprecated, message: "For testing purposes only")
func setWalletForTests(_ wallet: BtcWallet?) {
self.btcWallet = wallet
}
}
#endif

final class BtcTransaction: BaseBtcTransaction {
override var defaultCurrencySymbol: String? { BtcWalletService.currencySymbol }
}
File renamed without changes.
13 changes: 13 additions & 0 deletions AdamantTests/Extensions/Actor+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// Actor+Extensions.swift
// Adamant
//
// Created by Christian Benua on 10.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

extension Actor {
func isolated<T: Sendable>(_ closure: (isolated Self) -> T) -> T {
return closure(self)
}
}
40 changes: 40 additions & 0 deletions AdamantTests/Extensions/BitcoinKitTransaction+Equatable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// BitcoinKitTransaction+Equatable.swift
// Adamant
//
// Created by Christian Benua on 10.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

import BitcoinKit

extension BitcoinKit.Transaction: Equatable {
public static func == (lhs: BitcoinKit.Transaction, rhs: BitcoinKit.Transaction) -> Bool {
lhs.version == rhs.version &&
lhs.inputs == rhs.inputs &&
lhs.outputs == rhs.outputs &&
lhs.lockTime == rhs.lockTime
}
}

extension BitcoinKit.TransactionInput: Equatable {
public static func == (lhs: BitcoinKit.TransactionInput, rhs: BitcoinKit.TransactionInput) -> Bool {
lhs.previousOutput == rhs.previousOutput &&
lhs.signatureScript == rhs.signatureScript &&
lhs.sequence == rhs.sequence
}
}

extension BitcoinKit.TransactionOutPoint: Equatable {
public static func == (lhs: BitcoinKit.TransactionOutPoint, rhs: BitcoinKit.TransactionOutPoint) -> Bool {
lhs.hash == rhs.hash &&
lhs.index == rhs.index
}
}

extension BitcoinKit.TransactionOutput: Equatable {
public static func == (lhs: BitcoinKit.TransactionOutput, rhs: BitcoinKit.TransactionOutput) -> Bool {
lhs.value == rhs.value &&
lhs.lockingScript == rhs.lockingScript
}
}
38 changes: 38 additions & 0 deletions AdamantTests/Extensions/Result+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// Result+Extensions.swift
// Adamant
//
// Created by Christian Benua on 10.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

extension Result {
var error: Failure? {
switch self {
case let .failure(error):
return error
case .success:
return nil
}
}

var value: Success? {
switch self {
case .failure:
return nil
case let .success(value):
return value
}
}
}

extension Result where Failure == Error {
init(catchingAsync run: @escaping () async throws -> Success) async {
do {
let value = try await run()
self = .success(value)
} catch {
self = .failure(error)
}
}
}
16 changes: 16 additions & 0 deletions AdamantTests/Extensions/UnspentTransaction+Equatable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// UnspentTransaction+Equatable.swift
// Adamant
//
// Created by Christian Benua on 11.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

import BitcoinKit

extension UnspentTransaction: Equatable {
public static func == (lhs: UnspentTransaction, rhs: UnspentTransaction) -> Bool {
lhs.output == rhs.output &&
lhs.outpoint == rhs.outpoint
}
}
34 changes: 34 additions & 0 deletions AdamantTests/Extensions/WalletServiceError+Equatable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// WalletServiceError+Equatable.swift
// Adamant
//
// Created by Christian Benua on 10.01.2025.
// Copyright © 2025 Adamant. All rights reserved.
//

@testable import Adamant

extension WalletServiceError: Equatable {
public static func == (lhs: Adamant.WalletServiceError, rhs: Adamant.WalletServiceError) -> Bool {
switch (lhs, rhs) {
case (.notLogged, .notLogged), (.notEnoughMoney, .notEnoughMoney), (.networkError, .networkError),
(.accountNotFound, .accountNotFound), (.walletNotInitiated, .walletNotInitiated),
(.requestCancelled, .requestCancelled), (.dustAmountError, .dustAmountError):
return true
case let (.invalidAmount(lhsValue), invalidAmount(rhsValue)):
return lhsValue == rhsValue
case let (.transactionNotFound(lhsValue), transactionNotFound(rhsValue)):
return lhsValue == rhsValue
case (.apiError, .apiError):
return true
case let (.remoteServiceError(lhsValue, _), .remoteServiceError(rhsValue, _)):
return lhsValue == rhsValue
case let (.internalError(lhsValue, _), .internalError(rhsValue, _)):
return lhsValue == rhsValue
case (.notLogged, _), (.notEnoughMoney, _), (.networkError, _), (.accountNotFound, _), (.walletNotInitiated, _),
(.requestCancelled, _), (.dustAmountError, _), (.invalidAmount, _), (.transactionNotFound, _),
(.apiError, _), (.remoteServiceError, _), (.internalError, _):
return false
}
}
}
Loading