last hackathon effort

This commit is contained in:
Francisco Gindre 2020-07-08 13:00:05 -03:00
parent 1e336b256b
commit 0f7ed09c81
4 changed files with 144 additions and 35 deletions

View File

@ -227,8 +227,8 @@
0D64CEB124A3CDA90080AA4F /* CameraAccessHelper.swift */,
0D64CEAE24A3CDA80080AA4F /* MnemonicSeedPhraseHandling.swift */,
0D64CEAC24A3CDA80080AA4F /* MnemonicSeedPhraseProvider.swift */,
0D64CEAD24A3CDA80080AA4F /* QRCodeGenerator.swift */,
0D64CEAA24A3CDA80080AA4F /* SeedManagement.swift */,
0D64CEAD24A3CDA80080AA4F /* QRCodeGenerator.swift */,
0D64CEB324A3CDA90080AA4F /* SimpleLogger.swift */,
0D64CEAB24A3CDA80080AA4F /* String+Zcash.swift */,
0D64CEAF24A3CDA80080AA4F /* URL+Zcash.swift */,

View File

@ -10,6 +10,7 @@ import Foundation
class ZircleDataStorage {
static let usernameKey = "zircleusername"
static let autoIdKey = "autoid"
static var `default`: ZircleDataStorage = ZircleDataStorage()
private init() {}
@ -21,4 +22,13 @@ class ZircleDataStorage {
UserDefaults.standard.string(forKey: Self.usernameKey) ?? ""
}
var autoId: String {
if let autoid = UserDefaults.standard.string(forKey: Self.autoIdKey) {
return autoid
}
let newId = "zirclesUser\(Int.random(in: 0 ... Int.max))"
UserDefaults.standard.setValue(newId, forKey: Self.autoIdKey)
return newId
}
}

View File

