Skip to content

Commit

Permalink
Make BTC transaction settings to apply without explicit 'Apply/Done' …
Browse files Browse the repository at this point in the history
…action
  • Loading branch information
esen committed May 14, 2024
1 parent 0031539 commit 5ee539c
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ extension BitcoinBaseAdapter {
}
}

func validate(address: String, pluginData: [UInt8: IBitcoinPluginData]) throws {
func validate(address: String, pluginData: [UInt8: IPluginData]) throws {
try abstractKit.validate(address: address, pluginData: pluginData)
}

Expand Down
2 changes: 1 addition & 1 deletion UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protocol ISendBitcoinAdapter {
func availableBalance(params: SendParameters) -> Decimal
func maximumSendAmount(pluginData: [UInt8: IBitcoinPluginData]) -> Decimal?
func minimumSendAmount(params: SendParameters) -> Decimal
func validate(address: String, pluginData: [UInt8: IBitcoinPluginData]) throws
func validate(address: String, pluginData: [UInt8: IPluginData]) throws
func unspentOutputs(filters: UtxoFilters) -> [UnspentOutputInfo]
func sendInfo(params: SendParameters) throws -> SendInfo
func sendSingle(params: SendParameters, logger: HsToolKit.Logger) -> Single<Void>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,30 @@ import SwiftUI
class BitcoinPreSendHandler {
let token: Token

var sortMode: TransactionDataSortMode
var rbfEnabled: Bool
var lockTimeInterval: HodlerPlugin.LockTimeInterval?

var customUtxos: [UnspentOutputInfo]? {
didSet {
syncBalance()
balanceSubject.send(availableBalanceDecimal)
settingsModifiedSubject.send(settingsModified)
}
}

var sortMode: TransactionDataSortMode {
didSet {
blockchainManager.save(transactionSortMode: sortMode, blockchainType: token.blockchainType)
settingsModifiedSubject.send(settingsModified)
}
}

var rbfEnabled: Bool {
didSet {
blockchainManager.save(rbfEnabled: rbfEnabled, blockchainType: token.blockchainType)
settingsModifiedSubject.send(settingsModified)
}
}

var lockTimeInterval: HodlerPlugin.LockTimeInterval? {
didSet {
settingsModifiedSubject.send(settingsModified)
}
}

Expand All @@ -26,10 +43,20 @@ class BitcoinPreSendHandler {
return utxos.map(\.value).reduce(0, +)
}

var availableBalanceDecimal: Decimal {
let coinRate = pow(10, token.decimals)
return Decimal(availableBalance) / coinRate
}

private let adapter: BitcoinBaseAdapter
private let blockchainManager: BtcBlockchainManager
private let disposeBag = DisposeBag()

private let defaultSortMode: TransactionDataSortMode
private let defaultRbfEnabled: Bool
private let stateSubject = PassthroughSubject<AdapterState, Never>()
private let balanceSubject = PassthroughSubject<Decimal, Never>()
private let settingsModifiedSubject = PassthroughSubject<Bool, Never>()

private var pluginData: [UInt8: IPluginData] {
guard let lockTimeInterval else {
Expand All @@ -44,10 +71,13 @@ class BitcoinPreSendHandler {
self.adapter = adapter

let blockchainType = token.blockchainType
let blockchainManager = App.shared.btcBlockchainManager
blockchainManager = App.shared.btcBlockchainManager

sortMode = blockchainManager.transactionSortMode(blockchainType: blockchainType)
rbfEnabled = blockchainManager.transactionRbfEnabled(blockchainType: blockchainType)
defaultSortMode = blockchainManager.transactionSortMode(blockchainType: blockchainType)
sortMode = defaultSortMode

defaultRbfEnabled = blockchainManager.transactionRbfEnabled(blockchainType: blockchainType)
rbfEnabled = defaultRbfEnabled

adapter.balanceStateUpdatedObservable
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
Expand All @@ -68,13 +98,19 @@ class BitcoinPreSendHandler {

private func syncBalance() {
allUtxos = adapter.unspentOutputs(filters: .init())

let coinRate = pow(10, token.decimals)
let availableBalanceDecimal = Decimal(availableBalance) / coinRate
balanceSubject.send(availableBalanceDecimal)
}
}

extension BitcoinPreSendHandler {
func reset() {
sortMode = defaultSortMode
rbfEnabled = defaultRbfEnabled
lockTimeInterval = nil
customUtxos = nil
}
}

extension BitcoinPreSendHandler: IPreSendHandler {
var hasSettings: Bool {
true
Expand All @@ -89,13 +125,21 @@ extension BitcoinPreSendHandler: IPreSendHandler {
}

var balance: Decimal {
adapter.balanceData.available
availableBalanceDecimal
}

var balancePublisher: AnyPublisher<Decimal, Never> {
balanceSubject.eraseToAnyPublisher()
}

var settingsModified: Bool {
sortMode != defaultSortMode || rbfEnabled != defaultRbfEnabled || customUtxos != nil || lockTimeInterval != nil
}

var settingsModifiedPublisher: AnyPublisher<Bool, Never> {
settingsModifiedSubject.eraseToAnyPublisher()
}

func hasMemo(address _: String?) -> Bool {
true
}
Expand All @@ -109,6 +153,12 @@ extension BitcoinPreSendHandler: IPreSendHandler {
}

func sendData(amount: Decimal, address: String, memo: String?) -> SendDataResult {
do {
try adapter.validate(address: address, pluginData: pluginData)
} catch {
return .invalid(cautions: [CautionNew(text: error.localizedDescription, type: .error)])
}

let params = SendParameters(
address: address,
value: adapter.convertToSatoshi(value: amount),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,9 @@ struct BitcoinSendSettingsView: View {

ToolbarItem(placement: .confirmationAction) {
Button("button.done".localized) {
viewModel.applySettings()
onChangeSettings()
presentationMode.wrappedValue.dismiss()
}
.disabled(!viewModel.doneEnabled)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,29 @@ class BitcoinSendSettingsViewModel: ObservableObject {

let handler: BitcoinPreSendHandler

@Published var sortMode: TransactionDataSortMode
@Published var rbfEnabled: Bool
@Published var lockTimeInterval: HodlerPlugin.LockTimeInterval?
@Published var resetEnabled = false
@Published var doneEnabled = true
@Published var sortMode: TransactionDataSortMode {
didSet {
handler.sortMode = sortMode
}
}

@Published var rbfEnabled: Bool {
didSet {
handler.rbfEnabled = rbfEnabled
}
}

@Published var lockTimeInterval: HodlerPlugin.LockTimeInterval? {
didSet {
handler.lockTimeInterval = lockTimeInterval
}
}

@Published var resetEnabled: Bool {
didSet {
print("resetEnabled: \(resetEnabled)")
}
}

@Published var utxos: String = ""

Expand All @@ -22,6 +40,13 @@ class BitcoinSendSettingsViewModel: ObservableObject {
rbfEnabled = handler.rbfEnabled
lockTimeInterval = handler.lockTimeInterval

resetEnabled = handler.settingsModified

handler.settingsModifiedPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] in self?.resetEnabled = $0 }
.store(in: &cancellables)

handler.balancePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in self?.syncUtxos() }
Expand All @@ -39,11 +64,7 @@ class BitcoinSendSettingsViewModel: ObservableObject {
}

extension BitcoinSendSettingsViewModel {
func reset() {}

func applySettings() {
handler.sortMode = sortMode
handler.rbfEnabled = rbfEnabled
handler.lockTimeInterval = lockTimeInterval
func reset() {
handler.reset()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ protocol IPreSendHandler {
var statePublisher: AnyPublisher<AdapterState, Never> { get }
var balance: Decimal { get }
var balancePublisher: AnyPublisher<Decimal, Never> { get }
func validate(address: String) -> Caution?
var settingsModified: Bool { get }
var settingsModifiedPublisher: AnyPublisher<Bool, Never> { get }
func hasMemo(address: String?) -> Bool
func settingsView(onChangeSettings: @escaping () -> Void) -> AnyView
func sendData(amount: Decimal, address: String, memo: String?) -> SendDataResult
Expand All @@ -19,17 +20,21 @@ extension IPreSendHandler {
false
}

func validate(address _: String) -> Caution? {
nil
}

func hasMemo(address _: String?) -> Bool {
false
}

func settingsView(onChangeSettings _: @escaping () -> Void) -> AnyView {
AnyView(EmptyView())
}

var settingsModified: Bool {
false
}

var settingsModifiedPublisher: AnyPublisher<Bool, Never> {
Empty().eraseToAnyPublisher()
}
}

enum SendDataResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ class PreSendViewModel: ObservableObject {
.receive(on: DispatchQueue.main)
.sink { [weak self] in self?.availableBalance = $0 }
.store(in: &cancellables)

handler.settingsModifiedPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in self?.syncSendData() }
.store(in: &cancellables)
}

syncFiatAmount()
Expand Down Expand Up @@ -200,14 +205,8 @@ class PreSendViewModel: ObservableObject {
addressCautionState = .none
case let .valid(success):
let address = success.address.raw

if let handler, let caution = handler.validate(address: address) {
addressState = .invalid
addressCautionState = .caution(caution)
} else {
addressState = .valid(address: address)
addressCautionState = .none
}
addressState = .valid(address: address)
addressCautionState = .none
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,6 @@ extension ZcashPreSendHandler: IPreSendHandler {
balanceSubject.eraseToAnyPublisher()
}

func validate(address: String) -> Caution? {
do {
_ = try adapter.validate(address: address, checkSendToSelf: true)
return nil
} catch {
return Caution(text: error.smartDescription, type: .error)
}
}

func hasMemo(address: String?) -> Bool {
guard let address, let addressType = try? adapter.validate(address: address, checkSendToSelf: true) else {
return false
Expand All @@ -68,6 +59,12 @@ extension ZcashPreSendHandler: IPreSendHandler {
}

func sendData(amount: Decimal, address: String, memo: String?) -> SendDataResult {
do {
_ = try adapter.validate(address: address, checkSendToSelf: true)
} catch {
return .invalid(cautions: [CautionNew(text: error.smartDescription, type: .error)])
}

guard let recipient = adapter.recipient(from: address) else {
return .invalid(cautions: [])
}
Expand Down

0 comments on commit 5ee539c

Please sign in to comment.