Skip to content

Commit

Permalink
Refactor WalletConnect
Browse files Browse the repository at this point in the history
  • Loading branch information
ant013 committed Nov 4, 2023
1 parent 01ddb55 commit 27a4e30
Show file tree
Hide file tree
Showing 42 changed files with 1,222 additions and 919 deletions.
333 changes: 222 additions & 111 deletions UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions UnstoppableWallet/UnstoppableWallet/Core/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ class App {

let marketKit: MarketKit.Kit


let themeManager: ThemeManager
let systemInfoManager: SystemInfoManager

Expand Down Expand Up @@ -94,6 +93,7 @@ class App {
let guidesManager: GuidesManager
let termsManager: TermsManager

let walletConnectRequestHandler: WalletConnectRequestChain
let walletConnectSocketConnectionService: WalletConnectSocketConnectionService
let walletConnectSessionManager: WalletConnectSessionManager
let walletConnectManager: WalletConnectManager
Expand Down Expand Up @@ -268,6 +268,11 @@ class App {
guidesManager = GuidesManager(networkManager: networkManager)
termsManager = TermsManager(userDefaultsStorage: userDefaultsStorage)

walletConnectRequestHandler = WalletConnectRequestChain.instance(
evmBlockchainManager: evmBlockchainManager,
accountManager: accountManager
)

walletConnectManager = WalletConnectManager(accountManager: accountManager, evmBlockchainManager: evmBlockchainManager)

let walletClientInfo = WalletConnectClientInfo(
Expand All @@ -282,12 +287,17 @@ class App {
walletConnectSocketConnectionService = WalletConnectSocketConnectionService(reachabilityManager: reachabilityManager, logger: logger)
let walletConnectService = WalletConnectService(
connectionService: walletConnectSocketConnectionService,
sessionRequestFilterManager: SessionRequestFilterManager(),
info: walletClientInfo,
logger: logger
)
let walletConnectSessionStorage = WalletConnectSessionStorage(dbPool: dbPool)
walletConnectSessionManager = WalletConnectSessionManager(service: walletConnectService, storage: walletConnectSessionStorage, accountManager: accountManager, evmBlockchainManager: evmBlockchainManager, currentDateProvider: CurrentDateProvider())
walletConnectSessionManager = WalletConnectSessionManager(
service: walletConnectService,
storage: walletConnectSessionStorage,
accountManager: accountManager,
requestHandler: walletConnectRequestHandler,
currentDateProvider: CurrentDateProvider()
)

deepLinkManager = DeepLinkManager()
launchScreenManager = LaunchScreenManager(userDefaultsStorage: userDefaultsStorage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ class WalletConnectSessionManager {
private let storage: WalletConnectSessionStorage
private let accountManager: AccountManager
private let currentDateProvider: CurrentDateProvider
private let evmBlockchainManager: EvmBlockchainManager
private let requestHandler: IWalletConnectRequestHandler

private let sessionsRelay = BehaviorRelay<[WalletConnectSign.Session]>(value: [])
private let activePendingRequestsRelay = BehaviorRelay<[WalletConnectSign.Request]>(value: [])
private let pairingsRelay = BehaviorRelay<[WalletConnectPairing.Pairing]>(value: [])
private let sessionRequestReceivedRelay = PublishRelay<WalletConnectRequest>()

init(service: WalletConnectService, storage: WalletConnectSessionStorage, accountManager: AccountManager, evmBlockchainManager: EvmBlockchainManager, currentDateProvider: CurrentDateProvider) {
init(service: WalletConnectService, storage: WalletConnectSessionStorage, accountManager: AccountManager, requestHandler: IWalletConnectRequestHandler, currentDateProvider: CurrentDateProvider) {
self.service = service
self.storage = storage
self.accountManager = accountManager
self.evmBlockchainManager = evmBlockchainManager
self.requestHandler = requestHandler
self.currentDateProvider = currentDateProvider

subscribe(disposeBag, accountManager.accountDeletedObservable) { [weak self] in
Expand Down Expand Up @@ -95,25 +95,17 @@ class WalletConnectSessionManager {
}
let activeSessions = storage.sessions(accountId: account.id)

guard let chainId = Int(request.chainId.reference),
let blockchain = evmBlockchainManager.blockchain(chainId: chainId),
let address = try? WalletConnectManager.evmAddress(
account: account,
chain: evmBlockchainManager.chain(blockchainType: blockchain.type)
)
else {
return
}

let chain = WalletConnectRequest.Chain(id: chainId, chainName: blockchain.name, address: address.eip55)
guard activeSessions.first(where: { session in session.topic == request.topic }) != nil,
let session = allSessions.first(where: { session in session.topic == request.topic }),
let request = try? WalletConnectRequestMapper.map(dAppName: session.peer.name, chain: chain, request: request)
else {
let session = allSessions.first(where: { session in session.topic == request.topic }) else {
return
}

sessionRequestReceivedRelay.accept(request)
let request = requestHandler.handle(session: session, request: request)
switch request {
case .request(let request): sessionRequestReceivedRelay.accept(request)
case .handled: ()
case .unsuccessful(error: let error): print("Error while parsing request: \(error)")
}
}

private func sessions(accountId: String, sessions: [WalletConnectSign.Session]?) -> [WalletConnectSign.Session] {
Expand All @@ -137,12 +129,6 @@ class WalletConnectSessionManager {
pairingsRelay.accept(service.pairings)
}

private func isChainIdsEnabled(chainIds: [Int]) -> Bool {
chainIds.allSatisfy { id in
evmBlockchainManager.blockchain(chainId: id) != nil
}
}

private func requests(accountId: String? = nil) -> [WalletConnectSign.Request] {
let allRequests = service.pendingRequests
let dbSessions = storage.sessions(accountId: accountId)
Expand All @@ -169,9 +155,7 @@ extension WalletConnectSessionManager {
}

public var allSessions: [WalletConnectSign.Session] {
service.activeSessions.filter { session in
isChainIdsEnabled(chainIds: session.chainIds)
}
service.activeSessions
}

public var sessionsObservable: Observable<[WalletConnectSign.Session]> {
Expand Down
12 changes: 12 additions & 0 deletions UnstoppableWallet/UnstoppableWallet/Extensions/Encodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation

extension Encodable {
public var encoded: Data {
let encoder = JSONEncoder()
encoder.outputFormatting = [.sortedKeys]
return try! encoder.encode(self)
}
public var encodedString: String {
String(data: encoded, encoding: .utf8)!
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ class WalletConnectAppShowModule {
)
let walletConnectWorkerViewModel = WalletConnectAppShowViewModel(service: walletConnectWorkerService)

let viewController = WalletConnectAppShowView(viewModel: walletConnectWorkerViewModel)
let viewController = WalletConnectAppShowView(
viewModel: walletConnectWorkerViewModel,
requestViewFactory: App.shared.walletConnectRequestHandler
)
viewController.parentViewController = parentViewController

return viewController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class WalletConnectAppShowView {
private let timeOut = 5

private let viewModel: WalletConnectAppShowViewModel
private let requestViewFactory: IWalletConnectRequestViewFactory

private var cancellables = Set<AnyCancellable>()
private var timerCancellable: AnyCancellable?
private var isWaitingHandlerCancellable: AnyCancellable?
Expand All @@ -16,8 +18,9 @@ class WalletConnectAppShowView {

weak var parentViewController: UIViewController?

init(viewModel: WalletConnectAppShowViewModel) {
init(viewModel: WalletConnectAppShowViewModel, requestViewFactory: IWalletConnectRequestViewFactory) {
self.viewModel = viewModel
self.requestViewFactory = requestViewFactory

viewModel.showSessionRequestPublisher
.receive(on: DispatchQueue.main)
Expand Down Expand Up @@ -86,11 +89,16 @@ class WalletConnectAppShowView {
}

private func handle(request: WalletConnectRequest) {
guard let viewController = WalletConnectRequestModule.viewController(signService: App.shared.walletConnectSessionManager.service, request: request) else {
let result = requestViewFactory.viewController(request: request)
switch result {
case let .unsuccessful(error):
print("Can't create view")
return
case let .controller(controller):
guard let controller else { return }
let navigationController = ThemeNavigationController(rootViewController: controller)
parentViewController?.visibleController.present(navigationController, animated: true)
}

parentViewController?.visibleController.present(ThemeNavigationController(rootViewController: viewController), animated: true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ extension RestorePassphraseService {
}
switch rawBackup.account.type {
case .cex:
appBackupProvider.restore(raws: [rawBackup])
return .success
default:
return .restoredAccount(rawBackup)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Combine
import RxRelay
import RxSwift
import ThemeKit
import WalletConnectV1


class MainSettingsService {
private let disposeBag = DisposeBag()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import RxCocoa
import RxRelay
import RxSwift
import ThemeKit
import WalletConnectV1

class MainSettingsViewModel {
private let service: MainSettingsService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class WalletConnectMainPendingRequestService {

private let accountManager: AccountManager
private let sessionManager: WalletConnectSessionManager
private let requestHandler: IWalletConnectRequestHandler

private let evmBlockchainManager: EvmBlockchainManager
private let signService: IWalletConnectSignService
private var session: WalletConnectSign.Session?
Expand All @@ -21,9 +23,10 @@ class WalletConnectMainPendingRequestService {

private let showPendingRequestRelay = PublishRelay<WalletConnectRequest>()

init(service: WalletConnectMainService, accountManager: AccountManager, sessionManager: WalletConnectSessionManager, evmBlockchainManager: EvmBlockchainManager, signService: IWalletConnectSignService) {
init(service: WalletConnectMainService, accountManager: AccountManager, sessionManager: WalletConnectSessionManager, requestHandler: IWalletConnectRequestHandler, evmBlockchainManager: EvmBlockchainManager, signService: IWalletConnectSignService) {
self.accountManager = accountManager
self.sessionManager = sessionManager
self.requestHandler = requestHandler
self.evmBlockchainManager = evmBlockchainManager
self.signService = signService
session = service.session
Expand Down Expand Up @@ -85,25 +88,18 @@ extension WalletConnectMainPendingRequestService {
guard let request = sessionManager.pendingRequests().first(where: { $0.id.intValue == requestId }) else {
return
}
let session = sessionManager.sessions.first { $0.topic == request.topic }

guard let chainId = Int(request.chainId.reference),
let blockchain = evmBlockchainManager.blockchain(chainId: chainId),
let account = accountManager.activeAccount,
let address = try? WalletConnectManager.evmAddress(
account: account,
chain: evmBlockchainManager.chain(blockchainType: blockchain.type)
) else {
guard let session = sessionManager.sessions.first(where: { $0.topic == request.topic }) else {
return
}

let chain = WalletConnectRequest.Chain(id: chainId, chainName: blockchain.name, address: address.eip55)

guard let wcRequest = try? WalletConnectRequestMapper.map(dAppName: session?.peer.name, chain: chain, request: request) else {
return
let result = requestHandler.handle(session: session, request: request)
switch result {
case let .unsuccessful(error):
print("Cant select request because: \(error)")
case .handled: ()
case let .request(request):
showPendingRequestRelay.accept(request)
}

showPendingRequestRelay.accept(wcRequest)
}

func onReject(id: Int) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Foundation
import WalletConnectSign

class Eip155ProposalHandler {
static let namespace = "eip155"

static let supportedEvents = [
"chainChanged",
"accountsChanged",
]

private let evmBlockchainManager: EvmBlockchainManager
private let account: Account
private let supportedMethods: [String]

init(evmBlockchainManager: EvmBlockchainManager, account: Account, supportedMethods: [String]) {
self.evmBlockchainManager = evmBlockchainManager
self.account = account
self.supportedMethods = supportedMethods
}

private func blockchainSet(namespace: ProposalNamespace) -> WalletConnectMainModule.BlockchainSet {
var set = WalletConnectMainModule.BlockchainSet.empty

for blockchain in namespace.chains ?? [] {
guard let chainId = Int(blockchain.reference),
let evmBlockchain = evmBlockchainManager.blockchain(chainId: chainId) else {
// can't get blockchain by chainId, or can't parse chainId
continue
}

let chain = evmBlockchainManager.chain(blockchainType: evmBlockchain.type)

guard let address = try? WalletConnectManager.evmAddress(account: account, chain: chain) else {
// can't get address for chain
continue
}

set.items.insert(
WalletConnectMainModule.BlockchainItem(
namespace: blockchain.namespace,
chainId: chainId,
blockchain: evmBlockchain,
address: address.eip55
)
)
}

namespace.methods.forEach {
if supportedMethods.contains($0) {
set.methods.insert($0)
}
}

namespace.events.forEach {
if Self.supportedEvents.contains($0) {
set.events.insert($0)
}
}

return set
}
}

extension Eip155ProposalHandler: IProposalHandler {
func handle(provider: INamespaceProvider) -> WalletConnectMainModule.BlockchainSet {
var set = WalletConnectMainModule.BlockchainSet.empty

provider.get(namespace: Self.namespace).forEach { namespace in
set.formUnion(blockchainSet(namespace: namespace))
}

return set
}
}
Loading

0 comments on commit 27a4e30

Please sign in to comment.