tokenary/Encrypted Ink/Ethereum/Transaction.swift
2021-07-04 21:45:54 +03:00

135 lines
4.7 KiB
Swift

// Copyright © 2021 Encrypted Ink. All rights reserved.
import Foundation
import Web3Swift
struct Transaction {
let from: String
let to: String
var nonce: String?
var gasPrice: String?
var gas: String?
let value: String?
let data: String
var weiAmount: EthNumber {
if let value = value {
return EthNumber(hex: value)
} else {
return EthNumber(value: 0)
}
}
var hasFee: Bool {
return gas != nil && gasPrice != nil
}
var gasPriceGwei: Int? {
guard let gasPrice = gasPrice,
let currentAsDecimal = try? EthNumber(hex: gasPrice).value().toDecimal() else { return nil }
let current = NSDecimalNumber(decimal: currentAsDecimal).uintValue / 1_000_000_000
return Int(current)
}
func description(ethPrice: Double?) -> String {
let fee: String
if let gasPrice = gasPrice,
let gas = gas,
let a = try? EthNumber(hex: gasPrice).value().toNormalizedDecimal(power: 18),
let b = try? EthNumber(hex: gas).value().toDecimal() {
let c = NSDecimalNumber(decimal: a).multiplying(by: NSDecimalNumber(decimal: b))
let costString = cost(value: c, price: ethPrice)
fee = c.stringValue.prefix(7) + " ETH" + costString
} else {
fee = "Calculating…"
}
var result = [String]()
if let decimal = try? weiAmount.value().toNormalizedDecimal(power: 18) {
let decimalNumber = NSDecimalNumber(decimal: decimal)
let cost = cost(value: decimalNumber, price: ethPrice)
if let value = ethString(decimalNumber: decimalNumber) {
result.append("\(value) ETH" + cost)
}
}
result.append("Fee: " + fee)
result.append("Data: " + data)
return result.joined(separator: "\n\n")
}
private func cost(value: NSDecimalNumber, price: Double?) -> String {
guard let price = price else { return "" }
let cost = value.multiplying(by: NSDecimalNumber(value: price))
let formatter = NumberFormatter()
formatter.decimalSeparator = "."
formatter.maximumFractionDigits = 1
if let costString = formatter.string(from: cost) {
return " ≈ $\(costString)"
} else {
return ""
}
}
private func ethString(decimalNumber: NSDecimalNumber) -> String? {
let formatter = NumberFormatter()
formatter.decimalSeparator = "."
formatter.maximumFractionDigits = 12
return formatter.string(from: decimalNumber)
}
mutating func setGasPrice(value: Double, inRelationTo info: GasService.Info) {
let tickValues = info.sortedValues
let tickValuesCount = tickValues.count
guard value >= 0, value <= 100, tickValuesCount > 1 else { return }
if value.isZero, let min = tickValues.first {
setGasPrice(value: min)
return
} else if value == 100, let max = tickValues.last {
setGasPrice(value: max)
return
}
let step = Double(100) / Double(tickValuesCount - 1)
for i in 1..<tickValuesCount where value <= step * Double(i) {
let partialStep = value - step * Double(i - 1)
let previousTickValue = tickValues[i - 1]
let nextTickValue = tickValues[i]
let current = previousTickValue + UInt((partialStep / step) * Double(nextTickValue - previousTickValue))
setGasPrice(value: current)
return
}
}
private mutating func setGasPrice(value: UInt) {
gasPrice = try? EthNumber(decimal: String(value)).value().toHexString()
}
func currentGasInRelationTo(info: GasService.Info) -> Double {
guard let gasPrice = gasPrice,
let currentAsDecimal = try? EthNumber(hex: gasPrice).value().toDecimal() else { return 0 }
let current = NSDecimalNumber(decimal: currentAsDecimal).uintValue
let tickValues = info.sortedValues
let tickValuesCount = tickValues.count
guard tickValuesCount > 1 else { return 0 }
if current <= tickValues[0] {
return 0
} else if current >= tickValues[tickValuesCount - 1] {
return 100
}
let step = Double(100) / Double(tickValuesCount - 1)
for i in 1..<tickValuesCount where current < tickValues[i] {
let partialStep = Double(current - tickValues[i - 1]) / Double(tickValues[i] - tickValues[i - 1])
let fullSteps = Double(i - 1)
return (fullSteps + partialStep) * step
}
return 0
}
}