// // ResourcesServiceSetupPerformance.swift // Wallet // // Created by Igor Danich on 19.08.2020. // Copyright © 2020 List. All rights reserved. // import Foundation extension Resources.Service.Setup { class Performance: Common.Service.Provider { let performance: Resources.Service.Performance private let _staked: Resources.Service.Staked var title: String { let cpu = Resources.Model.Performance.Kind.cpu let net = Resources.Model.Performance.Kind.net return net.prefix.isEmpty ? "\(cpu.name)/\(net.name)" : "\(cpu.prefix)/\(net.prefix) (\(cpu.name)/\(net.name))" } enum Action: String, CommonMenuMappable { case stake case unstake var title: String { "resources.setup.action.\(rawValue)".localized } func toMenu() -> Common.Model.Menu { .menu(uuid: rawValue, title: title) } } let actions: [Action] = [.stake, .unstake] private var _action: Action? var action: Action? { get { _action } set { _action = newValue;clear() } } private var _isOtherEnabled = false var isOtherEnabled: Bool { get { _isOtherEnabled } set { _isOtherEnabled = newValue _otherAccount = "" transfer = false update() } } private var _otherAccount = "" var otherAccount: String { get { _otherAccount } set { _otherAccount = newValue;update() } } var transfer = false private(set) var submitText: String? private var _netAmount = "" var netAmount: String { get { _netAmount } set { _netAmount = newValue;update() } } private var _cpuAmount = "" var cpuAmount: String { get { _cpuAmount } set { _cpuAmount = newValue;update() } } private(set) var isValid = false var balance: Decimal { Wallet.Service.Tokens.shared.balances.collection.first(where: { $0.contract == Network.servers.current.contract(.eosioToken) && $0.symbol.uppercased() == "EOS" })?.amount ?? 0 } var balanceText: String { Wallet.Service.Tokens.shared.balances.collection.first(where: { $0.contract == Network.servers.current.contract(.eosioToken) && $0.symbol.uppercased() == "EOS" })?.description ?? "" } init(account: String) { _staked = .init(account: account) performance = .init(account: account) } var didUpdate: (() -> Void)? var didReload: (() -> Void)? func clear(force: Bool = false) { if force { _action = nil performance.clear() } _isOtherEnabled = false _otherAccount = "" transfer = false _cpuAmount = "" _netAmount = "" isValid = false submitText = "" didReload?() update() } func fetch() { performance.fetch { _ in self._staked.fetch { _ in self.didReload?() self.update() } } } var staked: [Resources.Model.Staked] { _staked.collection } private func update() { let value = netAmount.toDecimal() + cpuAmount.toDecimal() let string = value.toString(max: 4, symbol: "EOS") let isAvailable = action == .stake ? self.balance >= value : getSumUnstakeAmount() >= value if let action = action { isValid = isOtherEnabled ? (!otherAccount.isEmpty && value > 0 && isAvailable) : (value > 0 && isAvailable) submitText = action == .stake ? L10n.Resources.Setup.Submit.stake(string) : L10n.Resources.Setup.Submit.unstake(string) } else { isValid = false submitText = "" } didUpdate?() } func getSumUnstakeAmount() -> Decimal { if isOtherEnabled { return staked.map { $0.cpu_weight.toDecimal() }.reduce(0, +) + staked.map { $0.net_weight.toDecimal() }.reduce(0, +) } else { return performance[.cpu].stakedByMe.toDecimal() + performance[.net].stakedByMe.toDecimal() } } func getAvailableUnstakeAmount(isCpu: Bool) -> Decimal { if isOtherEnabled { return isCpu ? staked.map { $0.cpu_weight.toDecimal() }.reduce(0, +) : staked.map { $0.net_weight.toDecimal() }.reduce(0, +) } else { return isCpu ? performance[.cpu].stakedByMe.toDecimal() : performance[.net].stakedByMe.toDecimal() } } func refund(privateKey: String, _ completion: @escaping (NSError?) -> Void) { Network.Service.Blockchain.execute(contract: .eosio, action: .refund, data: [ "owner" : performance.account ], privateKeys: [privateKey]) { (result) in completion(.error(result)) } } // swiftlint:disable identifier_name private struct StakeRequest: Codable { let from: String let receiver: String let stake_net_quantity: String let stake_cpu_quantity: String let transfer: Bool } // swiftlint:disable identifier_name private struct UnstakeRequest: Codable { let from: String let receiver: String let unstake_net_quantity: String let unstake_cpu_quantity: String } func submit(privateKey: String, _ completion: @escaping Completion.Network) { guard let action = action, isValid else { return } switch action { case .stake: Network.Service.Blockchain.execute( contract: .eosio, action: .delegatebw, data: StakeRequest( from: performance.account, receiver: isOtherEnabled ? otherAccount : performance.account, stake_net_quantity: netAmount.toDecimal().toString(precision: .eosioToken), stake_cpu_quantity: cpuAmount.toDecimal().toString(precision: .eosioToken), transfer: isOtherEnabled ? transfer : false ), privateKeys: [privateKey] ) { (result) in completion(.error(result)) } case .unstake: Network.Service.Blockchain.execute( contract: .eosio, action: .undelegatebw, data: UnstakeRequest( from: performance.account, receiver: isOtherEnabled ? otherAccount : performance.account, unstake_net_quantity: netAmount.toDecimal().toString(precision: .eosioToken), unstake_cpu_quantity: cpuAmount.toDecimal().toString(precision: .eosioToken) ), privateKeys: [privateKey] ) { (result) in completion(.error(result)) } } } } }