Skip to content

Commit

Permalink
Implement send handlers for Binance chain
Browse files Browse the repository at this point in the history
  • Loading branch information
ealymbaev committed May 6, 2024
1 parent cfd6bce commit 04861b5
Show file tree
Hide file tree
Showing 19 changed files with 352 additions and 44 deletions.
12 changes: 12 additions & 0 deletions UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2974,6 +2974,10 @@
D339A93F29126D2A00B895BE /* HsCryptoKit in Frameworks */ = {isa = PBXBuildFile; productRef = D339A93E29126D2A00B895BE /* HsCryptoKit */; };
D3447DEA25E38300009928D9 /* WalletConnectManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B968B299A67FC7FEAE3 /* WalletConnectManager.swift */; };
D3447DEB25E38300009928D9 /* WalletConnectManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11B35B968B299A67FC7FEAE3 /* WalletConnectManager.swift */; };
D34903172BE8DF48005F147B /* BinanceSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34903162BE8DF48005F147B /* BinanceSendHandler.swift */; };
D34903182BE8DF48005F147B /* BinanceSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34903162BE8DF48005F147B /* BinanceSendHandler.swift */; };
D349031A2BE8DF5F005F147B /* BinancePreSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34903192BE8DF5F005F147B /* BinancePreSendHandler.swift */; };
D349031B2BE8DF5F005F147B /* BinancePreSendHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D34903192BE8DF5F005F147B /* BinancePreSendHandler.swift */; };
D350DDB02AE2526E00CF1989 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D350DDAF2AE2526E00CF1989 /* Localizable.xcstrings */; };
D350DDB12AE2526E00CF1989 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D350DDAF2AE2526E00CF1989 /* Localizable.xcstrings */; };
D350DDB22AE27E3B00CF1989 /* AppWidget.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = D350DDB92AE27E3B00CF1989 /* AppWidget.intentdefinition */; };
Expand Down Expand Up @@ -4840,6 +4844,8 @@
D3285F5120BD158F00644076 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D3373D9420BEC7B30082BC4A /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
D3373DB120C52F640082BC4A /* LaunchScreen.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = "<group>"; };
D34903162BE8DF48005F147B /* BinanceSendHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinanceSendHandler.swift; sourceTree = "<group>"; };
D34903192BE8DF5F005F147B /* BinancePreSendHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BinancePreSendHandler.swift; sourceTree = "<group>"; };
D34E941B21F86C3500AD8E90 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D34E941C21F86C3500AD8E90 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
D350DDAF2AE2526E00CF1989 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
Expand Down Expand Up @@ -9161,6 +9167,8 @@
D054DAE22BE5123F0040B7C9 /* InitialTransactionSettings.swift */,
D3A580932BE8AA80003953F4 /* BitcoinSendSettingsView.swift */,
D3A580962BE8AA90003953F4 /* BitcoinSendSettingsViewModel.swift */,
D34903162BE8DF48005F147B /* BinanceSendHandler.swift */,
D34903192BE8DF5F005F147B /* BinancePreSendHandler.swift */,
);
path = SendNew;
sourceTree = "<group>";
Expand Down Expand Up @@ -9986,6 +9994,7 @@
11B3563E71C4AC16DFE8AB76 /* ActiveAccount.swift in Sources */,
6BCD530D2A161F4100993F20 /* ICloudBackupNameViewModel.swift in Sources */,
11B35056B69A06C8CFF3CBB6 /* BackupModule.swift in Sources */,
D349031B2BE8DF5F005F147B /* BinancePreSendHandler.swift in Sources */,
D0A980AA2B5E3C0900127AF4 /* StepChangeButtonsView.swift in Sources */,
11B3598BE9C7A456A70B5DFD /* BackupVerifyWordsViewModel.swift in Sources */,
6BE8A0822ADE2FAB0012DE7F /* CurrencyManager.swift in Sources */,
Expand Down Expand Up @@ -10078,6 +10087,7 @@
58AAA0444AD1508917D349CF /* UniswapSettingsService.swift in Sources */,
D0C2261A2A66A703007101F7 /* PersonalSupportViewModel.swift in Sources */,
58AAA52F2D68C5C4397C4D10 /* UniswapSettings.swift in Sources */,
D34903182BE8DF48005F147B /* BinanceSendHandler.swift in Sources */,
58AAA81C7A95558DBD560C90 /* OneInchSettings.swift in Sources */,
6BCD53092A161F4100993F20 /* ICloudBackupNameService.swift in Sources */,
58AAA5A70BBDBD3A9D572261 /* OneInchSettingsService.swift in Sources */,
Expand Down Expand Up @@ -11524,6 +11534,7 @@
D02A67C8272A7460009B2C1C /* CoinTweetsViewController.swift in Sources */,
D02A67C2272A7460009B2C1C /* TwitterText.swift in Sources */,
6BE8A0812ADE2FAB0012DE7F /* CurrencyManager.swift in Sources */,
D349031A2BE8DF5F005F147B /* BinancePreSendHandler.swift in Sources */,
11B359F73F1D626BF832977F /* BackupModule.swift in Sources */,
D0A980A92B5E3C0900127AF4 /* StepChangeButtonsView.swift in Sources */,
6BCD530C2A161F4100993F20 /* ICloudBackupNameViewModel.swift in Sources */,
Expand Down Expand Up @@ -11616,6 +11627,7 @@
58AAA63F99B1FC1B88B5C8A0 /* UniswapSettings.swift in Sources */,
58AAAD97F2A1F00258CF9E00 /* OneInchSettings.swift in Sources */,
D0C226192A66A703007101F7 /* PersonalSupportViewModel.swift in Sources */,
D34903172BE8DF48005F147B /* BinanceSendHandler.swift in Sources */,
58AAA126020F429D94D77A76 /* OneInchSettingsService.swift in Sources */,
58AAAB67059E3F289F557860 /* OneInchSettingsViewModel.swift in Sources */,
58AAA71839C54D05E04BC2EC /* UniswapSettingsDataSource.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import RxSwift

class BinanceAdapter {
static let confirmationsThreshold = 1
static let transferFee: Decimal = 0.000075
static let transferFee: Decimal = .init(string: "0.000075") ?? 0.000075

private let binanceKit: BinanceChainKit
private let feeToken: Token
Expand Down Expand Up @@ -144,6 +144,10 @@ extension BinanceAdapter: ISendBinanceAdapter {
binanceKit.sendSingle(symbol: asset.symbol, to: address, amount: amount, memo: memo ?? "")
.map { _ in () }
}

func send(amount: Decimal, address: String, memo: String?) async throws -> String {
try await binanceKit.send(symbol: asset.symbol, to: address, amount: amount, memo: memo ?? "")
}
}

extension BinanceAdapter: ITransactionsAdapter {
Expand Down
1 change: 1 addition & 0 deletions UnstoppableWallet/UnstoppableWallet/Core/Protocols.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ protocol ISendBinanceAdapter {
func validate(address: String) throws
var fee: Decimal { get }
func sendSingle(amount: Decimal, address: String, memo: String?) -> Single<Void>
func send(amount: Decimal, address: String, memo: String?) async throws -> String
}

protocol ISendZcashAdapter {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Combine
import Foundation
import MarketKit
import RxSwift

class BinancePreSendHandler {
private let token: Token
private let adapter: ISendBinanceAdapter & IBalanceAdapter

private let balanceStateSubject = PassthroughSubject<AdapterState, Never>()
private let balanceDataSubject = PassthroughSubject<BalanceData, Never>()

private let disposeBag = DisposeBag()

init(token: Token, adapter: ISendBinanceAdapter & IBalanceAdapter) {
self.token = token
self.adapter = adapter

adapter.balanceStateUpdatedObservable
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.subscribe { [weak self] state in
self?.balanceStateSubject.send(state)
}
.disposed(by: disposeBag)

adapter.balanceDataUpdatedObservable
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.subscribe { [weak self] _ in
self?.onUpdateBalance()
}
.disposed(by: disposeBag)
}

private func onUpdateBalance() {
balanceDataSubject.send(BalanceData(available: adapter.availableBalance))
}
}

extension BinancePreSendHandler: IPreSendHandler {
var hasMemo: Bool {
true
}

var balanceState: AdapterState {
adapter.balanceState
}

var balanceStatePublisher: AnyPublisher<AdapterState, Never> {
balanceStateSubject.eraseToAnyPublisher()
}

var balanceData: BalanceData {
BalanceData(available: adapter.availableBalance)
}

var balanceDataPublisher: AnyPublisher<BalanceData, Never> {
balanceDataSubject.eraseToAnyPublisher()
}

func sendData(amount: Decimal, address: String, memo: String?) -> SendData? {
let memo = memo?.trimmingCharacters(in: .whitespaces)
return .binance(token: token, amount: amount, address: address, memo: memo.flatMap { $0.isEmpty ? nil : $0 })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import Foundation
import MarketKit

class BinanceSendHandler {
let baseToken: Token
private let token: Token
private let amount: Decimal
private let address: String
private let memo: String?
private var adapter: ISendBinanceAdapter

init(baseToken: Token, token: Token, amount: Decimal, address: String, memo: String?, adapter: ISendBinanceAdapter) {
self.baseToken = baseToken
self.token = token
self.amount = amount
self.address = address
self.memo = memo
self.adapter = adapter
}
}

extension BinanceSendHandler: ISendHandler {
func sendData(transactionSettings _: TransactionSettings?) async throws -> ISendData {
SendData(
token: token,
amount: amount,
address: address,
memo: memo,
fee: adapter.fee
)
}

func send(data: ISendData) async throws {
guard let data = data as? SendData else {
throw SendError.invalidData
}

_ = try await adapter.send(amount: data.amount, address: data.address, memo: data.memo)
}
}

extension BinanceSendHandler {
class SendData: ISendData {
private let token: Token
let amount: Decimal
let address: String
let memo: String?
private let fee: Decimal

init(token: Token, amount: Decimal, address: String, memo: String?, fee: Decimal) {
self.token = token
self.amount = amount
self.address = address
self.memo = memo
self.fee = fee
}

var feeData: FeeData? {
nil
}

var canSend: Bool {
true
}

var rateCoins: [Coin] {
[token.coin]
}

func cautions(baseToken _: Token) -> [CautionNew] {
[]
}

func sections(baseToken: Token, currency: Currency, rates: [String: Decimal]) -> [[SendField]] {
var fields: [SendField] = [
.amount(
title: "send.confirmation.you_send".localized,
token: token,
coinValueType: .regular(coinValue: CoinValue(kind: .token(token: token), value: amount)),
currencyValue: rates[token.coin.uid].map { CurrencyValue(currency: currency, value: $0 * amount) },
type: .neutral
),
.address(
title: "send.confirmation.to".localized,
value: address,
blockchainType: .binanceChain
),
]

if let memo {
fields.append(.levelValue(title: "send.confirmation.memo".localized, value: memo, level: .regular))
}

return [
fields,
[
.value(
title: "fee_settings.network_fee".localized,
description: .init(title: "fee_settings.network_fee".localized, description: "fee_settings.network_fee.info".localized),
coinValue: CoinValue(kind: .token(token: baseToken), value: fee),
currencyValue: rates[baseToken.coin.uid].map { CurrencyValue(currency: currency, value: fee * $0) },
formatFull: true
),
],
]
}
}
}

extension BinanceSendHandler {
enum SendError: Error {
case invalidData
}
}

extension BinanceSendHandler {
static func instance(token: Token, amount: Decimal, address: String, memo: String?) -> BinanceSendHandler? {
guard let baseToken = try? App.shared.coinManager.token(query: .init(blockchainType: .binanceChain, tokenType: .native)) else {
return nil
}

guard let adapter = App.shared.adapterManager.adapter(for: token) as? ISendBinanceAdapter else {
return nil
}

return BinanceSendHandler(
baseToken: baseToken,
token: token,
amount: amount,
address: address,
memo: memo,
adapter: adapter
)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import BigInt
import BitcoinCore
import Combine
import Foundation
import MarketKit
import RxSwift
import SwiftUI

class BitcoinPreSendHandler {
Expand All @@ -13,9 +15,28 @@ class BitcoinPreSendHandler {
var pluginData = [UInt8: IPluginData]()
var unspentOutputs: [UnspentOutputInfo]?

private let balanceStateSubject = PassthroughSubject<AdapterState, Never>()
private let balanceDataSubject = PassthroughSubject<BalanceData, Never>()

private let disposeBag = DisposeBag()

init(token: Token, adapter: BitcoinBaseAdapter) {
self.token = token
self.adapter = adapter

adapter.balanceStateUpdatedObservable
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.subscribe { [weak self] state in
self?.balanceStateSubject.send(state)
}
.disposed(by: disposeBag)

adapter.balanceDataUpdatedObservable
.observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.subscribe { [weak self] balanceData in
self?.balanceDataSubject.send(balanceData)
}
.disposed(by: disposeBag)
}
}

Expand All @@ -28,6 +49,22 @@ extension BitcoinPreSendHandler: IPreSendHandler {
true
}

var balanceState: AdapterState {
adapter.balanceState
}

var balanceStatePublisher: AnyPublisher<AdapterState, Never> {
balanceStateSubject.eraseToAnyPublisher()
}

var balanceData: BalanceData {
adapter.balanceData
}

var balanceDataPublisher: AnyPublisher<BalanceData, Never> {
balanceDataSubject.eraseToAnyPublisher()
}

func settingsView(onChangeSettings: @escaping () -> Void) -> AnyView {
let view = ThemeNavigationView {
BitcoinSendSettingsView(handler: self, onChangeSettings: onChangeSettings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ extension BitcoinSendHandler: ISendHandler {
token
}

var syncingText: String? {
nil
}

var expirationDuration: Int? {
10
}
Expand Down
Loading

0 comments on commit 04861b5

Please sign in to comment.