Files
raspberry/iOS/Wallet/Sources/Account/Service/AccountServiceChangeKey.swift
2022-05-27 20:21:01 +03:00

132 lines
6.0 KiB
Swift

//
// AccountServiceChangeKey.swift
// PayCash
//
// Created by Alexandr Serpokrylow on 16.02.2022.
// Copyright © 2022 AM. All rights reserved.
//
import Foundation
import EosioSwift
extension Account.Service {
class ChangeKey: Common.Service.Provider {
private(set) var accounts = [Account.Model.ChangeKey]()
private var requests = 0
func fetch(privateKey: String, keyType: Account.KeyType, _ completion: @escaping Completion.Network) {
guard let publicKey = privateKey.publicKey(), let newPrivateKey = try? EOSPrivateKey() else {
completion(.error(L10n.Error.Accounts.keyInvalid))
return
}
Network.accounts.fetch(publicKey: publicKey) { (collection) in
if (collection.isEmpty) {
completion(.error(L10n.Error.Accounts.empty))
} else {
self.requests = collection.count
collection.forEach { username in
Network.accounts.account(username, completion: { response in
DispatchQueue.global().async {
guard let accountInfo = response else {
completion(.error(L10n.Error.Accounts.empty))
return
}
let newAccounts = self.prepareAccountInfo(username: username,
publicKey: publicKey,
keyType: keyType,
newPrivateKey: newPrivateKey,
accountPermissions: accountInfo.permissions)
self.accounts += newAccounts
self.requests -= 1
if (self.requests == 0) {
DispatchQueue.main.async { completion(nil) }
}
}
})
}
}
}
}
private func prepareAccountInfo(username: String,
publicKey: String,
keyType: Account.KeyType,
newPrivateKey: EOSPrivateKey,
accountPermissions: [Permission]
) -> [Account.Model.ChangeKey] {
var accounts: [Account.Model.ChangeKey] = []
let permissions = accountPermissions.filter {
switch keyType {
case .active:
return $0.permName == Account.KeyType.active.rawValue && $0.requiredAuth.keys.first?.key == publicKey
case .owner:
return $0.requiredAuth.keys.first?.key == publicKey
}
}
.sorted { $0.permName > $1.permName }
permissions.forEach { permission in
accounts.append(Account.Model.ChangeKey(username: username, permission: permission, privateKey: newPrivateKey.base58, publicKey: newPrivateKey.publicKey.base58))
}
return accounts
}
func validatePrivateKey(privateKey: String) -> Bool {
let privateKey = try? EOSPrivateKey(base58: privateKey)
return privateKey != nil
}
func validatePublicKey(publicKey: String) -> Bool {
let publicKey = try? EOSPublicKey(base58: publicKey)
return publicKey != nil
}
func validateKeyPair(privateKey: String, publicKey: String) -> Bool {
guard let privateKey = try? EOSPrivateKey(base58: privateKey) else {
return false
}
return privateKey.publicKey.base58 == publicKey
}
func submit(privateKey: String, accounts: [Account.Model.ChangeKey], password: String, _ completion: @escaping (String?, NSError?) -> Void) {
var actions = [(contract: Network.Model.Contract, action: Network.Model.Blockchain.Action, data: Codable)]()
for account in accounts {
if let data = createChangeKeyData(account: account) {
actions.append((contract: .eosio, action: .updateauth, data: data))
}
}
Network.Service.Blockchain.execute(actions: actions, privateKeys: [privateKey]) { (result) in
if case .success(let trxId) = result {
Accounts().updateCredentialsIfNeeded(accounts: accounts, password: password)
completion(trxId, nil)
} else {
completion(nil, .error(result))
}
}
}
private func createChangeKeyData(account: Account.Model.ChangeKey) -> Network.Model.Blockchain.UpdateAuth? {
var keys: [Network.Model.Blockchain.KeyWeight] = []
guard let eosioPublicKey = (try? Data(eosioPublicKey: account.publicKey).toEosioK1PublicKey) else { return nil }
let key = Network.Model.Blockchain.KeyWeight(key: eosioPublicKey, weight: 1)
keys.append(key)
let auth = Network.Model.Blockchain.Authority(threshold: 1, keys: keys, waits: [], accounts: [])
let parent = account.permission.permName == Account.KeyType.active.rawValue ? Account.KeyType.owner.rawValue : ""
let permission = account.permission.permName
return Network.Model.Blockchain.UpdateAuth(account: account.username, permission: permission, parent: parent, auth: auth)
}
}
}