diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.pbxproj b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.pbxproj index 131d07ae..9060c427 100644 --- a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.pbxproj +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 284BE6342BC512A80049C203 /* RecoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 284BE6332BC512A80049C203 /* RecoveryView.swift */; }; 284BE6362BC512B20049C203 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 284BE6352BC512B20049C203 /* HomeView.swift */; }; 284BE63E2BC55A080049C203 /* EthereumHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 284BE63D2BC55A080049C203 /* EthereumHelper.swift */; }; + F0B964702D376989008A3FE1 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0B9646F2D376983008A3FE1 /* LoadingView.swift */; }; F0EB92902D27C1270024D038 /* mpc-core-kit-swift in Frameworks */ = {isa = PBXBuildFile; productRef = F0EB928F2D27C1270024D038 /* mpc-core-kit-swift */; }; F0EB92922D27C12A0024D038 /* MpcProviderSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F0EB92912D27C12A0024D038 /* MpcProviderSwift */; }; /* End PBXBuildFile section */ @@ -60,6 +61,8 @@ 284BE6332BC512A80049C203 /* RecoveryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecoveryView.swift; sourceTree = ""; }; 284BE6352BC512B20049C203 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 284BE63D2BC55A080049C203 /* EthereumHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EthereumHelper.swift; sourceTree = ""; }; + F09C56682D2F93C00056861D /* mpc-core-kit-ios-quick-start.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "mpc-core-kit-ios-quick-start.entitlements"; sourceTree = ""; }; + F0B9646F2D376983008A3FE1 /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -113,6 +116,7 @@ 284BE5FC2BC509500049C203 /* mpc-core-kit-ios-quick-start */ = { isa = PBXGroup; children = ( + F09C56682D2F93C00056861D /* mpc-core-kit-ios-quick-start.entitlements */, 284BE6302BC50C3C0049C203 /* Helpers */, 284BE62B2BC50A0E0049C203 /* Models */, 284BE62A2BC50A080049C203 /* Views */, @@ -151,6 +155,7 @@ 284BE62A2BC50A080049C203 /* Views */ = { isa = PBXGroup; children = ( + F0B9646F2D376983008A3FE1 /* LoadingView.swift */, 284BE5FF2BC509500049C203 /* ContentView.swift */, 284BE62C2BC50A1F0049C203 /* LoginView.swift */, 284BE6332BC512A80049C203 /* RecoveryView.swift */, @@ -324,6 +329,7 @@ files = ( 284712242BFB94450088411D /* Extension.swift in Sources */, 284BE62D2BC50A1F0049C203 /* LoginView.swift in Sources */, + F0B964702D376989008A3FE1 /* LoadingView.swift in Sources */, 284BE6362BC512B20049C203 /* HomeView.swift in Sources */, 284BE6002BC509500049C203 /* ContentView.swift in Sources */, 284BE5FE2BC509500049C203 /* mpc_core_kit_ios_quick_startApp.swift in Sources */, @@ -491,6 +497,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.entitlements"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"mpc-core-kit-ios-quick-start/Preview Content\""; @@ -520,6 +527,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.entitlements"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"mpc-core-kit-ios-quick-start/Preview Content\""; @@ -666,7 +674,7 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/tkey/mpc-core-kit-swift"; requirement = { - branch = update_dependencies; + branch = feat/signer; kind = branch; }; }; diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c24b64b6..0df5bce1 100644 --- a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -60,8 +60,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/tkey/mpc-core-kit-swift", "state" : { - "branch" : "update_dependencies", - "revision" : "742afd28c5a7319933c1f41f6796d864581fe0dc" + "branch" : "feat/signer", + "revision" : "31261336790df3227a34d365fd038e10b3c3c7f2" } }, { @@ -195,8 +195,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/tkey/tkey-mpc-swift", "state" : { - "revision" : "b6d9d1013f21f51105e845a0c16ee39b2f01fd1c", - "version" : "4.0.1" + "revision" : "74ea5301e316163b48e653ba107fd9edd4fe6bf8", + "version" : "4.0.2" } }, { diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcuserdata/apollo.xcuserdatad/UserInterfaceState.xcuserstate b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcuserdata/apollo.xcuserdatad/UserInterfaceState.xcuserstate index 116c819a..6c49afb3 100644 Binary files a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcuserdata/apollo.xcuserdatad/UserInterfaceState.xcuserstate and b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/project.xcworkspace/xcuserdata/apollo.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/xcuserdata/apollo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/xcuserdata/apollo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 00000000..fc54be70 --- /dev/null +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.xcodeproj/xcuserdata/apollo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,328 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Models/MainViewModel.swift b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Models/MainViewModel.swift index 792ade59..165b43cf 100644 --- a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Models/MainViewModel.swift +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Models/MainViewModel.swift @@ -16,6 +16,10 @@ class MainViewModel: ObservableObject { @Published var isRecoveryRequired: Bool = false @Published var factorPubs: [String] = [] + @Published var showAlert: Bool = false + + @Published var isLoaderVisible: Bool = false + var publicAddress: String! @@ -23,10 +27,14 @@ class MainViewModel: ObservableObject { private var ethereumClient: EthereumClient! private var mpcEthereumProvider: MPCEthereumProvider! + + var alertContent: String = "" + var loaderContent: String = "" + func initialize() throws { mpcCoreKit = try MpcCoreKit( - options: .init(web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ", - web3AuthNetwork: .SAPPHIRE_MAINNET, storage: UserStorage() + options: .init(web3AuthClientId: "BHgArYmWwSeq21czpcarYh0EVq2WWOzflX-NTK-tY1-1pauPzHKRRLgpABkmYiIV_og9jAvoIxQ8L3Smrwe04Lw", + web3AuthNetwork: .SAPPHIRE_DEVNET, storage: UserStorage() ) ) @@ -57,7 +65,7 @@ class MainViewModel: ObservableObject { Task { do { let result = try await mpcCoreKit.loginWithOAuth( - singleLoginParams: .init(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") + singleLoginParams: .init(typeOfLogin: .google, verifier: "w3a-sfa-web-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") ) DispatchQueue.main.async { @@ -78,7 +86,8 @@ class MainViewModel: ObservableObject { do { try await mpcCoreKit.resetAccount() DispatchQueue.main.async { - self.isRecoveryRequired.toggle() + self.isRecoveryRequired = false + self.isLoggedIn = false } } catch let error { print(error.localizedDescription) @@ -101,9 +110,10 @@ class MainViewModel: ObservableObject { func signMessage(onSigned: @escaping (_ signedMessage: String?, _ error: String?) -> ()){ Task { do { + let signature = try mpcCoreKit.sign(message: "YOUR_MESSAGE".data(using: .ascii)!) print(mpcCoreKit.debugDescription) - let signature = try mpcEthereumProvider.signMessage(message: "YOUR_MESSAGE".data(using: .ascii)!) - onSigned(signature, nil) +// let signature = try mpcEthereumProvider.signMessage(message: "YOUR_MESSAGE".data(using: .ascii)!) + onSigned(signature.hexString, nil) } catch let error { onSigned(nil, error.localizedDescription) } @@ -213,6 +223,15 @@ class MainViewModel: ObservableObject { } } + func logout() { + Task { + do { + try await mpcCoreKit.logout() + toggleIsLoggedIn() + } + } + } + private func login() async throws { mpcEthereumProvider = MPCEthereumProvider(evmSigner: mpcCoreKit) publicAddress = mpcEthereumProvider.address.toChecksumAddress() @@ -233,4 +252,24 @@ class MainViewModel: ObservableObject { self.isLoggedIn.toggle() } } + + func showLoader(_ message: String) { + loaderContent = message + DispatchQueue.main.async { + self.isLoaderVisible = true + } + } + + func hideLoader() { + DispatchQueue.main.async { + self.isLoaderVisible = false + } + } + + func showAlert(message: String) { + alertContent = message + DispatchQueue.main.async { + self.showAlert = true + } + } } diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/HomeView.swift b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/HomeView.swift index 357b354e..b91f51ed 100644 --- a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/HomeView.swift +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/HomeView.swift @@ -17,107 +17,130 @@ struct HomeView: View { var body: some View { NavigationView { - Form { - Section(header: Text("Public Address")) { - Button( - action: { - UIPasteboard.general.string = viewModel.publicAddress - }, label: { - Text(viewModel.publicAddress) - }) + LoadingView(viewModel: viewModel, content: { + Form { + Section(header: Text("Public Address")) { + Button( + action: { + UIPasteboard.general.string = viewModel.publicAddress + }, label: { + Text(viewModel.publicAddress) + }) + + } - } - - Section(header: Text("Chain Interactions")) { - Button( - action: { - viewModel.signMessage{ - result, error in - if result != nil { - signedMessage = result + Section(header: Text("Chain Interactions")) { + Button( + action: { + viewModel.signMessage{ + result, error in + if result != nil { + signedMessage = result + } } + }, + label: { + Text("Sign Message") } - }, - label: { - Text("Sign Message") + ) + + if signedMessage != nil { + Text(signedMessage!) } - ) - - if signedMessage != nil { - Text(signedMessage!) - } - - Button( - action: { - viewModel.sendTransaction{ - result, error in - if result != nil { - hash = result + + Button( + action: { + viewModel.sendTransaction{ + result, error in + if result != nil { + hash = result + } } + }, + label: { + Text("Send 0.001 ETH") } - }, - label: { - Text("Send 0.001 ETH") + ) + + if(hash != nil) { + Link( + hash!, + destination: URL( + string: "https://sepolia.etherscan.io/tx/\(hash!)" + )! + ).underline() } - ) - - if(hash != nil) { - Link( - hash!, - destination: URL( - string: "https://sepolia.etherscan.io/tx/\(hash!)" - )! - ).underline() + + Text("The sample uses Eth Sepolia, you can choose any EVM network of your choice. Send 0.001 ETH will perform self transfer of ETH. You'll need to have Sepolia faucet to perform transaction.").font(.caption) + } - Text("The sample uses Eth Sepolia, you can choose any EVM network of your choice. Send 0.001 ETH will perform self transfer of ETH. You'll need to have Sepolia faucet to perform transaction.").font(.caption) - - } - - if(!viewModel.factorPubs.isEmpty) { - Section(header: Text("TSS Factors PubKey")) { - ForEach(Array(viewModel.factorPubs), id: \.self) { factorPub in - HStack( - alignment: .top, - spacing: 24, - content: { - Text(factorPub) - Button(action: { - withAnimation { - viewModel.deleteFactor( - factorPub: factorPub - ) + if(!viewModel.factorPubs.isEmpty) { + Section(header: Text("TSS Factors PubKey")) { + ForEach(Array(viewModel.factorPubs), id: \.self) { factorPub in + HStack( + alignment: .top, + spacing: 24, + content: { + Text(factorPub) + Button(action: { + withAnimation { + viewModel.deleteFactor( + factorPub: factorPub + ) + } + }) { + Label("",systemImage: "trash") } - }) { - Label("",systemImage: "trash") } - } - ) + ) + } } } + + Section( + header: Text("TSS Operations") + ) { + Button( + action: { + viewModel.enableMFA() + }, + label: { + Text("Enable MFA") + } + ) + Button( + action: { + viewModel.showAlert(message: "creating factor...") + viewModel.createNewTssFactor() + viewModel.hideLoader() + }, + label: { + Text("Create new Factor") + } + ) + Button( + action: { + viewModel.logout() + }, + label: { + Text("Logout") + } + ) + + Button( + action: { + viewModel.resetAccount() + }, + label: { + Text("Reset") + } + ) + } } - - Section( - header: Text("TSS Operations") - ) { - Button( - action: { - viewModel.enableMFA() - }, - label: { - Text("Enable MFA") - } - ) - Button( - action: { - viewModel.createNewTssFactor() - }, - label: { - Text("Create new Factor") - } - ) - } - } - } + }) + }.alert(isPresented: $viewModel.showAlert, content: { + Alert(title: Text(viewModel.alertContent)) + }) } } diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/LoadingView.swift b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/LoadingView.swift new file mode 100644 index 00000000..ddf9e692 --- /dev/null +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/Views/LoadingView.swift @@ -0,0 +1,50 @@ +// +// Loading.swift +// mpc-core-kit-ios-quick-start +// +// Created by CW Lee on 15/01/2025. +// + +import SwiftUI + +struct ActivityIndicator: UIViewRepresentable { + + @Binding var isAnimating: Bool + let style: UIActivityIndicatorView.Style + + func makeUIView(context: UIViewRepresentableContext) -> UIActivityIndicatorView { + return UIActivityIndicatorView(style: style) + } + + func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext) { + isAnimating ? uiView.startAnimating() : uiView.stopAnimating() + } +} + +struct LoadingView: View where Content: View { + @StateObject var viewModel: MainViewModel + var content: () -> Content + + var body: some View { + GeometryReader { geometry in + ZStack(alignment: .center) { + + self.content() + .disabled(viewModel.isLoaderVisible) + .blur(radius: viewModel.isLoaderVisible ? 3 : 0) + + VStack { + Text(viewModel.loaderContent) + ActivityIndicator(isAnimating: .constant(true), style: .large) + } + .frame(width: geometry.size.width / 2, + height: geometry.size.height / 5) + .background(Color.secondary.colorInvert()) + .foregroundColor(Color.primary) + .cornerRadius(20) + .opacity(viewModel.isLoaderVisible ? 1 : 0) + + } + } + } +} diff --git a/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.entitlements b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.entitlements new file mode 100644 index 00000000..fbad0237 --- /dev/null +++ b/mpc-core-kit-ios/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start/mpc-core-kit-ios-quick-start.entitlements @@ -0,0 +1,8 @@ + + + + + keychain-access-groups + + +