@ -108,7 +108,7 @@ struct CreateNewZircleDescription: View {
)
}.padding(.all, 0)
Button(action: {
// ZircleServic
}, label: {
Text("Create New Zircle")
.font(.system(size: 20, weight: .bold, design: .default))

View File

@ -8,19 +8,21 @@
import Foundation
import Combine
import ZcashLightClientKit
enum ZircleServiceError: Error {
case generalError(message: String)
}
protocol ZircleService {
func createNewZircle(name: String, goal zatoshi: Int64, frequency: ZircleFrequency, endDate: ZircleEndDate, spendingKey: String) throws -> Future<ZircleEntity, Error>
func closeZircle(name: String) throws
func contribute(zatoshi: Int64, zircle: ZircleEntity) throws
func allOpenZircles() throws -> [ZircleEntity]?
func contribute(zatoshi: Int64, zircle: ZircleEntity) -> Future<PendingTransactionEntity, Error>
func allOpenZircles() -> Future<[ZircleEntity], Error>
func allContributions(from zircle: ZircleEntity) -> Future<[ZircleOverallContribution],Error>
func openInvite(_ url: URL) -> Future<Int,Error>
}
protocol ZircleOverallContribution {
var from: String { get set }
var zAddr: String { get set }
@ -45,8 +47,8 @@ enum ZircleFrequency: Int {
case daily = 0
case weekly
case monthly
}
enum ZircleEndDate {
case onDate(date: Date)
case atWill
@ -73,17 +75,103 @@ import MnemonicSwift
extension CombineSynchronizer: ZircleService {
func allOpenZircles() -> Future<[ZircleEntity], Error> {
Future<[ZircleEntity], Error>() { promise in
DispatchQueue.global().async { [weak self] in
guard let self = self else {
return
}
let accountRepository = AccountRepositoryBuilder.repository(initializer: self.initializer)
guard let accounts = try? accountRepository.getAccounts() else {
promise(.failure(ZircleServiceError.generalError(message: "could not get accounts")))
return
}
do {
var zircles = [ZircleEntity]()
for account in accounts {
let foundZircles = try self.synchronizer.allClearedTransactions(accountIndex: account.account)
.compactMap({ (confirmedTx) -> ZircleEntity? in
guard let memo = confirmedTx.memo?.asZcashTransactionMemo() else {
return nil
}
let zircle = try CreateZircleMessage(jsonString: memo)
return ConcreteZircle(name: zircle.name, goal: Int64(zircle.goal), frequency: zircle.frequency.rawValue, endDate: TimeInterval(zircle.end), accountIndex: account.account, address: account.address)
})
zircles.append(contentsOf: foundZircles)
}
promise(.success(zircles))
} catch {
promise(.failure(ZircleServiceError.generalError(message: "error: \(error)")))
}
}
}
}
func closeZircle(name: String) throws {
}
func contribute(zatoshi: Int64, zircle: ZircleEntity) throws {
func contribute(zatoshi: Int64, zircle: ZircleEntity) -> Future<PendingTransactionEntity, Error> {
Future<PendingTransactionEntity, Error>() { promise in
guard let mainSpendingKey = SeedManager.default.getKeys()?.first else {
return
}
guard let replyToAddr = self.initializer.getAddress() else {
promise(.failure(ZircleServiceError.generalError(message: "could not create contribution")))
return
}
let contribution = ContributionJoin.with { (contrib) in
contrib.autoid = ZircleDataStorage.default.autoId
contrib.replyTo = replyToAddr
contrib.from = ZircleDataStorage.default.username
}
guard let contributionMemo = try? contribution.jsonString() else {
promise(.failure(ZircleServiceError.generalError(message: "could not create contribution")))
return
}
guard contributionMemo.count <= 512 else {
promise(.failure(ZircleServiceError.generalError(message: "could not create contribution. contribution message exceeds memo size")))
return
}
self.send(with: mainSpendingKey,
zatoshi: zatoshi,
to: zircle.address,
memo: contributionMemo,
from: zircle.accountIndex)
.sink { (errorCompletion) in
switch errorCompletion {
case .failure(let error):
promise(.failure(error))
default:
break
}
} receiveValue: { (pendingTransaction) in
promise(.success(pendingTransaction))
}.store(in: &self.cancellables)
}
}
func allOpenZircles() throws -> [ZircleEntity]? {
nil
}
func allContributions(from zircle: ZircleEntity) -> Future<[ZircleOverallContribution], Error> {
Future<[ZircleOverallContribution], Error>() { promise in
@ -132,8 +220,8 @@ extension CombineSynchronizer: ZircleService {
return
}
// import extended viewing key
let accountIndex = try self.initializer.importExtendedFullViewingKey(extendedViewingKey)
@ -157,15 +245,15 @@ extension CombineSynchronizer: ZircleService {
// create zircle struct
let zircle = ConcreteZircle(name: name,
goal: zatoshi,
frequency: frequency.rawValue,
endDate: end,
accountIndex: Int(accountIndex),
address: zAddr)
goal: zatoshi,
frequency: frequency.rawValue,
endDate: end,
accountIndex: Int(accountIndex),
address: zAddr)
// get supporting wallet spending keys to create zircle
guard let freq = CreateZircleMessage.ContributionFrequency(rawValue: zircle.frequency) else {
promise(.failure(ZircleServiceError.generalError(message: "could not create frequency with value \(zircle.frequency)")))
@ -189,10 +277,10 @@ extension CombineSynchronizer: ZircleService {
return
}
// save before sending
try SeedManager.default.saveKeys(name,
phrase: seedPhrase,
height: height,
spendingKey: extendedSpendingKey)
try SeedManager.default.saveKeys(name,
phrase: seedPhrase,
height: height,
spendingKey: extendedSpendingKey)
// fund zircle
self.send(with: spendingKey,
zatoshi: 1000,
@ -200,16 +288,16 @@ extension CombineSynchronizer: ZircleService {
memo: memo,
from: 0)
.sink { errorSubscriber in
switch errorSubscriber {
case .failure(let underlyingError):
promise(.failure(underlyingError))
default:
break
}
} receiveValue: { (p) in
promise(.success(zircle))
}.store(in: &storage)
switch errorSubscriber {
case .failure(let underlyingError):
promise(.failure(underlyingError))
default:
break
}
} receiveValue: { (p) in
promise(.success(zircle))
}.store(in: &storage)
} catch {
promise(.failure(error))
}
@ -225,6 +313,17 @@ extension CombineSynchronizer: ZircleService {
}
func openInvite(_ url: URL) throws {
guard let invite = LiberatedInviteHandler.parseInvite(url) else {
throw ZircleServiceError.generalError(message: "URL: \(url) - is not a valid liberated invite url")
}
// this should now rewind and try to sync again.
self.stop()
try initializer.rewindTo(invite.height)
self.start(retry: true)
}
}