Skip to content

Commit

Permalink
Merge pull request #902 from WalletConnect/feature/w3m-showcase-integ…
Browse files Browse the repository at this point in the history
…ration

[W3M] Showcase Chat integration
  • Loading branch information
radeknovis authored Jun 12, 2023
2 parents c70ea7b + bc5d1a4 commit ae41f71
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift.git",
"state": {
"branch": null,
"revision": "eee9ad754926c40a0f7e73f152357d37b119b7fa",
"version": "1.7.1"
"revision": "19b3c3ceed117c5cc883517c4e658548315ba70b",
"version": "1.6.0"
}
},
{
Expand All @@ -33,8 +33,8 @@
"repositoryURL": "https://github.com/mxcl/PromiseKit.git",
"state": {
"branch": null,
"revision": "8a98e31a47854d3180882c8068cc4d9381bf382d",
"version": "6.22.1"
"revision": "43772616c46a44a9977e41924ae01d0e55f2f9ca",
"version": "6.18.1"
}
},
{
Expand Down Expand Up @@ -105,8 +105,8 @@
"repositoryURL": "https://github.com/bigearsenal/task-retrying-swift.git",
"state": {
"branch": null,
"revision": "1249b3524378423c848cef39fb220041e00a08ec",
"version": "1.0.4"
"revision": "645eaaf207a6f39ab4b469558d916ae23df199b5",
"version": "1.0.3"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,3 @@ final class AccountStorage {
}
}
}

private extension ImportAccount {

var storageId: String {
switch self {
case .swift, .kotlin, .js:
return name
case .custom(let privateKey):
return privateKey
}
}
}
75 changes: 68 additions & 7 deletions Example/Showcase/Classes/DomainLayer/Chat/ChatService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Foundation
import Combine
import WalletConnectChat
import WalletConnectRelay
import WalletConnectSign

typealias Stream<T> = AnyPublisher<T, Never>

Expand Down Expand Up @@ -81,7 +82,7 @@ final class ChatService {
try await client.reject(inviteId: invite.id)
}

