create ZircleService
This commit is contained in:
parent
b4d1eb8a0a
commit
74e1da5cdd
|
@ -52,6 +52,8 @@
|
||||||
0DB5330F24A623AF0090D722 /* sapling-spend.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330D24A623AF0090D722 /* sapling-spend.params */; };
|
0DB5330F24A623AF0090D722 /* sapling-spend.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330D24A623AF0090D722 /* sapling-spend.params */; };
|
||||||
0DB5331024A623AF0090D722 /* sapling-output.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330E24A623AF0090D722 /* sapling-output.params */; };
|
0DB5331024A623AF0090D722 /* sapling-output.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330E24A623AF0090D722 /* sapling-output.params */; };
|
||||||
0DB5331224A6413D0090D722 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB5331124A6413D0090D722 /* LazyView.swift */; };
|
0DB5331224A6413D0090D722 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB5331124A6413D0090D722 /* LazyView.swift */; };
|
||||||
|
0DB5331424A6B8B60090D722 /* memo.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB5331324A6B8B60090D722 /* memo.pb.swift */; };
|
||||||
|
0DC1B47B24AAA44B00AEF3D0 /* ZircleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC1B47A24AAA44B00AEF3D0 /* ZircleService.swift */; };
|
||||||
0DD7278924A5532300C36D27 /* AllZirclesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7278824A5532300C36D27 /* AllZirclesView.swift */; };
|
0DD7278924A5532300C36D27 /* AllZirclesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7278824A5532300C36D27 /* AllZirclesView.swift */; };
|
||||||
0DD7278B24A564AF00C36D27 /* ZircleListCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */; };
|
0DD7278B24A564AF00C36D27 /* ZircleListCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */; };
|
||||||
0DEE59A824A24B7300447C15 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DEE59A724A24B7300447C15 /* WelcomeView.swift */; };
|
0DEE59A824A24B7300447C15 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DEE59A724A24B7300447C15 /* WelcomeView.swift */; };
|
||||||
|
@ -128,6 +130,8 @@
|
||||||
0DB5330D24A623AF0090D722 /* sapling-spend.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-spend.params"; sourceTree = "<group>"; };
|
0DB5330D24A623AF0090D722 /* sapling-spend.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-spend.params"; sourceTree = "<group>"; };
|
||||||
0DB5330E24A623AF0090D722 /* sapling-output.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-output.params"; sourceTree = "<group>"; };
|
0DB5330E24A623AF0090D722 /* sapling-output.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-output.params"; sourceTree = "<group>"; };
|
||||||
0DB5331124A6413D0090D722 /* LazyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
0DB5331124A6413D0090D722 /* LazyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
||||||
|
0DB5331324A6B8B60090D722 /* memo.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = memo.pb.swift; sourceTree = "<group>"; };
|
||||||
|
0DC1B47A24AAA44B00AEF3D0 /* ZircleService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleService.swift; sourceTree = "<group>"; };
|
||||||
0DD7278824A5532300C36D27 /* AllZirclesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllZirclesView.swift; sourceTree = "<group>"; };
|
0DD7278824A5532300C36D27 /* AllZirclesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllZirclesView.swift; sourceTree = "<group>"; };
|
||||||
0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleListCard.swift; sourceTree = "<group>"; };
|
0DD7278A24A564AF00C36D27 /* ZircleListCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleListCard.swift; sourceTree = "<group>"; };
|
||||||
0DEE59A724A24B7300447C15 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
|
0DEE59A724A24B7300447C15 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -229,6 +233,8 @@
|
||||||
0D1366AA24991A6000F0EB54 /* Zircles */ = {
|
0D1366AA24991A6000F0EB54 /* Zircles */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0DC1B47924AAA43100AEF3D0 /* ZircleService */,
|
||||||
|
0DB5331324A6B8B60090D722 /* memo.pb.swift */,
|
||||||
0DB5330E24A623AF0090D722 /* sapling-output.params */,
|
0DB5330E24A623AF0090D722 /* sapling-output.params */,
|
||||||
0DB5330D24A623AF0090D722 /* sapling-spend.params */,
|
0DB5330D24A623AF0090D722 /* sapling-spend.params */,
|
||||||
0D64CEBE24A3D3A30080AA4F /* CombineSynchronizer.swift */,
|
0D64CEBE24A3D3A30080AA4F /* CombineSynchronizer.swift */,
|
||||||
|
@ -323,6 +329,14 @@
|
||||||
path = Neumorphic;
|
path = Neumorphic;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0DC1B47924AAA43100AEF3D0 /* ZircleService */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0DC1B47A24AAA44B00AEF3D0 /* ZircleService.swift */,
|
||||||
|
);
|
||||||
|
path = ZircleService;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
E7393F4D108BAE27C875D7F0 /* Pods */ = {
|
E7393F4D108BAE27C875D7F0 /* Pods */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -578,6 +592,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
0DC1B47B24AAA44B00AEF3D0 /* ZircleService.swift in Sources */,
|
||||||
0D6A22C9249AB3CA00B4E946 /* ZcashButton.swift in Sources */,
|
0D6A22C9249AB3CA00B4E946 /* ZcashButton.swift in Sources */,
|
||||||
0D64CEB924A3CDA90080AA4F /* URL+Zcash.swift in Sources */,
|
0D64CEB924A3CDA90080AA4F /* URL+Zcash.swift in Sources */,
|
||||||
0D64CEC524A41AF30080AA4F /* AppDetails.swift in Sources */,
|
0D64CEC524A41AF30080AA4F /* AppDetails.swift in Sources */,
|
||||||
|
@ -611,6 +626,7 @@
|
||||||
0D64CEBD24A3CDA90080AA4F /* SimpleLogger.swift in Sources */,
|
0D64CEBD24A3CDA90080AA4F /* SimpleLogger.swift in Sources */,
|
||||||
0D64CEBC24A3CDA90080AA4F /* BalanceUtils.swift in Sources */,
|
0D64CEBC24A3CDA90080AA4F /* BalanceUtils.swift in Sources */,
|
||||||
0D5142C824A16F9600F9AE2E /* CreateNewTypeOfZircle.swift in Sources */,
|
0D5142C824A16F9600F9AE2E /* CreateNewTypeOfZircle.swift in Sources */,
|
||||||
|
0DB5331424A6B8B60090D722 /* memo.pb.swift in Sources */,
|
||||||
0D64CEBB24A3CDA90080AA4F /* CameraAccessHelper.swift in Sources */,
|
0D64CEBB24A3CDA90080AA4F /* CameraAccessHelper.swift in Sources */,
|
||||||
0D64CEB424A3CDA90080AA4F /* SeedManagement.swift in Sources */,
|
0D64CEB424A3CDA90080AA4F /* SeedManagement.swift in Sources */,
|
||||||
0D64CEC324A4137D0080AA4F /* ZircleData.swift in Sources */,
|
0D64CEC324A4137D0080AA4F /* ZircleData.swift in Sources */,
|
||||||
|
|
|
@ -158,4 +158,20 @@ class CombineSynchronizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func latestHeight() -> Future<BlockHeight,Error> {
|
||||||
|
|
||||||
|
Future<BlockHeight,Error>() { promise in
|
||||||
|
|
||||||
|
DispatchQueue.global().async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
do {
|
||||||
|
promise(.success(try self.initializer.lightWalletService.latestBlockHeight()))
|
||||||
|
} catch {
|
||||||
|
promise(.failure(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,10 +101,9 @@ final class SeedManager {
|
||||||
There's no fate but what we make for ourselves - Sarah Connor
|
There's no fate but what we make for ourselves - Sarah Connor
|
||||||
*/
|
*/
|
||||||
func nukeWallet() {
|
func nukeWallet() {
|
||||||
nukeKeys()
|
for key in keychain.allKeys {
|
||||||
nukeSeed()
|
keychain.delete(key)
|
||||||
nukePhrase()
|
}
|
||||||
nukeBirthday()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,3 +112,45 @@ extension SeedManager: SeedProvider {
|
||||||
(try? exportSeed()) ?? []
|
(try? exportSeed()) ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension SeedManager {
|
||||||
|
func saveKeys(_ key: String, phrase: String,height: BlockHeight, spendingKey: String) throws {
|
||||||
|
guard keychain.get(heightKey(key)) == nil else {
|
||||||
|
throw SeedManagerError.alreadyImported
|
||||||
|
}
|
||||||
|
keychain.set(String(height), forKey: heightKey(key))
|
||||||
|
|
||||||
|
guard keychain.get(phraseKey(key)) == nil else {
|
||||||
|
throw SeedManagerError.alreadyImported
|
||||||
|
}
|
||||||
|
keychain.set(String(phrase), forKey: phraseKey(key))
|
||||||
|
|
||||||
|
guard keychain.get(spendingKeyKey(key)) == nil else {
|
||||||
|
throw SeedManagerError.alreadyImported
|
||||||
|
}
|
||||||
|
keychain.set(String(phrase), forKey: spendingKeyKey(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getZircleKeys(_ key: String) throws -> (height: BlockHeight, phrase: String, spendingKey: String)? {
|
||||||
|
guard let heightString = keychain.get(heightKey(key)),
|
||||||
|
let height = BlockHeight(heightString),
|
||||||
|
let phrase = keychain.get(phraseKey(key)),
|
||||||
|
let spendingKey = keychain.get(spendingKeyKey(key)) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return (height: height, phrase: phrase, spendingKey: spendingKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func heightKey(_ key: String) -> String {
|
||||||
|
key+"+height"
|
||||||
|
}
|
||||||
|
|
||||||
|
func phraseKey(_ key: String) -> String {
|
||||||
|
key+"+phrase"
|
||||||
|
}
|
||||||
|
|
||||||
|
func spendingKeyKey(_ key: String) -> String {
|
||||||
|
key+"+spending"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,51 +8,46 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
extension ZircleFrequency {
|
||||||
|
var textDescription: String {
|
||||||
|
switch self {
|
||||||
|
case .daily:
|
||||||
|
return "Daily"
|
||||||
|
case .weekly:
|
||||||
|
return "Weekly"
|
||||||
|
case .monthly:
|
||||||
|
return "Monthly"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension ZircleEndDate {
|
||||||
|
var optionIndex: Int {
|
||||||
|
switch self {
|
||||||
|
case .onDate(_):
|
||||||
|
return 0
|
||||||
|
case .atWill:
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var textDescription: String {
|
||||||
|
switch self {
|
||||||
|
case .atWill:
|
||||||
|
return "At Will"
|
||||||
|
case .onDate:
|
||||||
|
return "On Date"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
struct CreateNewZircleDescription: View {
|
struct CreateNewZircleDescription: View {
|
||||||
|
|
||||||
enum ZircleFrequency: Int {
|
|
||||||
case daily = 0
|
|
||||||
case weekly
|
|
||||||
case monthly
|
|
||||||
|
|
||||||
var textDescription: String {
|
|
||||||
switch self {
|
|
||||||
case .daily:
|
|
||||||
return "Daily"
|
|
||||||
case .weekly:
|
|
||||||
return "Weekly"
|
|
||||||
case .monthly:
|
|
||||||
return "Monthly"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
enum ZircleEndDate {
|
|
||||||
case onDate(date: Date)
|
|
||||||
case atWill
|
|
||||||
|
|
||||||
var optionIndex: Int {
|
|
||||||
switch self {
|
|
||||||
case .onDate(_):
|
|
||||||
return 0
|
|
||||||
case .atWill:
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var textDescription: String {
|
|
||||||
switch self {
|
|
||||||
case .atWill:
|
|
||||||
return "At Will"
|
|
||||||
case .onDate:
|
|
||||||
return "On Date"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@State var contributionFrequency: Int = ZircleFrequency.weekly.rawValue
|
@State var contributionFrequency: Int = ZircleFrequency.weekly.rawValue
|
||||||
@State var endDate: Int = ZircleEndDate.atWill.optionIndex
|
@State var endDate: Int = ZircleEndDate.atWill.optionIndex
|
||||||
@State var zircleEndDate = Date()
|
@State var zircleEndDate = Date()
|
||||||
|
@State var zircleName = ""
|
||||||
|
@State var contributionInZec: String = ""
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack {
|
ZStack {
|
||||||
Color.background.edgesIgnoringSafeArea(.all)
|
Color.background.edgesIgnoringSafeArea(.all)
|
||||||
|
@ -65,7 +60,7 @@ struct CreateNewZircleDescription: View {
|
||||||
.frame(alignment: .leading)
|
.frame(alignment: .leading)
|
||||||
Card(isOn: .constant(true),cornerRadius: 5,padding: 8) {
|
Card(isOn: .constant(true),cornerRadius: 5,padding: 8) {
|
||||||
|
|
||||||
TextField("some title text", text: .constant("Hackathon Happy Hour"))
|
TextField("some title text", text: $zircleName)
|
||||||
.foregroundColor(Color.textDarkGray)
|
.foregroundColor(Color.textDarkGray)
|
||||||
.font(.system(size: 14, weight: .heavy, design: .default))
|
.font(.system(size: 14, weight: .heavy, design: .default))
|
||||||
|
|
||||||
|
@ -80,9 +75,10 @@ struct CreateNewZircleDescription: View {
|
||||||
.frame(alignment: .leading)
|
.frame(alignment: .leading)
|
||||||
Card(isOn: .constant(true),cornerRadius: 5,padding: 8) {
|
Card(isOn: .constant(true),cornerRadius: 5,padding: 8) {
|
||||||
|
|
||||||
TextField("some title text", text: .constant("3 ZEC"))
|
TextField("ZEC to save", text: $contributionInZec)
|
||||||
.foregroundColor(Color.textDarkGray)
|
.foregroundColor(Color.textDarkGray)
|
||||||
.font(.system(size: 14, weight: .heavy, design: .default))
|
.font(.system(size: 14, weight: .heavy, design: .default))
|
||||||
|
.keyboardType(.decimalPad)
|
||||||
|
|
||||||
}
|
}
|
||||||
}.padding(.all, 0)
|
}.padding(.all, 0)
|
||||||
|
@ -111,7 +107,9 @@ struct CreateNewZircleDescription: View {
|
||||||
ZircleEndDate.atWill.textDescription
|
ZircleEndDate.atWill.textDescription
|
||||||
)
|
)
|
||||||
}.padding(.all, 0)
|
}.padding(.all, 0)
|
||||||
Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, label: {
|
Button(action: {
|
||||||
|
|
||||||
|
}, label: {
|
||||||
Text("Create New Zircle")
|
Text("Create New Zircle")
|
||||||
.font(.system(size: 20, weight: .bold, design: .default))
|
.font(.system(size: 20, weight: .bold, design: .default))
|
||||||
.shadow(color:Color(.sRGBLinear, red: 0.2, green: 0.2, blue: 0.2, opacity: 0.5), radius: 1, x: 0, y: 2)
|
.shadow(color:Color(.sRGBLinear, red: 0.2, green: 0.2, blue: 0.2, opacity: 0.5), radius: 1, x: 0, y: 2)
|
||||||
|
|
|
@ -0,0 +1,251 @@
|
||||||
|
//
|
||||||
|
// ZircleService.swift
|
||||||
|
// Zircles
|
||||||
|
//
|
||||||
|
// Created by Francisco Gindre on 6/29/20.
|
||||||
|
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
enum ZircleServiceError: Error {
|
||||||
|
case generalError(message: String)
|
||||||
|
}
|
||||||
|
protocol ZircleService {
|
||||||
|
func createNewZircle(name: String, goal zatoshi: Int64, frequency: ZircleFrequency, endDate: ZircleEndDate) throws -> Future<ZircleEntity, Error>
|
||||||
|
func closeZircle(name: String) throws
|
||||||
|
func contribute(zatoshi: Int64, zircle: ZircleEntity) throws
|
||||||
|
func allOpenZircles() throws -> [ZircleEntity]?
|
||||||
|
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 }
|
||||||
|
var zatoshi: Int64 { get set }
|
||||||
|
}
|
||||||
|
protocol ZircleContribution {
|
||||||
|
var from: String { get set }
|
||||||
|
var zatoshi: Int64 { get set }
|
||||||
|
var date: Date { get set }
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol ZircleEntity {
|
||||||
|
var name: String { get set}
|
||||||
|
var goal: Int64 { get set }
|
||||||
|
var frequency: Int {get set }
|
||||||
|
var endDate: TimeInterval { get set }
|
||||||
|
var accountIndex: Int {get set}
|
||||||
|
var address: String {get set}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ZircleFrequency: Int {
|
||||||
|
case daily = 0
|
||||||
|
case weekly
|
||||||
|
case monthly
|
||||||
|
|
||||||
|
}
|
||||||
|
enum ZircleEndDate {
|
||||||
|
case onDate(date: Date)
|
||||||
|
case atWill
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct ConcreteZircle: ZircleEntity {
|
||||||
|
var name: String
|
||||||
|
|
||||||
|
var goal: Int64
|
||||||
|
|
||||||
|
var frequency: Int
|
||||||
|
|
||||||
|
var endDate: TimeInterval
|
||||||
|
|
||||||
|
var accountIndex: Int
|
||||||
|
|
||||||
|
var address: String
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
import MnemonicSwift
|
||||||
|
extension CombineSynchronizer: ZircleService {
|
||||||
|
func closeZircle(name: String) throws {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func contribute(zatoshi: Int64, zircle: ZircleEntity) throws {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func allOpenZircles() throws -> [ZircleEntity]? {
|
||||||
|
nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func allContributions(from zircle: ZircleEntity) -> Future<[ZircleOverallContribution], Error> {
|
||||||
|
Future<[ZircleOverallContribution], Error>() { promise in
|
||||||
|
promise(.success([]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func openInvite(_ url: URL) -> Future<Int, Error> {
|
||||||
|
Future<Int, Error>() { promise in
|
||||||
|
promise(.success(-1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNewZircle(name: String, goal zatoshi: Int64, frequency: ZircleFrequency, endDate: ZircleEndDate) -> Future<ZircleEntity, Error> {
|
||||||
|
|
||||||
|
Future<ZircleEntity, Error>() { promise in
|
||||||
|
var storage = [AnyCancellable]()
|
||||||
|
|
||||||
|
DispatchQueue.global().async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
// Get latest height from chain and generate a mnemonic seed for this zircle
|
||||||
|
Publishers.Zip(self.latestHeight(),
|
||||||
|
Mnemonic.generatePublisher(strength: 24)
|
||||||
|
).sink(receiveCompletion: { error in
|
||||||
|
switch error {
|
||||||
|
case .failure(let e):
|
||||||
|
promise(.failure(e))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}, receiveValue: { (height, seedPhrase) in
|
||||||
|
guard let seedBytes = Mnemonic.deterministicSeedBytes(from: seedPhrase) else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "mnemonic bytes failed")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
// start derivation
|
||||||
|
let derivationHelper = self.initializer.keyDerivationHelper()
|
||||||
|
|
||||||
|
// derive extended spending keys, and extended Viewing Keys
|
||||||
|
guard let extendedSpendingKeys = try derivationHelper.deriveExtendedSpendingKeys(seed: seedBytes, accounts: 1),
|
||||||
|
let extendedSpendingKey = extendedSpendingKeys.first,
|
||||||
|
let extendedViewingKey = try derivationHelper.deriveExtendedFullViewingKey(extendedSpendingKey) else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "Key derivation error")))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// import extended viewing key
|
||||||
|
let accountIndex = try self.initializer.importExtendedFullViewingKey(extendedViewingKey)
|
||||||
|
|
||||||
|
// get zAddr for this zircle
|
||||||
|
|
||||||
|
guard let zAddr = self.initializer.getAddress(index: Int(accountIndex)) else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "coudn't get zAddr for account index: \(accountIndex)")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set end date per input
|
||||||
|
var end: TimeInterval = -1
|
||||||
|
|
||||||
|
switch endDate {
|
||||||
|
case .onDate(let date):
|
||||||
|
end = date.timeIntervalSince1970
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// create zircle struct
|
||||||
|
let zircle = ConcreteZircle(name: name,
|
||||||
|
goal: zatoshi,
|
||||||
|
frequency: frequency.rawValue,
|
||||||
|
endDate: end,
|
||||||
|
accountIndex: Int(accountIndex),
|
||||||
|
address: zAddr)
|
||||||
|
|
||||||
|
|
||||||
|
// get supporting wallet spending keys to create zircle
|
||||||
|
guard let mainSpendingKey = SeedManager.default.getKeys()?.first else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "error getting spending keys")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let freq = CreateZircleMessage.ContributionFrequency(rawValue: zircle.frequency) else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "could not create frequency with value \(zircle.frequency)")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// create protobut message for the memo
|
||||||
|
let createMessage = CreateZircleMessage.with { (createMsg) in
|
||||||
|
createMsg.name = zircle.name
|
||||||
|
createMsg.goal = UInt64(zircle.goal)
|
||||||
|
createMsg.frequency = freq
|
||||||
|
createMsg.end = UInt64(zircle.endDate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// not sure if this is ok, but I don't have a data interface
|
||||||
|
let memo = try createMessage.jsonString()
|
||||||
|
|
||||||
|
// double check that the resulting data won't be truncated. this should be caught earlier on UI
|
||||||
|
guard memo.utf8.count <= 512 else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "Zircle Message \"\(memo)\" is longer than 512 bytes - total: \(memo.utf8.count)")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// save before sending
|
||||||
|
try SeedManager.default.saveKeys(name,
|
||||||
|
phrase: seedPhrase,
|
||||||
|
height: height,
|
||||||
|
spendingKey: extendedSpendingKey)
|
||||||
|
// fund zircle
|
||||||
|
self.send(with: mainSpendingKey,
|
||||||
|
zatoshi: 1000,
|
||||||
|
to: zAddr,
|
||||||
|
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)
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
promise(.failure(error))
|
||||||
|
}
|
||||||
|
}).store(in: &storage)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func allContributions(from zircle: ZircleEntity) throws -> [ZircleOverallContribution] {
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
|
||||||
|
func openInvite(_ url: URL) throws {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Mnemonic {
|
||||||
|
static func generatePublisher(strength: Int) -> Future<String, Error> {
|
||||||
|
|
||||||
|
Future<String,Error>() { promise in
|
||||||
|
|
||||||
|
DispatchQueue.global().async {
|
||||||
|
guard let mnemonic = Mnemonic.generateMnemonic(strength: 24) else {
|
||||||
|
promise(.failure(ZircleServiceError.generalError(message: "Error generating mnemonic")))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
promise(.success(mnemonic))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue