An advanced Ethereum/EVM mobile wallet
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
alpha-wallet-ios/Trust/Transfer/Controllers/TransactionConfigurator.swift

164 lines
5.1 KiB

// Copyright SIX DAY LLC. All rights reserved.
import Foundation
import BigInt
import Result
import TrustKeystore
import JSONRPCKit
import APIKit
public struct PreviewTransaction {
let value: BigInt
let account: Account
let address: Address?
let contract: Address?
let nonce: Int
let data: Data
let gasPrice: BigInt
let gasLimit: BigInt
let transferType: TransferType
}
class TransactionConfigurator {
let session: WalletSession
let account: Account
let transaction: UnconfirmedTransaction
private let gasPrice: BigInt?
var configuration: TransactionConfiguration {
didSet {
configurationUpdate.value = configuration
}
}
lazy var calculatedGasPrice: BigInt = {
return self.gasPrice ?? configuration.gasPrice
}()
var configurationUpdate: Subscribable<TransactionConfiguration> = Subscribable(nil)
init(
session: WalletSession,
account: Account,
transaction: UnconfirmedTransaction,
gasPrice: BigInt?
) {
self.session = session
self.account = account
self.transaction = transaction
self.gasPrice = gasPrice
self.configuration = TransactionConfiguration(
gasPrice: min(max(gasPrice ?? GasPriceConfiguration.default, GasPriceConfiguration.min), GasPriceConfiguration.max),
gasLimit: GasLimitConfiguration.default,
data: Data()
)
}
func load(completion: @escaping (Result<Void, AnyError>) -> Void) {
switch transaction.transferType {
case .ether:
self.configuration = TransactionConfiguration(
gasPrice: calculatedGasPrice,
gasLimit: GasLimitConfiguration.default,
data: transaction.data ?? self.configuration.data
)
completion(.success(()))
case .token:
session.web3.request(request: ContractERC20Transfer(amount: transaction.value, address: transaction.to!.description)) { [unowned self] result in
switch result {
case .success(let res):
let data = Data(hex: res.drop0x)
self.configuration = TransactionConfiguration(
gasPrice: self.calculatedGasPrice,
gasLimit: 144000,
data: data
)
completion(.success(()))
case .failure(let error):
completion(.failure(error))
}
}
case .exchange:
// TODO
self.configuration = TransactionConfiguration(
gasPrice: calculatedGasPrice,
gasLimit: 300_000,
data: Data()
)
completion(.success(()))
}
estimateGasLimit()
}
func estimateGasLimit() {
let request = EstimateGasRequest(to: transaction.to, data: self.configuration.data)
Session.send(EtherServiceRequest(batch: BatchFactory().create(request))) { [weak self] result in
guard let `self` = self else { return }
switch result {
case .success(let block):
let gasLimit: BigInt = {
let limit = BigInt(block.drop0x, radix: 16) ?? BigInt()
if limit == BigInt(21000) {
return limit
}
return limit + (limit * 10 / 100)
}()
self.configuration = TransactionConfiguration(
gasPrice: self.calculatedGasPrice,
gasLimit: gasLimit,
data: self.configuration.data
)
case .failure: break
}
}
}
func previewTransaction() -> PreviewTransaction {
return PreviewTransaction(
value: transaction.value,
account: account,
address: transaction.to,
contract: .none,
nonce: 0,
data: configuration.data,
gasPrice: configuration.gasPrice,
gasLimit: configuration.gasLimit,
transferType: transaction.transferType
)
}
func signTransaction() -> SignTransaction {
let value: BigInt = {
switch transaction.transferType {
case .ether: return transaction.value
case .token, .exchange: return 0
}
}()
let address: Address? = {
switch transaction.transferType {
case .ether, .exchange: return transaction.to
case .token(let token): return token.address
}
}()
let signTransaction = SignTransaction(
value: value,
account: account,
to: address,
nonce: 0,
data: configuration.data,
gasPrice: configuration.gasPrice,
gasLimit: configuration.gasLimit,
chainID: session.config.chainID
)
return signTransaction
}
func update(configuration: TransactionConfiguration) {
self.configuration = configuration
}
}