func goPublic(account: Account, privateKey: String) async throws {
func goPublic(account: Account) async throws {
try await client.goPublic(account: account)
}

Expand All @@ -91,17 +92,15 @@ final class ChatService {
try await client.invite(invite: invite)
}

func register(account: Account, privateKey: String) async throws {
func register(account: Account, importAccount: ImportAccount) async throws {
_ = try await client.register(account: account) { message in
let signature = self.onSign(message: message, privateKey: privateKey)
return SigningResult.signed(signature)
return await self.onSign(message: message, importAccount: importAccount)
}
}

func unregister(account: Account, privateKey: String) async throws {
func unregister(account: Account, importAccount: ImportAccount) async throws {
try await client.unregister(account: account) { message in
let signature = self.onSign(message: message, privateKey: privateKey)
return SigningResult.signed(signature)
return await self.onSign(message: message, importAccount: importAccount)
}
}

Expand All @@ -116,9 +115,71 @@ final class ChatService {

private extension ChatService {

func onSign(message: String, importAccount: ImportAccount) async -> SigningResult {
switch importAccount {
case .swift, .kotlin, .js, .custom:
return .signed(onSign(message: message, privateKey: importAccount.privateKey))
case .web3Modal(let account, let topic):
return await onWeb3ModalSign(message: message, account: account, topic: topic)
}
}

func onSign(message: String, privateKey: String) -> CacaoSignature {
let privateKey = Data(hex: privateKey)
let signer = MessageSignerFactory(signerFactory: DefaultSignerFactory()).create()
return try! signer.sign(message: message, privateKey: privateKey, type: .eip191)
}

func onWeb3ModalSign(message: String, account: Account, topic: String) async -> SigningResult {
guard let session = Sign.instance.getSessions().first(where: { $0.topic == topic }) else { return .rejected }

do {
let request = makeRequest(session: session, message: message, account: account)
try await Sign.instance.request(params: request)

let signature: CacaoSignature = try await withCheckedThrowingContinuation { continuation in
var cancellable: AnyCancellable?
cancellable = Sign.instance.sessionResponsePublisher
.sink { response in
defer { cancellable?.cancel() }
switch response.result {
case .response(let value):
do {
let string = try value.get(String.self)
let signature = CacaoSignature(t: .eip191, s: string.deleting0x())
continuation.resume(returning: signature)
} catch {
continuation.resume(throwing: error)
}
case .error(let error):
continuation.resume(throwing: error)
}
}
}

return .signed(signature)
} catch {
return .rejected
}
}

func makeRequest(session: WalletConnectSign.Session, message: String, account: Account) -> Request {
return Request(
topic: session.topic,
method: "personal_sign",
params: AnyCodable(["0x" + message.data(using: .utf8)!.toHexString(), account.address]),
chainId: Blockchain("eip155:1")!
)
}
}

fileprivate extension String {

func deleting0x() -> String {
var string = self
if starts(with: "0x") {
string.removeFirst(2)
}
return string
}
}
55 changes: 40 additions & 15 deletions Example/Showcase/Classes/DomainLayer/Chat/ImportAccount.swift
Original file line number Diff line number Diff line change
@@ -1,41 +1,62 @@
import Foundation
import Web3
import WalletConnectSign

enum ImportAccount {
enum ImportAccount: Codable {
case swift
case kotlin
case js
case custom(privateKey: String)
case web3Modal(account: Account, topic: String)

static let swiftId = "swift.eth"
static let kotlinId = "kotlin.eth"
static let jsId = "js.eth"
static let privateKeyId = "privateKey"
static let web3ModalId = "web3Modal"

init?(input: String) {
switch input.lowercased() {
case ImportAccount.swift.name:
case ImportAccount.swiftId:
self = .swift
case ImportAccount.kotlin.name:
case ImportAccount.kotlinId:
self = .kotlin
case ImportAccount.js.name:
case ImportAccount.jsId:
self = .js
default:
if let _ = try? EthereumPrivateKey(hexPrivateKey: "0x" + input, ctx: nil) {
self = .custom(privateKey: input)
} else if let _ = try? EthereumPrivateKey(hexPrivateKey: input, ctx: nil) {
self = .custom(privateKey: input.replacingOccurrences(of: "0x", with: ""))
} else {
switch true {
case input.starts(with: ImportAccount.privateKeyId):
if let _ = try? EthereumPrivateKey(hexPrivateKey: "0x" + input, ctx: nil) {
self = .custom(privateKey: input)
} else if let _ = try? EthereumPrivateKey(hexPrivateKey: input, ctx: nil) {
self = .custom(privateKey: input.replacingOccurrences(of: "0x", with: ""))
} else {
return nil
}
case input.starts(with: ImportAccount.web3ModalId):
let components = input.components(separatedBy: "-")
guard components.count == 3, let account = Account(components[1]) else {
return nil
}
self = .web3Modal(account: account, topic: components[2])
default:
return nil
}
}
}

var name: String {
var storageId: String {
switch self {
case .swift:
return "swift.eth"
return ImportAccount.swiftId
case .kotlin:
return "kotlin.eth"
return ImportAccount.kotlinId
case .js:
return "js.eth"
case .custom:
return account.address
return ImportAccount.jsId
case .custom(let privateKey):
return "\(ImportAccount.privateKeyId)-\(privateKey)"
case .web3Modal(let account, let topic):
return "\(ImportAccount.web3ModalId)-\(account.absoluteString)-\(topic)"
}
}

Expand All @@ -50,6 +71,8 @@ enum ImportAccount {
case .custom(let privateKey):
let address = try! EthereumPrivateKey(hexPrivateKey: "0x" + privateKey, ctx: nil).address.hex(eip55: true)
return Account("eip155:1:\(address)")!
case .web3Modal(let account, _):
return account
}
}

Expand All @@ -63,6 +86,8 @@ enum ImportAccount {
return "de15cb11963e9bde0a5cce06a5ee2bda1cf3a67be6fbcd7a4fc8c0e4c4db0298"
case .custom(let privateKey):
return privateKey
case .web3Modal:
fatalError("Private key not available")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ final class ChatListInteractor {
func logout() async throws {
guard let importAccount = accountStorage.importAccount else { return }
try await chatService.goPrivate(account: importAccount.account)
try await chatService.unregister(account: importAccount.account, privateKey: importAccount.privateKey)
try await chatService.unregister(account: importAccount.account, importAccount: importAccount)
accountStorage.importAccount = nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ final class ImportInteractor {
}

func register(importAccount: ImportAccount) async throws {
try await chatService.register(account: importAccount.account, privateKey: importAccount.privateKey)
try await chatService.register(account: importAccount.account, importAccount: importAccount)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UIKit
import Combine
import WalletConnectSign

final class ImportPresenter: ObservableObject {

Expand All @@ -18,6 +19,20 @@ final class ImportPresenter: ObservableObject {
@MainActor
func didPressWeb3Modal() async throws {
router.presentWeb3Modal()

let session: Session = try await withCheckedThrowingContinuation { continuation in
var cancellable: AnyCancellable?
cancellable = Sign.instance.sessionSettlePublisher.sink { session in
defer { cancellable?.cancel() }
return continuation.resume(returning: session)
}
}

guard let account = session.accounts.first(where: { $0.blockchain.absoluteString == "eip155:1" }) else {
throw AlertError(message: "Тo matching accounts found in namespaces")
}

try await importAccount(.web3Modal(account: account, topic: session.topic))
}

@MainActor
Expand Down Expand Up @@ -57,8 +72,8 @@ private extension ImportPresenter {

@MainActor
func importAccount(_ importAccount: ImportAccount) async throws {
try! await interactor.register(importAccount: importAccount)
interactor.save(importAccount: importAccount)
try await interactor.register(importAccount: importAccount)
router.presentChat(importAccount: importAccount)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ final class WelcomeInteractor {

func goPublic() async throws {
guard let importAccount = importAccount else { return }
try await chatService.goPublic(account: importAccount.account, privateKey: importAccount.privateKey)
try await chatService.goPublic(account: importAccount.account)
}
}

Expand Down
6 changes: 6 additions & 0 deletions Sources/WalletConnectSign/Session.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ extension Session {
SessionType.EventParams.Event(name: name, data: data)
}
}

public var accounts: [Account] {
return namespaces.values.reduce(into: []) { result, namespace in
result = result + Array(namespace.accounts)
}
}
}

0 comments on commit ae41f71

Please sign in to comment.