From a0013cd96571ee446e4e5317e8e4b54d0c65d471 Mon Sep 17 00:00:00 2001 From: 0xChqrles Date: Wed, 19 Jun 2024 10:06:20 +0200 Subject: [PATCH] Setup config --- app/App/Constants/Configuration.swift | 42 +++ app/App/Constants/Constants.swift | 12 +- app/App/Models/Model.swift | 85 +++--- app/App/Navigation/ContentView.swift | 4 +- app/App/Navigation/ErrorView.swift | 23 ++ .../Services/VaultAPI/Models/APIRequest.swift | 16 ++ .../VaultAPI/Models/DataContainer.swift | 14 - .../Services/VaultAPI/Models/Deployment.swift | 13 + app/App/Services/VaultAPI/Models/Empty.swift | 10 + app/App/Services/VaultAPI/Models/Error.swift | 13 + .../Services/VaultAPI/Models/Execution.swift | 12 + .../Services/VaultAPI/Models/VaultError.swift | 1 + .../VaultAPI/Models/VaultResponse.swift | 19 -- .../Requests/ExecuteFromOutside.swift | 38 +++ .../VaultAPI/Requests/GetBalance.swift | 5 + .../Services/VaultAPI/Requests/GetOTP.swift | 35 +++ .../VaultAPI/Requests/VerifyOTP.swift | 42 +++ .../VaultAPI/Utils/BodyParamsEncoder.swift | 21 ++ .../VaultAPI/Utils/HTTPParameter.swift | 5 + .../Services/VaultAPI/VaultAPIClient.swift | 258 ++++-------------- app/Dev.xcconfig | 11 + app/Prod.xcconfig | 11 + app/Vault-Info.plist | 5 +- app/Vault.xcodeproj/project.pbxproj | 157 ++++++----- .../xcschemes/Vault(Development).xcscheme | 12 - .../xcschemes/Vault(Staging).xcscheme | 7 - 26 files changed, 491 insertions(+), 380 deletions(-) create mode 100644 app/App/Constants/Configuration.swift create mode 100644 app/App/Navigation/ErrorView.swift delete mode 100644 app/App/Services/VaultAPI/Models/DataContainer.swift create mode 100644 app/App/Services/VaultAPI/Models/Deployment.swift create mode 100644 app/App/Services/VaultAPI/Models/Empty.swift create mode 100644 app/App/Services/VaultAPI/Models/Error.swift create mode 100644 app/App/Services/VaultAPI/Models/Execution.swift delete mode 100644 app/App/Services/VaultAPI/Models/VaultResponse.swift create mode 100644 app/App/Services/VaultAPI/Requests/ExecuteFromOutside.swift create mode 100644 app/App/Services/VaultAPI/Requests/GetOTP.swift create mode 100644 app/App/Services/VaultAPI/Requests/VerifyOTP.swift create mode 100644 app/App/Services/VaultAPI/Utils/BodyParamsEncoder.swift create mode 100644 app/Dev.xcconfig create mode 100644 app/Prod.xcconfig diff --git a/app/App/Constants/Configuration.swift b/app/App/Constants/Configuration.swift new file mode 100644 index 00000000..8e6ab2ce --- /dev/null +++ b/app/App/Constants/Configuration.swift @@ -0,0 +1,42 @@ +// +// Configuration.swift +// Vault +// +// Created by Charles Lanier on 18/06/2024. +// + +import Foundation + +enum AppConfiguration { + enum Error: Swift.Error { + case missingKey, invalidValue + } + + static func value(for key: String) throws -> T where T: LosslessStringConvertible { + guard let object = Bundle.main.object(forInfoDictionaryKey: key) else { + throw Error.missingKey + } + + switch object { + case let value as T: + return value + case let string as String: + guard let value = T(string) else { fallthrough } + return value + default: + throw Error.invalidValue + } + } + + enum API { + static var baseURL: URL? { + do { + let base: String = try AppConfiguration.value(for: "API_BASE_URL") + + return URL(string: "https://" + base) + } catch { + return nil + } + } + } +} diff --git a/app/App/Constants/Constants.swift b/app/App/Constants/Constants.swift index d7626f33..c005d276 100644 --- a/app/App/Constants/Constants.swift +++ b/app/App/Constants/Constants.swift @@ -24,23 +24,15 @@ struct Constants { // MARK: ENV - static let vaultBaseURL: URL = { + static let vaultBaseURL: URL? = { guard let urlString = ProcessInfo.processInfo.environment["VAULT_API_BASE_URL"], let url = URL(string: urlString) else { - fatalError("Vault API Base URL not configured properly.") + return nil } return url }() - static let starknetRpcApiKey: String = { - guard let apiKey = ProcessInfo.processInfo.environment["STARKNET_RPC_API_KEY"] else { - fatalError("Starknet RPC API key not configured properly.") - } - - return apiKey - }() - // MARK: ICONS struct Icons { diff --git a/app/App/Models/Model.swift b/app/App/Models/Model.swift index 95050459..a8f855c2 100644 --- a/app/App/Models/Model.swift +++ b/app/App/Models/Model.swift @@ -33,6 +33,7 @@ class Model: ObservableObject { // App @Published var isLoading = false @Published var showMessage = false + @Published var isProperlyConfigured: Bool // Sending USDC @Published var recipientContact: Contact? @@ -86,28 +87,18 @@ class Model: ObservableObject { .sorted { $0.name < $1.name } }() - private lazy var provider: StarknetProviderProtocol = StarknetProvider(url: "https://rpc.nethermind.io/sepolia-juno/?apikey=\(Constants.starknetRpcApiKey)")! - private lazy var signer = P256Signer() - private lazy var account: StarknetAccountProtocol = { - return StarknetAccount( - address: Felt(stringLiteral: self.address), - signer: self.signer, - provider: self.provider, - chainId: .sepolia, - cairoVersion: .one - ) - }() - init(vaultService: VaultService) { // Vault API self.vaultService = vaultService + self.isProperlyConfigured = self.vaultService.healthCheck + // Contacts checkContactsAuthorizationStatus() -// self.address = "0x039fd69d03e3735490a86925612072c5612cbf7a0223678619a1b7f30f4bdc8f" + self.address = "0x039fd69d03e3735490a86925612072c5612cbf7a0223678619a1b7f30f4bdc8f" self.getBalance() } @@ -126,17 +117,19 @@ extension Model { // TODO: implement nickname support vaultService.send(GetOTP(phoneNumber: phoneNumber, nickname: "nickname")) { result in - self.isLoading = false + DispatchQueue.main.async { + self.isLoading = false - switch result { - case .success(let response): - onSuccess() + switch result { + case .success: + onSuccess() - case .failure(let error): - // TODO: Handle error - #if DEBUG - print(error) - #endif + case .failure(let error): + // TODO: Handle error +#if DEBUG + print(error) +#endif + } } } } @@ -154,18 +147,20 @@ extension Model { self.isLoading = true vaultService.send(VerifyOTP(phoneNumber: phoneNumber, sentOTP: otp, publicKey: publicKey)) { result in - self.isLoading = false + DispatchQueue.main.async { + self.isLoading = false - switch result { - case .success(let response): - self.address = response.contract_address - onSuccess() + switch result { + case .success(let response): + self.address = response.contract_address + onSuccess() - case .failure(let error): - // TODO: Handle error - #if DEBUG - print(error) - #endif + case .failure(let error): + // TODO: Handle error +#if DEBUG + print(error) +#endif + } } } } catch { @@ -178,13 +173,15 @@ extension Model { func getBalance() { vaultService.send(GetBalance(address: self.address)) { result in - switch result { - case .success(let response): - self.balance = USDCAmount(from: response.balance)! + DispatchQueue.main.async { + switch result { + case .success(let response): + self.balance = USDCAmount(from: response.balance)! - case .failure(let error): - // TODO: Handle error - print(error) + case .failure(let error): + // TODO: Handle error + print(error) + } } } } @@ -236,17 +233,13 @@ extension Model { extension Model { - // invoke - - func executeTransaction(signedTransaction: StarknetInvokeTransactionV1) async throws -> StarknetInvokeTransactionResponse { - return try await self.provider.addInvokeTransaction(signedTransaction) - } - // sign func signOutsideExecution(outsideExecution: OutsideExecution) async throws -> StarknetSignature { - print("MessageHash: \(self.outsideExecution!.getMessageHash(forSigner: self.account.address))") - return try self.signer.sign(transactionHash: self.outsideExecution!.getMessageHash(forSigner: self.account.address)) + let feltAddress = Felt(fromHex: self.address)! + + print("MessageHash: \(self.outsideExecution!.getMessageHash(forSigner: feltAddress))") + return try self.signer.sign(transactionHash: self.outsideExecution!.getMessageHash(forSigner: feltAddress)) } // addr utils diff --git a/app/App/Navigation/ContentView.swift b/app/App/Navigation/ContentView.swift index aa950dab..654aaa40 100644 --- a/app/App/Navigation/ContentView.swift +++ b/app/App/Navigation/ContentView.swift @@ -34,7 +34,9 @@ struct ContentView: View { } var body: some View { - if self.isOnboarded { + if !self.model.isProperlyConfigured { + ErrorView() + } else if self.isOnboarded { ZStack(alignment: .bottom) { TabView(selection: $selectedTab) { NavigationStack { diff --git a/app/App/Navigation/ErrorView.swift b/app/App/Navigation/ErrorView.swift new file mode 100644 index 00000000..27087a37 --- /dev/null +++ b/app/App/Navigation/ErrorView.swift @@ -0,0 +1,23 @@ +// +// ErrorView.swift +// Vault +// +// Created by Charles Lanier on 18/06/2024. +// + +import SwiftUI + +struct ErrorView: View { + var body: some View { + VStack { + Text("An error has occurred").textTheme(.headlineLarge) + Text("Please contact our support.").textTheme(.subtitle) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .defaultBackground() + } +} + +#Preview { + ErrorView() +} diff --git a/app/App/Services/VaultAPI/Models/APIRequest.swift b/app/App/Services/VaultAPI/Models/APIRequest.swift index 31e7169c..4d6028aa 100644 --- a/app/App/Services/VaultAPI/Models/APIRequest.swift +++ b/app/App/Services/VaultAPI/Models/APIRequest.swift @@ -7,6 +7,11 @@ import Foundation +public enum HTTPMethod: String { + case GET + case POST +} + /// All requests must conform to this protocol /// - Discussion: You must conform to Encodable too, so that all stored public parameters /// of types conforming this protocol will be encoded as parameters. @@ -16,4 +21,15 @@ public protocol APIRequest: Encodable { /// Endpoint for this request (the last part of the URL) var resourceName: String { get } + + var httpMethod: HTTPMethod { get } + + var headers: [String: String] { get } +} + +public extension APIRequest { + + var headers: [String: String] { + return [:] + } } diff --git a/app/App/Services/VaultAPI/Models/DataContainer.swift b/app/App/Services/VaultAPI/Models/DataContainer.swift deleted file mode 100644 index 84130510..00000000 --- a/app/App/Services/VaultAPI/Models/DataContainer.swift +++ /dev/null @@ -1,14 +0,0 @@ -// -// DataContainer.swift -// Vault -// -// Created by Charles Lanier on 14/06/2024. -// - -import Foundation - -/// All successful responses return this, and contains all -/// the metainformation about the returned chunk. -public struct DataContainer: Decodable { - public let results: Results -} diff --git a/app/App/Services/VaultAPI/Models/Deployment.swift b/app/App/Services/VaultAPI/Models/Deployment.swift new file mode 100644 index 00000000..cbea60dd --- /dev/null +++ b/app/App/Services/VaultAPI/Models/Deployment.swift @@ -0,0 +1,13 @@ +// +// Deployment.swift +// Vault +// +// Created by Charles Lanier on 17/06/2024. +// + +import Foundation + +public struct Deployment: Decodable { + public let contract_address: String +} + diff --git a/app/App/Services/VaultAPI/Models/Empty.swift b/app/App/Services/VaultAPI/Models/Empty.swift new file mode 100644 index 00000000..6c315111 --- /dev/null +++ b/app/App/Services/VaultAPI/Models/Empty.swift @@ -0,0 +1,10 @@ +// +// Empty.swift +// Vault +// +// Created by Charles Lanier on 17/06/2024. +// + +import Foundation + +public struct Empty: Decodable {} diff --git a/app/App/Services/VaultAPI/Models/Error.swift b/app/App/Services/VaultAPI/Models/Error.swift new file mode 100644 index 00000000..537f4517 --- /dev/null +++ b/app/App/Services/VaultAPI/Models/Error.swift @@ -0,0 +1,13 @@ +// +// Error.swift +// Vault +// +// Created by Charles Lanier on 14/06/2024. +// + +import Foundation + +public struct ErrorResponse: Decodable { + /// Message that usually gives more information about some error + public let message: String? +} diff --git a/app/App/Services/VaultAPI/Models/Execution.swift b/app/App/Services/VaultAPI/Models/Execution.swift new file mode 100644 index 00000000..e4f0a01d --- /dev/null +++ b/app/App/Services/VaultAPI/Models/Execution.swift @@ -0,0 +1,12 @@ +// +// Execution.swift +// Vault +// +// Created by Charles Lanier on 16/06/2024. +// + +import Foundation + +public struct Execution: Decodable { + public let transaction_hash: String +} diff --git a/app/App/Services/VaultAPI/Models/VaultError.swift b/app/App/Services/VaultAPI/Models/VaultError.swift index cf82bf90..050ef3a1 100644 --- a/app/App/Services/VaultAPI/Models/VaultError.swift +++ b/app/App/Services/VaultAPI/Models/VaultError.swift @@ -10,5 +10,6 @@ import Foundation public enum VaultError: Error { case encoding case decoding + case unknown case server(message: String) } diff --git a/app/App/Services/VaultAPI/Models/VaultResponse.swift b/app/App/Services/VaultAPI/Models/VaultResponse.swift deleted file mode 100644 index d11674b0..00000000 --- a/app/App/Services/VaultAPI/Models/VaultResponse.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// VaultResponse.swift -// Vault -// -// Created by Charles Lanier on 14/06/2024. -// - -import Foundation - -/// Top level response for every request to the Vault API -/// Everything in the API seems to be optional, so we cannot rely on having values here -public struct VaultResponse: Decodable { - /// Whether it was ok or not - public let status: String? - /// Message that usually gives more information about some error - public let message: String? - /// Requested data - public let data: DataContainer? -} diff --git a/app/App/Services/VaultAPI/Requests/ExecuteFromOutside.swift b/app/App/Services/VaultAPI/Requests/ExecuteFromOutside.swift new file mode 100644 index 00000000..964521b9 --- /dev/null +++ b/app/App/Services/VaultAPI/Requests/ExecuteFromOutside.swift @@ -0,0 +1,38 @@ +// +// ExecuteFromOutside.swift +// Vault +// +// Created by Charles Lanier on 15/06/2024. +// + +import Foundation +import Starknet + +public struct ExecuteFromOutside: APIRequest { + public typealias Response = Execution + + // Notice how we create a composed resourceName + public var resourceName: String { + return "execute_from_outside" + } + + public var httpMethod: HTTPMethod { + return .POST + } + + public var headers: [String : String] { + return ["Content-Type": "application/json"] + } + + // Parameters + public let address: String + public let calldata: [String] + + public init(address: String, outsideExecution: OutsideExecution, signature: StarknetSignature) { + let rawOutsideExecution = outsideExecution.calldata.map { String($0.value, radix: 10) } + let rawSignautre = signature.map { String($0.value, radix: 10) } + + self.address = address + self.calldata = rawOutsideExecution + [String(rawSignautre.count, radix: 10)] + rawSignautre + } +} diff --git a/app/App/Services/VaultAPI/Requests/GetBalance.swift b/app/App/Services/VaultAPI/Requests/GetBalance.swift index 60fb733d..d35add46 100644 --- a/app/App/Services/VaultAPI/Requests/GetBalance.swift +++ b/app/App/Services/VaultAPI/Requests/GetBalance.swift @@ -8,6 +8,7 @@ import Foundation public struct GetBalance: APIRequest { + public typealias Response = Balance // Notice how we create a composed resourceName @@ -15,6 +16,10 @@ public struct GetBalance: APIRequest { return "get_balance" } + public var httpMethod: HTTPMethod { + return .GET + } + // Parameters public let address: String diff --git a/app/App/Services/VaultAPI/Requests/GetOTP.swift b/app/App/Services/VaultAPI/Requests/GetOTP.swift new file mode 100644 index 00000000..45d30417 --- /dev/null +++ b/app/App/Services/VaultAPI/Requests/GetOTP.swift @@ -0,0 +1,35 @@ +// +// GetOTP.swift +// Vault +// +// Created by Charles Lanier on 17/06/2024. +// + +import Foundation +import PhoneNumberKit + +public struct GetOTP: APIRequest { + public typealias Response = Empty + + // Notice how we create a composed resourceName + public var resourceName: String { + return "get_otp" + } + + public var httpMethod: HTTPMethod { + return .POST + } + + public var headers: [String : String] { + return ["Content-Type": "application/json"] + } + + // Parameters + public let phone_number: String + public let nickname: String + + public init(phoneNumber: PhoneNumber, nickname: String) { + self.phone_number = phoneNumber.rawString() + self.nickname = nickname + } +} diff --git a/app/App/Services/VaultAPI/Requests/VerifyOTP.swift b/app/App/Services/VaultAPI/Requests/VerifyOTP.swift new file mode 100644 index 00000000..9331bf4a --- /dev/null +++ b/app/App/Services/VaultAPI/Requests/VerifyOTP.swift @@ -0,0 +1,42 @@ +// +// VerifyOTP.swift +// Vault +// +// Created by Charles Lanier on 17/06/2024. +// + +import Foundation +import PhoneNumberKit + +public struct VerifyOTP: APIRequest { + public typealias Response = Deployment + + // Notice how we create a composed resourceName + public var resourceName: String { + return "verify_otp" + } + + public var httpMethod: HTTPMethod { + return .POST + } + + public var headers: [String : String] { + return ["Content-Type": "application/json"] + } + + // Parameters + public let phone_number: String + public let sent_otp: String + public let public_key_x: String + public let public_key_y: String + + public init(phoneNumber: PhoneNumber, sentOTP: String, publicKey: P256PublicKey) { + self.phone_number = phoneNumber.rawString() + self.sent_otp = sentOTP + self.public_key_x = publicKey.x.toHex() + self.public_key_y = publicKey.y.toHex() + } +} + + + diff --git a/app/App/Services/VaultAPI/Utils/BodyParamsEncoder.swift b/app/App/Services/VaultAPI/Utils/BodyParamsEncoder.swift new file mode 100644 index 00000000..200450b1 --- /dev/null +++ b/app/App/Services/VaultAPI/Utils/BodyParamsEncoder.swift @@ -0,0 +1,21 @@ +// +// BodyParamsEncoder.swift +// Vault +// +// Created by Charles Lanier on 16/06/2024. +// + +import Foundation + +enum BodyParamsEncoder { + static func encode(_ encodable: T) throws -> Data { + let parametersData = try JSONEncoder().encode(encodable) +// let parameters = try JSONDecoder().decode([String: HTTPParameter].self, from: parametersData) +// let body = parameters.reduce(into: [:] as [String: Any]) { acc, param in +// acc[param.key] = param.value.description +// } +// // Convert the dictionary into JSON data +// return try! JSONSerialization.data(withJSONObject: body, options: []) + return parametersData + } +} diff --git a/app/App/Services/VaultAPI/Utils/HTTPParameter.swift b/app/App/Services/VaultAPI/Utils/HTTPParameter.swift index 018ff18e..3cc7165c 100644 --- a/app/App/Services/VaultAPI/Utils/HTTPParameter.swift +++ b/app/App/Services/VaultAPI/Utils/HTTPParameter.swift @@ -14,6 +14,7 @@ enum HTTPParameter: CustomStringConvertible, Decodable { case bool(Bool) case int(Int) case double(Double) + case stringArray([String]) init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() @@ -26,6 +27,8 @@ enum HTTPParameter: CustomStringConvertible, Decodable { self = .int(int) } else if let double = try? container.decode(Double.self) { self = .double(double) + } else if let stringArray = try? container.decode([String].self) { + self = .stringArray(stringArray) } else { throw VaultError.decoding } @@ -41,6 +44,8 @@ enum HTTPParameter: CustomStringConvertible, Decodable { return String(describing: int) case .double(let double): return String(describing: double) + case .stringArray(let stringArray): + return stringArray.description } } } diff --git a/app/App/Services/VaultAPI/VaultAPIClient.swift b/app/App/Services/VaultAPI/VaultAPIClient.swift index b8ef26cc..21870140 100644 --- a/app/App/Services/VaultAPI/VaultAPIClient.swift +++ b/app/App/Services/VaultAPI/VaultAPIClient.swift @@ -10,8 +10,6 @@ import Foundation enum Endpoint { case getOTP(String, String) case verifyOTP(String, String, String, String) - case executeFromOutside(String, [String], [String]) - case getBalance(String) } enum Method { @@ -22,135 +20,54 @@ enum Method { public typealias ResultCallback = (Result) -> Void class VaultService { - private let baseEndpointUrl = Constants.vaultBaseURL - private let session = URLSession(configuration: .default) - - private func query(endpoint: Endpoint, completion: @escaping @Sendable (Result<[String: Any], Error>) -> Void) { - var url = Constants.vaultBaseURL - var body: [String: Any] = [:] - var method: Method? - - switch endpoint { - case let .getOTP(phoneNumber, nickname): - url.append(path: "/get_otp") - - body["phone_number"] = phoneNumber - body["nickname"] = nickname - - method = .post - - case let .verifyOTP(phoneNumber, otp, publicKeyX, publicKeyY): - url.append(path: "/verify_otp") - - body["phone_number"] = phoneNumber - body["sent_otp"] = otp - body["public_key_x"] = publicKeyX - body["public_key_y"] = publicKeyY - - method = .post - - case let .executeFromOutside(address, calldata, signature): - url.append(path: "/execute_from_outside") - body["address"] = address - body["calldata"] = calldata + [signature.count] + signature - - method = .post - - case let .getBalance(address): - url.append(path: "/get_balance") - url.append(queryItems: [URLQueryItem(name: "address", value: address)]) + var healthCheck: Bool { + return baseEndpointUrl != nil + } - method = .get - } + private let baseEndpointUrl = AppConfiguration.API.baseURL + private let session = URLSession(configuration: .default) - // Convert the dictionary into JSON data - guard let jsonData = try? JSONSerialization.data(withJSONObject: body, options: []) else { - print("Error: Unable to encode JSON") - return - } + /// Sends a request to Vault servers, calling the completion method when finished + public func send(_ request: T, completion: @escaping ResultCallback) { + let urlRequest = self.endpoint(for: request) - // Create a URLRequest object and configure it for a POST method - var request = URLRequest(url: url) + let task = session.dataTask(with: urlRequest) { data, response, error in + if + let data = data, + let httpResponse = response as? HTTPURLResponse + { - switch method { - case .get: - request.httpMethod = "GET" +#if DEBUG + print(data.base64EncodedString()) +#endif - case .post: - request.httpMethod = "POST" - request.httpBody = jsonData - request.addValue("application/json", forHTTPHeaderField: "Content-Type") + if httpResponse.isSuccessful { + // request is successful - case nil: - fatalError("Unknown error.") - } + do { + // Decode the top level response as data + let vaultResponse = try JSONDecoder().decode(T.Response.self, from: data) - // fetch request - URLSession.shared.dataTask(with: request) { data, response, error in - guard - let data = data, - let httpResponse = response as? HTTPURLResponse, - error == nil - else { - DispatchQueue.main.async { - completion(.failure(error ?? "Unknown error")) - } - return - } + completion(.success(vaultResponse)) + } catch { + completion(.failure(VaultError.decoding)) + } + } else { + // request failed - #if DEBUG - print(data.base64EncodedString()) - #endif + do { + // Decode the top level response as error + let vaultResponse = try JSONDecoder().decode(ErrorResponse.self, from: data) - do { - // make sure this JSON is in the format we expect - if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { - DispatchQueue.main.async { - if httpResponse.isSuccessful { - completion(.success(json)) + if let message = vaultResponse.message { + completion(.failure(VaultError.server(message: message))) } else { - completion(.failure(json["message"] as? String ?? "Unkown error")) + completion(.failure(VaultError.unknown)) } - } - } - } catch let error as NSError { - DispatchQueue.main.async { - completion(.failure(error)) - } - } - }.resume() - } - - - - - - - - - - - /// Sends a request to Vault servers, calling the completion method when finished - public func send(_ request: T, completion: @escaping ResultCallback>) { - let endpoint = self.endpoint(for: request) - - let task = session.dataTask(with: URLRequest(url: endpoint)) { data, response, error in - if let data = data { - do { - // Decode the top level response, and look up the decoded response to see - // if it's a success or a failure - let vaultResponse = try JSONDecoder().decode(VaultResponse.self, from: data) - - if let dataContainer = vaultResponse.data { - completion(.success(dataContainer)) - } else if let message = vaultResponse.message { - completion(.failure(VaultError.server(message: message))) - } else { + } catch { completion(.failure(VaultError.decoding)) } - } catch { - completion(.failure(error)) } } else if let error = error { completion(.failure(error)) @@ -161,105 +78,50 @@ class VaultService { /// Encodes a URL based on the given request /// Everything needed for a public request to Vault servers is encoded directly in this URL - private func endpoint(for request: T) -> URL { + private func endpoint(for request: T) -> URLRequest { guard let baseUrl = URL(string: request.resourceName, relativeTo: baseEndpointUrl) else { fatalError("Bad resourceName: \(request.resourceName)") } var components = URLComponents(url: baseUrl, resolvingAgainstBaseURL: true)! - // Custom query items needed for this specific request - let customQueryItems: [URLQueryItem] + // Add query parameters + if (request.httpMethod == .GET) { + // Custom query items needed for this specific request + let customQueryItems: [URLQueryItem] - do { - customQueryItems = try URLQueryItemEncoder.encode(request) - } catch { - fatalError("Wrong parameters: \(error)") - } + do { + customQueryItems = try URLQueryItemEncoder.encode(request) + } catch { + fatalError("Wrong parameters: \(error)") + } - components.queryItems = customQueryItems + components.queryItems = customQueryItems + } // Construct the final URL with all the previous data - return components.url! - } - - func getOTP(phoneNumber: String, completion: @escaping (Result) -> Void) { - self.query(endpoint: .getOTP(phoneNumber, "chqrles")) { result in - switch result { - case .success(let json): - guard let _ = json["ok"] as? Bool else { - completion(.failure("Unkown Error")) - return - } - - completion(.success(Void())) + var urlRequest = URLRequest(url: components.url!) - case .failure(let error): - completion(.failure(error)) + // add Headers and body params + if (request.httpMethod == .POST) { + for (headerField, value) in request.headers { + urlRequest.addValue(value, forHTTPHeaderField: headerField) } - } - } - func verifyOTP( - phoneNumber: String, - otp: String, - publicKeyX: String, - publicKeyY: String, - completion: @escaping (Result) -> Void - ) { - self.query(endpoint: .verifyOTP(phoneNumber, otp, publicKeyX, publicKeyY)) { result in - switch result { - case .success(let json): - guard let address = json["contract_address"] as? String else { - completion(.failure("Unkown Error")) - return - } + // Custom body params needed for this specific request + let customBodyParams: Data - completion(.success(address)) - - case .failure(let error): - completion(.failure(error)) + do { + customBodyParams = try BodyParamsEncoder.encode(request) + } catch { + fatalError("Wrong parameters: \(error)") } - } - } - func executeFromOutside( - address: String, - calldata: [String], - signature: [String], - completion: @escaping (Result) -> Void - ) { - self.query(endpoint: .executeFromOutside(address, calldata, signature)) { result in - switch result { - case .success(let json): - guard let txHash = json["transaction_hash"] as? String else { - completion(.failure("Unkown Error")) - return - } - - completion(.success(txHash)) - - case .failure(let error): - completion(.failure(error)) - } + urlRequest.httpBody = customBodyParams } - } - - func getBalance(of address: String, completion: @escaping (Result) -> Void) { - self.query(endpoint: .getBalance(address)) { result in - switch result { - case .success(let json): - guard let balance = json["balance"] as? String else { - completion(.failure("Unkown Error")) - return - } - completion(.success(balance)) + urlRequest.httpMethod = request.httpMethod.rawValue - case .failure(let error): - completion(.failure(error)) - } - } + return urlRequest } } - diff --git a/app/Dev.xcconfig b/app/Dev.xcconfig new file mode 100644 index 00000000..99ba85f2 --- /dev/null +++ b/app/Dev.xcconfig @@ -0,0 +1,11 @@ +// +// Development.xcconfig +// Vault +// +// Created by Charles Lanier on 18/06/2024. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +API_BASE_URL = api-production-e1fe.up.railway.app diff --git a/app/Prod.xcconfig b/app/Prod.xcconfig new file mode 100644 index 00000000..bade6052 --- /dev/null +++ b/app/Prod.xcconfig @@ -0,0 +1,11 @@ +// +// Prod.xcconfig +// Vault +// +// Created by Charles Lanier on 18/06/2024. +// + +// Configuration settings file format documentation can be found at: +// https://help.apple.com/xcode/#/dev745c5c974 + +API_BASE_URL = api-production-e1fe.up.railway.app diff --git a/app/Vault-Info.plist b/app/Vault-Info.plist index e3be6935..21a71ee8 100644 --- a/app/Vault-Info.plist +++ b/app/Vault-Info.plist @@ -2,12 +2,11 @@ + API_BASE_URL + $(API_BASE_URL) UIAppFonts Sofia Pro Medium.otf - - NSContactsUsageDescription - We need access to your contacts to show them in the app. diff --git a/app/Vault.xcodeproj/project.pbxproj b/app/Vault.xcodeproj/project.pbxproj index 88a82c48..e0b94bf5 100644 --- a/app/Vault.xcodeproj/project.pbxproj +++ b/app/Vault.xcodeproj/project.pbxproj @@ -42,21 +42,23 @@ 9C637CDB2BB09C4D005816B4 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C637CDA2BB09C4D005816B4 /* Notification.swift */; }; 9C637CDE2BB0A564005816B4 /* AppIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C637CDD2BB0A564005816B4 /* AppIcon.swift */; }; 9C637CE02BB0C0E5005816B4 /* Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C637CDF2BB0C0E5005816B4 /* Input.swift */; }; - 9C83D05B2C1DC46A006F8716 /* APIRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D04C2C1DC46A006F8716 /* APIRequest.swift */; }; - 9C83D05C2C1DC46A006F8716 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D04D2C1DC46A006F8716 /* Balance.swift */; }; - 9C83D05F2C1DC46A006F8716 /* VaultError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0502C1DC46A006F8716 /* VaultError.swift */; }; - 9C83D0602C1DC46A006F8716 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0512C1DC46A006F8716 /* Error.swift */; }; - 9C83D0612C1DC46A006F8716 /* GetBalance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0532C1DC46A006F8716 /* GetBalance.swift */; }; - 9C83D0622C1DC46A006F8716 /* HTTPParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0552C1DC46A006F8716 /* HTTPParameter.swift */; }; - 9C83D0632C1DC46A006F8716 /* URLQueryItemEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0562C1DC46A006F8716 /* URLQueryItemEncoder.swift */; }; - 9C83D0642C1DC46A006F8716 /* VaultAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0582C1DC46A006F8716 /* VaultAPIClient.swift */; }; - 9C83D0662C1DCD7E006F8716 /* ExecuteFromOutside.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0652C1DCD7E006F8716 /* ExecuteFromOutside.swift */; }; - 9C83D0682C1ED28C006F8716 /* BodyParamsEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0672C1ED28C006F8716 /* BodyParamsEncoder.swift */; }; - 9C83D06A2C1EF0F0006F8716 /* Execution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0692C1EF0F0006F8716 /* Execution.swift */; }; - 9C83D06C2C204373006F8716 /* GetOTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D06B2C204373006F8716 /* GetOTP.swift */; }; - 9C83D0702C2046A6006F8716 /* VerifyOTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D06F2C2046A6006F8716 /* VerifyOTP.swift */; }; - 9C83D0722C20495B006F8716 /* Deployment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0712C20495B006F8716 /* Deployment.swift */; }; - 9C83D0742C2061A2006F8716 /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C83D0732C2061A2006F8716 /* Empty.swift */; }; + 9C6ABFCC2C21C9C9000227D2 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6ABFCB2C21C9C9000227D2 /* ErrorView.swift */; }; + 9C6ABFD02C21D21A000227D2 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C6ABFCF2C21D21A000227D2 /* Configuration.swift */; }; + 9C9F9EEF2C22368200620AC6 /* APIRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EDC2C22368200620AC6 /* APIRequest.swift */; }; + 9C9F9EF02C22368200620AC6 /* Balance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EDD2C22368200620AC6 /* Balance.swift */; }; + 9C9F9EF12C22368200620AC6 /* Deployment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EDE2C22368200620AC6 /* Deployment.swift */; }; + 9C9F9EF22C22368200620AC6 /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EDF2C22368200620AC6 /* Empty.swift */; }; + 9C9F9EF32C22368200620AC6 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE02C22368200620AC6 /* Error.swift */; }; + 9C9F9EF42C22368200620AC6 /* Execution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE12C22368200620AC6 /* Execution.swift */; }; + 9C9F9EF52C22368200620AC6 /* VaultError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE22C22368200620AC6 /* VaultError.swift */; }; + 9C9F9EF62C22368200620AC6 /* ExecuteFromOutside.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE42C22368200620AC6 /* ExecuteFromOutside.swift */; }; + 9C9F9EF72C22368200620AC6 /* GetBalance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE52C22368200620AC6 /* GetBalance.swift */; }; + 9C9F9EF82C22368200620AC6 /* GetOTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE62C22368200620AC6 /* GetOTP.swift */; }; + 9C9F9EF92C22368200620AC6 /* VerifyOTP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE72C22368200620AC6 /* VerifyOTP.swift */; }; + 9C9F9EFA2C22368200620AC6 /* BodyParamsEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EE92C22368200620AC6 /* BodyParamsEncoder.swift */; }; + 9C9F9EFB2C22368200620AC6 /* HTTPParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EEA2C22368200620AC6 /* HTTPParameter.swift */; }; + 9C9F9EFC2C22368200620AC6 /* URLQueryItemEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EEB2C22368200620AC6 /* URLQueryItemEncoder.swift */; }; + 9C9F9EFD2C22368200620AC6 /* VaultAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C9F9EED2C22368200620AC6 /* VaultAPIClient.swift */; }; 9CC82FFA2C1BB9A30089042C /* OutsideExecution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CC82FF92C1BB9A30089042C /* OutsideExecution.swift */; }; 9CD1BE8A2BCD4F5B0077A60B /* OTPInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD1BE892BCD4F5B0077A60B /* OTPInput.swift */; }; 9CD1BE8C2BCD5D790077A60B /* String+character.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CD1BE8B2BCD5D790077A60B /* String+character.swift */; }; @@ -156,21 +158,25 @@ 9C637CDA2BB09C4D005816B4 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 9C637CDD2BB0A564005816B4 /* AppIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIcon.swift; sourceTree = ""; }; 9C637CDF2BB0C0E5005816B4 /* Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Input.swift; sourceTree = ""; }; - 9C83D04C2C1DC46A006F8716 /* APIRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIRequest.swift; sourceTree = ""; }; - 9C83D04D2C1DC46A006F8716 /* Balance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Balance.swift; sourceTree = ""; }; - 9C83D0502C1DC46A006F8716 /* VaultError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VaultError.swift; sourceTree = ""; }; - 9C83D0512C1DC46A006F8716 /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; - 9C83D0532C1DC46A006F8716 /* GetBalance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBalance.swift; sourceTree = ""; }; - 9C83D0552C1DC46A006F8716 /* HTTPParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPParameter.swift; sourceTree = ""; }; - 9C83D0562C1DC46A006F8716 /* URLQueryItemEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLQueryItemEncoder.swift; sourceTree = ""; }; - 9C83D0582C1DC46A006F8716 /* VaultAPIClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VaultAPIClient.swift; sourceTree = ""; }; - 9C83D0652C1DCD7E006F8716 /* ExecuteFromOutside.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExecuteFromOutside.swift; sourceTree = ""; }; - 9C83D0672C1ED28C006F8716 /* BodyParamsEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BodyParamsEncoder.swift; sourceTree = ""; }; - 9C83D0692C1EF0F0006F8716 /* Execution.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Execution.swift; sourceTree = ""; }; - 9C83D06B2C204373006F8716 /* GetOTP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetOTP.swift; sourceTree = ""; }; - 9C83D06F2C2046A6006F8716 /* VerifyOTP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerifyOTP.swift; sourceTree = ""; }; - 9C83D0712C20495B006F8716 /* Deployment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deployment.swift; sourceTree = ""; }; - 9C83D0732C2061A2006F8716 /* Empty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Empty.swift; sourceTree = ""; }; + 9C6ABFCB2C21C9C9000227D2 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; + 9C6ABFCD2C21CF94000227D2 /* Dev.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Dev.xcconfig; sourceTree = ""; }; + 9C6ABFCE2C21D0CC000227D2 /* Prod.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Prod.xcconfig; sourceTree = ""; }; + 9C6ABFCF2C21D21A000227D2 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; + 9C9F9EDC2C22368200620AC6 /* APIRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIRequest.swift; sourceTree = ""; }; + 9C9F9EDD2C22368200620AC6 /* Balance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Balance.swift; sourceTree = ""; }; + 9C9F9EDE2C22368200620AC6 /* Deployment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Deployment.swift; sourceTree = ""; }; + 9C9F9EDF2C22368200620AC6 /* Empty.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Empty.swift; sourceTree = ""; }; + 9C9F9EE02C22368200620AC6 /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; + 9C9F9EE12C22368200620AC6 /* Execution.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Execution.swift; sourceTree = ""; }; + 9C9F9EE22C22368200620AC6 /* VaultError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VaultError.swift; sourceTree = ""; }; + 9C9F9EE42C22368200620AC6 /* ExecuteFromOutside.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExecuteFromOutside.swift; sourceTree = ""; }; + 9C9F9EE52C22368200620AC6 /* GetBalance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetBalance.swift; sourceTree = ""; }; + 9C9F9EE62C22368200620AC6 /* GetOTP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GetOTP.swift; sourceTree = ""; }; + 9C9F9EE72C22368200620AC6 /* VerifyOTP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerifyOTP.swift; sourceTree = ""; }; + 9C9F9EE92C22368200620AC6 /* BodyParamsEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BodyParamsEncoder.swift; sourceTree = ""; }; + 9C9F9EEA2C22368200620AC6 /* HTTPParameter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPParameter.swift; sourceTree = ""; }; + 9C9F9EEB2C22368200620AC6 /* URLQueryItemEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLQueryItemEncoder.swift; sourceTree = ""; }; + 9C9F9EED2C22368200620AC6 /* VaultAPIClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VaultAPIClient.swift; sourceTree = ""; }; 9CC82FF92C1BB9A30089042C /* OutsideExecution.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutsideExecution.swift; sourceTree = ""; }; 9CD1BE892BCD4F5B0077A60B /* OTPInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OTPInput.swift; sourceTree = ""; }; 9CD1BE8B2BCD5D790077A60B /* String+character.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+character.swift"; sourceTree = ""; }; @@ -307,57 +313,56 @@ path = Utils; sourceTree = ""; }; - 9C83D0522C1DC46A006F8716 /* Models */ = { + 9C9F9EE32C22368200620AC6 /* Models */ = { isa = PBXGroup; children = ( - 9C83D04C2C1DC46A006F8716 /* APIRequest.swift */, - 9C83D04D2C1DC46A006F8716 /* Balance.swift */, - 9C83D0502C1DC46A006F8716 /* VaultError.swift */, - 9C83D0512C1DC46A006F8716 /* Error.swift */, - 9C83D0692C1EF0F0006F8716 /* Execution.swift */, - 9C83D0712C20495B006F8716 /* Deployment.swift */, - 9C83D0732C2061A2006F8716 /* Empty.swift */, + 9C9F9EDC2C22368200620AC6 /* APIRequest.swift */, + 9C9F9EDD2C22368200620AC6 /* Balance.swift */, + 9C9F9EDE2C22368200620AC6 /* Deployment.swift */, + 9C9F9EDF2C22368200620AC6 /* Empty.swift */, + 9C9F9EE02C22368200620AC6 /* Error.swift */, + 9C9F9EE12C22368200620AC6 /* Execution.swift */, + 9C9F9EE22C22368200620AC6 /* VaultError.swift */, ); path = Models; sourceTree = ""; }; - 9C83D0542C1DC46A006F8716 /* Requests */ = { + 9C9F9EE82C22368200620AC6 /* Requests */ = { isa = PBXGroup; children = ( - 9C83D0532C1DC46A006F8716 /* GetBalance.swift */, - 9C83D0652C1DCD7E006F8716 /* ExecuteFromOutside.swift */, - 9C83D06B2C204373006F8716 /* GetOTP.swift */, - 9C83D06F2C2046A6006F8716 /* VerifyOTP.swift */, + 9C9F9EE42C22368200620AC6 /* ExecuteFromOutside.swift */, + 9C9F9EE52C22368200620AC6 /* GetBalance.swift */, + 9C9F9EE62C22368200620AC6 /* GetOTP.swift */, + 9C9F9EE72C22368200620AC6 /* VerifyOTP.swift */, ); path = Requests; sourceTree = ""; }; - 9C83D0572C1DC46A006F8716 /* Utils */ = { + 9C9F9EEC2C22368200620AC6 /* Utils */ = { isa = PBXGroup; children = ( - 9C83D0552C1DC46A006F8716 /* HTTPParameter.swift */, - 9C83D0562C1DC46A006F8716 /* URLQueryItemEncoder.swift */, - 9C83D0672C1ED28C006F8716 /* BodyParamsEncoder.swift */, + 9C9F9EE92C22368200620AC6 /* BodyParamsEncoder.swift */, + 9C9F9EEA2C22368200620AC6 /* HTTPParameter.swift */, + 9C9F9EEB2C22368200620AC6 /* URLQueryItemEncoder.swift */, ); path = Utils; sourceTree = ""; }; - 9C83D0592C1DC46A006F8716 /* VaultAPI */ = { + 9C9F9EEE2C22368200620AC6 /* VaultAPI */ = { isa = PBXGroup; children = ( - 9C83D0522C1DC46A006F8716 /* Models */, - 9C83D0542C1DC46A006F8716 /* Requests */, - 9C83D0572C1DC46A006F8716 /* Utils */, - 9C83D0582C1DC46A006F8716 /* VaultAPIClient.swift */, + 9C9F9EE32C22368200620AC6 /* Models */, + 9C9F9EE82C22368200620AC6 /* Requests */, + 9C9F9EEC2C22368200620AC6 /* Utils */, + 9C9F9EED2C22368200620AC6 /* VaultAPIClient.swift */, ); - name = VaultAPI; - path = ../../../../../Desktop/VaultAPI; + path = VaultAPI; sourceTree = ""; }; 9CD1BE8E2BD510420077A60B /* Services */ = { isa = PBXGroup; children = ( - 9C83D0592C1DC46A006F8716 /* VaultAPI */, + 9C9F9EEE2C22368200620AC6 /* VaultAPI */, ); path = Services; sourceTree = ""; @@ -393,6 +398,7 @@ isa = PBXGroup; children = ( 9CD778B52BBCB0DE00BA4677 /* Constants.swift */, + 9C6ABFCF2C21D21A000227D2 /* Configuration.swift */, ); path = Constants; sourceTree = ""; @@ -400,6 +406,8 @@ 9CDFD3F22BAB3428000466B9 = { isa = PBXGroup; children = ( + 9C6ABFCE2C21D0CC000227D2 /* Prod.xcconfig */, + 9C6ABFCD2C21CF94000227D2 /* Dev.xcconfig */, 9CDFD4352BAB80D5000466B9 /* Vault-Info.plist */, 9CDFD3FD2BAB3428000466B9 /* App */, 9CDFD40E2BAB3429000466B9 /* VaultTests */, @@ -460,6 +468,7 @@ 9CDFD42B2BAB4CF8000466B9 /* Onboarding */, 9CDFD4002BAB3428000466B9 /* ContentView.swift */, 9CD778BB2BBED06700BA4677 /* CustomTabBar.swift */, + 9C6ABFCB2C21C9C9000227D2 /* ErrorView.swift */, ); path = Navigation; sourceTree = ""; @@ -665,7 +674,11 @@ buildActionMask = 2147483647; files = ( 9CD390EB2BE1977E00238FE9 /* HTTPURLReponse.swift in Sources */, + 9C9F9EFA2C22368200620AC6 /* BodyParamsEncoder.swift in Sources */, + 9C9F9EFC2C22368200620AC6 /* URLQueryItemEncoder.swift in Sources */, + 9C9F9EF42C22368200620AC6 /* Execution.swift in Sources */, 9C5CFDA62BC69446001776E1 /* CountryPickerView.swift in Sources */, + 9C9F9EEF2C22368200620AC6 /* APIRequest.swift in Sources */, 9C62590A2BF79F8C0039DE9C /* NumPad.swift in Sources */, 9CE7A75B2BE12CBC008509FE /* Data+Hex.swift in Sources */, 9CD778BC2BBED06700BA4677 /* CustomTabBar.swift in Sources */, @@ -677,9 +690,13 @@ 9CD390FB2BEAB6C600238FE9 /* WebView.swift in Sources */, 9C1C9D962C105E3D0028C8FD /* Amount.swift in Sources */, 9CD778C22BBF1E9200BA4677 /* View+border.swift in Sources */, - 9C83D0742C2061A2006F8716 /* Empty.swift in Sources */, 9C6259172BFB6A910039DE9C /* UIImage.swift in Sources */, 9C1C9D842C0D093F0028C8FD /* P256Signer.swift in Sources */, + 9C9F9EF52C22368200620AC6 /* VaultError.swift in Sources */, + 9C9F9EFB2C22368200620AC6 /* HTTPParameter.swift in Sources */, + 9C9F9EF32C22368200620AC6 /* Error.swift in Sources */, + 9C9F9EF12C22368200620AC6 /* Deployment.swift in Sources */, + 9C9F9EF02C22368200620AC6 /* Balance.swift in Sources */, 9C1C9D8C2C0DEBAE0028C8FD /* CountryData.swift in Sources */, 9CDFD4382BAB8934000466B9 /* Buttons.swift in Sources */, 9C1C9D902C0F5DE40028C8FD /* Popover.swift in Sources */, @@ -689,37 +706,34 @@ 9CD778B62BBCB0DE00BA4677 /* Constants.swift in Sources */, 9CE7A75D2BE15C21008509FE /* SpinnerView.swift in Sources */, 9C637CD92BB09710005816B4 /* NotificationsManager.swift in Sources */, + 9C9F9EF92C22368200620AC6 /* VerifyOTP.swift in Sources */, 9C6259132BFB5A990039DE9C /* SendingAmountView.swift in Sources */, 9C6259192BFCDCEC0039DE9C /* NewRecipientView.swift in Sources */, 9C4F451D2BDEEF0E00D44CBE /* Data+from.swift in Sources */, 9CD778D22BC4423C00BA4677 /* PhoneInput.swift in Sources */, 9CDFD4012BAB3428000466B9 /* ContentView.swift in Sources */, 9CD778B32BBC38F400BA4677 /* HistoricalGraph.swift in Sources */, + 9C9F9EF82C22368200620AC6 /* GetOTP.swift in Sources */, 9C637CDE2BB0A564005816B4 /* AppIcon.swift in Sources */, - 9C83D06A2C1EF0F0006F8716 /* Execution.swift in Sources */, - 9C83D0622C1DC46A006F8716 /* HTTPParameter.swift in Sources */, - 9C83D0642C1DC46A006F8716 /* VaultAPIClient.swift in Sources */, + 9C6ABFCC2C21C9C9000227D2 /* ErrorView.swift in Sources */, 9CD1BE8C2BCD5D790077A60B /* String+character.swift in Sources */, 9C637CD62BB09334005816B4 /* NotificationsView.swift in Sources */, - 9C83D0602C1DC46A006F8716 /* Error.swift in Sources */, 9CD778AB2BBAF8BE00BA4677 /* HomeView.swift in Sources */, + 9C9F9EF72C22368200620AC6 /* GetBalance.swift in Sources */, 9CC82FFA2C1BB9A30089042C /* OutsideExecution.swift in Sources */, 9C6259102BFAADB90039DE9C /* NavigationBar.swift in Sources */, + 9C9F9EF22C22368200620AC6 /* Empty.swift in Sources */, 9CD778C42BC1B63800BA4677 /* BudgetView.swift in Sources */, 9C5CFDB02BC828DE001776E1 /* Locale.swift in Sources */, + 9C9F9EF62C22368200620AC6 /* ExecuteFromOutside.swift in Sources */, 9CD7789D2BB1846600BA4677 /* AccessCodeView.swift in Sources */, 9CD778CB2BC3113A00BA4677 /* PhoneRequestView.swift in Sources */, - 9C83D05B2C1DC46A006F8716 /* APIRequest.swift in Sources */, 9CDFD42F2BAB7641000466B9 /* OnboardingView.swift in Sources */, - 9C83D06C2C204373006F8716 /* GetOTP.swift in Sources */, - 9C83D05C2C1DC46A006F8716 /* Balance.swift in Sources */, - 9C83D0662C1DCD7E006F8716 /* ExecuteFromOutside.swift in Sources */, 9CD390F72BEA3D2A00238FE9 /* EarnView.swift in Sources */, - 9C83D0682C1ED28C006F8716 /* BodyParamsEncoder.swift in Sources */, 9CD778CD2BC3115E00BA4677 /* PhoneValidationView.swift in Sources */, + 9C6ABFD02C21D21A000227D2 /* Configuration.swift in Sources */, 9C4F451B2BDE999000D44CBE /* String+Error.swift in Sources */, 9CDFD42D2BAB4D1D000466B9 /* WelcomeView.swift in Sources */, - 9C83D0632C1DC46A006F8716 /* URLQueryItemEncoder.swift in Sources */, 9C62590C2BF9FFF60039DE9C /* Container.swift in Sources */, 9C6259152BFB5B9A0039DE9C /* SendingRecipientView.swift in Sources */, 9C637CDB2BB09C4D005816B4 /* Notification.swift in Sources */, @@ -733,21 +747,18 @@ 9C62591D2BFE20AF0039DE9C /* Contact.swift in Sources */, 9C62590E2BFA7D260039DE9C /* Icon.swift in Sources */, 9C2E73C52BF3CB86004FFFD1 /* Background.swift in Sources */, - 9C83D05F2C1DC46A006F8716 /* VaultError.swift in Sources */, 9C5CFDB22BC82C57001776E1 /* Array+indexed.swift in Sources */, 9CD778D42BC4426D00BA4677 /* View+placeholder.swift in Sources */, 9CDFD43A2BAC4561000466B9 /* AskSurnameView.swift in Sources */, - 9C83D0722C20495B006F8716 /* Deployment.swift in Sources */, 9C2E73C32BF39635004FFFD1 /* BalanceView.swift in Sources */, 9CD778BA2BBCB89C00BA4677 /* TransferRow.swift in Sources */, 9C6259082BF79F140039DE9C /* FancyAmount.swift in Sources */, 9C62591F2BFE56000039DE9C /* ContactRow.swift in Sources */, - 9C83D0612C1DC46A006F8716 /* GetBalance.swift in Sources */, 9C5CFDAE2BC828C9001776E1 /* Model.swift in Sources */, 9CD1BE982BD7C51A0077A60B /* PhoneNumber+Parse.swift in Sources */, 9C1C9D922C0FB4760028C8FD /* ConfirmationView.swift in Sources */, + 9C9F9EFD2C22368200620AC6 /* VaultAPIClient.swift in Sources */, 9CDFD43E2BAD7F12000466B9 /* Shared.swift in Sources */, - 9C83D0702C2046A6006F8716 /* VerifyOTP.swift in Sources */, 9CDFD3FF2BAB3428000466B9 /* VaultApp.swift in Sources */, 9CD778C62BC1DEEA00BA4677 /* Navigation.swift in Sources */, ); @@ -788,6 +799,7 @@ /* Begin XCBuildConfiguration section */ 9CD1BE912BD563710077A60B /* Debug(Staging) */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9C6ABFCE2C21D0CC000227D2 /* Prod.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -862,6 +874,7 @@ INFOPLIST_FILE = "Vault-Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = Vault; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; + INFOPLIST_KEY_NSContactsUsageDescription = "We need access to your contacts to show them in the app."; INFOPLIST_KEY_NSFaceIDUsageDescription = "Authenticate to access your secure data."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -924,6 +937,7 @@ }; 9CDFD41D2BAB3429000466B9 /* Debug(Development) */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9C6ABFCD2C21CF94000227D2 /* Dev.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -987,6 +1001,7 @@ }; 9CDFD41E2BAB3429000466B9 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 9C6ABFCE2C21D0CC000227D2 /* Prod.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; @@ -1054,6 +1069,7 @@ INFOPLIST_FILE = "Vault-Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = Vault; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; + INFOPLIST_KEY_NSContactsUsageDescription = "We need access to your contacts to show them in the app."; INFOPLIST_KEY_NSFaceIDUsageDescription = "Authenticate to access your secure data."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -1089,6 +1105,7 @@ INFOPLIST_FILE = "Vault-Info.plist"; INFOPLIST_KEY_CFBundleDisplayName = Vault; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; + INFOPLIST_KEY_NSContactsUsageDescription = "We need access to your contacts to show them in the app."; INFOPLIST_KEY_NSFaceIDUsageDescription = "Authenticate to access your secure data."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; diff --git a/app/Vault.xcodeproj/xcshareddata/xcschemes/Vault(Development).xcscheme b/app/Vault.xcodeproj/xcshareddata/xcschemes/Vault(Development).xcscheme index adadfcb5..ebd5fc33 100644 --- a/app/Vault.xcodeproj/xcshareddata/xcschemes/Vault(Development).xcscheme +++ b/app/Vault.xcodeproj/xcshareddata/xcschemes/Vault(Development).xcscheme @@ -74,18 +74,6 @@ ReferencedContainer = "container:Vault.xcodeproj"> - - - - - - - - - -