From ae416f60485ba5eb474ad1b517ebaa13095381af Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 28 Mar 2024 12:26:02 +0100 Subject: [PATCH 1/4] update sample app --- .../AuthRequest/AuthRequestPresenter.swift | 54 ++++++++++++++++ .../Wallet/AuthRequest/AuthRequestView.swift | 62 ++++++++++++++----- 2 files changed, 101 insertions(+), 15 deletions(-) diff --git a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift index 01813b92f..8b8626aa0 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift @@ -5,6 +5,9 @@ import Web3Wallet import WalletConnectRouter final class AuthRequestPresenter: ObservableObject { + enum Errors: Error { + case noCommonChains + } private let router: AuthRequestRouter let importAccount: ImportAccount @@ -73,6 +76,30 @@ final class AuthRequestPresenter: ObservableObject { } } + @MainActor + func signOne() async { + do { + ActivityIndicatorManager.shared.start() + + let auths = try buildOneAuthObject() + + _ = try await Web3Wallet.instance.approveSessionAuthenticate(requestId: request.id, auths: auths) + ActivityIndicatorManager.shared.stop() + + /* Redirect */ + if let uri = request.requester.redirect?.native { + WalletConnectRouter.goBack(uri: uri) + router.dismiss() + } else { + showSignedSheet.toggle() + } + + } catch { + ActivityIndicatorManager.shared.stop() + AlertPresenter.present(message: error.localizedDescription, type: .error) + } + } + @MainActor func reject() async { ActivityIndicatorManager.shared.start() @@ -99,6 +126,33 @@ final class AuthRequestPresenter: ObservableObject { } private func buildAuthObjects() throws -> [AuthObject] { + + guard let chain = getCommonAndRequestedChainsIntersection().first else { + throw Errors.noCommonChains + } + + let account = Account(blockchain: chain, address: importAccount.account.address)! + + var supportedAuthPayload: AuthPayload! + do { + supportedAuthPayload = try Web3Wallet.instance.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!, Blockchain("eip155:69")!], supportedMethods: ["personal_sign", "eth_sendTransaction"]) + } catch { + Task { await reject() } + throw error + } + let SIWEmessages = try Web3Wallet.instance.formatAuthMessage(payload: supportedAuthPayload, account: account) + + let signature = try messageSigner.sign( + message: SIWEmessages, + privateKey: Data(hex: importAccount.privateKey), + type: .eip191) + + let auth = try Web3Wallet.instance.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: account) + + return [auth] + } + + private func buildOneAuthObject() throws -> [AuthObject] { var auths = [AuthObject]() try getCommonAndRequestedChainsIntersection().forEach { chain in diff --git a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift index e2b81cd20..73ce87bc6 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestView.swift @@ -93,20 +93,8 @@ struct AuthRequestView: View { } } - if case .scam = presenter.validationStatus { - VStack(spacing: 20) { - declineButton() - allowButton() - } - .padding(.top, 25) - } else { - HStack { - declineButton() - allowButton() - } - .padding(.top, 25) - } - + buttonGroup() + } .padding(20) @@ -241,7 +229,7 @@ struct AuthRequestView: View { presenter.approve() } } label: { - Text(presenter.validationStatus == .scam ? "Proceed anyway" : "Allow") + Text(presenter.validationStatus == .scam ? "Proceed anyway" : "Sign Multi") .frame(maxWidth: .infinity) .foregroundColor(presenter.validationStatus == .scam ? .grey50 : .white) .font(.system(size: 20, weight: .semibold, design: .rounded)) @@ -265,6 +253,50 @@ struct AuthRequestView: View { } .shadow(color: .white.opacity(0.25), radius: 8, y: 2) } + + private func signOneButton() -> some View { + Button { + Task(priority: .userInitiated) { + await presenter.signOne() + } + } label: { + Text("Sign One") + .frame(maxWidth: .infinity) + .foregroundColor(.white) + .font(.system(size: 20, weight: .semibold, design: .rounded)) + .padding(.vertical, 11) + .background( + LinearGradient( + gradient: Gradient(colors: [.blue, .purple]), // Example gradient, adjust as needed + startPoint: .top, endPoint: .bottom + ) + ) + .cornerRadius(20) + } + .shadow(color: .white.opacity(0.25), radius: 8, y: 2) + } + + // Adjusted layout to include the signOneButton + private func buttonGroup() -> some View { + Group { + if case .scam = presenter.validationStatus { + VStack(spacing: 20) { + declineButton() + signOneButton() // Place the "Sign One" button between "Decline" and "Allow" + allowButton() + } + .padding(.top, 25) + } else { + HStack { + declineButton() + signOneButton() // Include the "Sign One" button in the horizontal stack + allowButton() + } + .padding(.top, 25) + } + } + } + } #if DEBUG From 45bdb0670c01ae3dd1da8756ac2d415b76d5295b Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 28 Mar 2024 13:06:11 +0100 Subject: [PATCH 2/4] update --- .../AuthRequest/AuthRequestPresenter.swift | 51 ++++++------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift index 8b8626aa0..131546b82 100644 --- a/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift +++ b/Example/WalletApp/PresentationLayer/Wallet/AuthRequest/AuthRequestPresenter.swift @@ -125,30 +125,26 @@ final class AuthRequestPresenter: ObservableObject { router.dismiss() } - private func buildAuthObjects() throws -> [AuthObject] { - - guard let chain = getCommonAndRequestedChainsIntersection().first else { - throw Errors.noCommonChains - } - + private func createAuthObjectForChain(chain: Blockchain) throws -> AuthObject { let account = Account(blockchain: chain, address: importAccount.account.address)! - var supportedAuthPayload: AuthPayload! - do { - supportedAuthPayload = try Web3Wallet.instance.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!, Blockchain("eip155:69")!], supportedMethods: ["personal_sign", "eth_sendTransaction"]) - } catch { - Task { await reject() } - throw error - } + let supportedAuthPayload = try Web3Wallet.instance.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!, Blockchain("eip155:69")!], supportedMethods: ["personal_sign", "eth_sendTransaction"]) + let SIWEmessages = try Web3Wallet.instance.formatAuthMessage(payload: supportedAuthPayload, account: account) - let signature = try messageSigner.sign( - message: SIWEmessages, - privateKey: Data(hex: importAccount.privateKey), - type: .eip191) + let signature = try messageSigner.sign(message: SIWEmessages, privateKey: Data(hex: importAccount.privateKey), type: .eip191) let auth = try Web3Wallet.instance.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: account) + return auth + } + + private func buildAuthObjects() throws -> [AuthObject] { + guard let chain = getCommonAndRequestedChainsIntersection().first else { + throw Errors.noCommonChains + } + + let auth = try createAuthObjectForChain(chain: chain) return [auth] } @@ -156,30 +152,13 @@ final class AuthRequestPresenter: ObservableObject { var auths = [AuthObject]() try getCommonAndRequestedChainsIntersection().forEach { chain in - - let account = Account(blockchain: chain, address: importAccount.account.address)! - - var supportedAuthPayload: AuthPayload! - do { - supportedAuthPayload = try Web3Wallet.instance.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!, Blockchain("eip155:69")!], supportedMethods: ["personal_sign", "eth_sendTransaction"]) - } catch { - Task { await reject() } - throw error - } - let SIWEmessages = try Web3Wallet.instance.formatAuthMessage(payload: supportedAuthPayload, account: account) - - let signature = try messageSigner.sign( - message: SIWEmessages, - privateKey: Data(hex: importAccount.privateKey), - type: .eip191) - - let auth = try Web3Wallet.instance.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: account) - + let auth = try createAuthObjectForChain(chain: chain) auths.append(auth) } return auths } + func getCommonAndRequestedChainsIntersection() -> Set { let requestedChains: Set = Set(request.payload.chains.compactMap { Blockchain($0) }) let supportedChains: Set = [Blockchain("eip155:1")!, Blockchain("eip155:137")!] From 80d7eebb9e22dea46a7d389d15aad9f418bd5db6 Mon Sep 17 00:00:00 2001 From: Bartosz Rozwarski Date: Thu, 28 Mar 2024 14:48:08 +0100 Subject: [PATCH 3/4] fix addresses order --- .../Auth/Services/SessionNamespaceBuilder.swift | 15 ++++++++++++++- .../SessionNamespaceBuilderTests.swift | 6 +++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Sources/WalletConnectSign/Auth/Services/SessionNamespaceBuilder.swift b/Sources/WalletConnectSign/Auth/Services/SessionNamespaceBuilder.swift index 3e1931910..343a66934 100644 --- a/Sources/WalletConnectSign/Auth/Services/SessionNamespaceBuilder.swift +++ b/Sources/WalletConnectSign/Auth/Services/SessionNamespaceBuilder.swift @@ -38,7 +38,7 @@ class SessionNamespaceBuilder { throw Errors.cannotCreateSessionNamespaceFromTheRecap } - let addresses = Set(cacaos.compactMap { try? DIDPKH(did: $0.p.iss).account.address }) + let addresses = getUniqueAddresses(from: cacaos) var accounts = [Account]() for address in addresses { @@ -56,4 +56,17 @@ class SessionNamespaceBuilder { return [chainsNamespace: sessionNamespace] } + func getUniqueAddresses(from cacaos: [Cacao]) -> [String] { + var seenAddresses = Set() + var uniqueAddresses = [String]() + + for cacao in cacaos { + if let address = try? DIDPKH(did: cacao.p.iss).account.address, !seenAddresses.contains(address) { + uniqueAddresses.append(address) + seenAddresses.insert(address) + } + } + return uniqueAddresses + } + } diff --git a/Tests/WalletConnectSignTests/SessionNamespaceBuilderTests.swift b/Tests/WalletConnectSignTests/SessionNamespaceBuilderTests.swift index d441cafb1..aadfd436c 100644 --- a/Tests/WalletConnectSignTests/SessionNamespaceBuilderTests.swift +++ b/Tests/WalletConnectSignTests/SessionNamespaceBuilderTests.swift @@ -66,10 +66,10 @@ class SessionNamespaceBuilderTests: XCTestCase { let expectedSessionNamespace = SessionNamespace( chains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], accounts: [ - Account("eip155:1:0x990a10343Bcdebe21283c7172d67a9a113E819X5")!, - Account("eip155:137:0x990a10343Bcdebe21283c7172d67a9a113E819X5")!, Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!, - Account("eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5")! + Account("eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!, + Account("eip155:1:0x990a10343Bcdebe21283c7172d67a9a113E819X5")!, + Account("eip155:137:0x990a10343Bcdebe21283c7172d67a9a113E819X5")! ], methods: Set(["personal_sign", "eth_signTypedData", "eth_sign"]), events: Set(["chainChanged", "accountsChanged"]) From f09dc2a60f14c631c3ce71ca83721cabb29d206c Mon Sep 17 00:00:00 2001 From: llbartekll Date: Fri, 29 Mar 2024 07:35:03 +0000 Subject: [PATCH 4/4] Set User Agent --- Sources/WalletConnectRelay/PackageConfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WalletConnectRelay/PackageConfig.json b/Sources/WalletConnectRelay/PackageConfig.json index b14d280bf..2c162848f 100644 --- a/Sources/WalletConnectRelay/PackageConfig.json +++ b/Sources/WalletConnectRelay/PackageConfig.json @@ -1 +1 @@ -{"version": "1.18.3"} +{"version": "1.18.4"}