Skip to content

Commit f7ffc79

Browse files
Merge pull request #1187 from WalletConnect/dapp-extend-session
[Sign] Dapp extend session exp
2 parents 6c7c129 + 20a5f59 commit f7ffc79

12 files changed

+216
-113
lines changed

Example/WalletApp/PresentationLayer/Wallet/ConnectionDetails/ConnectionDetailsView.swift

+40-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ import SwiftUI
22

33
struct ConnectionDetailsView: View {
44
@EnvironmentObject var presenter: ConnectionDetailsPresenter
5-
5+
6+
private var dateFormatter: DateFormatter {
7+
let formatter = DateFormatter()
8+
formatter.dateFormat = "HH:mm:ss E, d MMM y"
9+
return formatter
10+
}
11+
612
var body: some View {
713
ZStack {
814
Color.grey100
@@ -145,6 +151,39 @@ struct ConnectionDetailsView: View {
145151
.padding(.top, 30)
146152
}
147153

154+
VStack(alignment: .leading) {
155+
Text("Expiry")
156+
.font(.system(size: 15, weight: .semibold, design: .rounded))
157+
.foregroundColor(.whiteBackground)
158+
.padding(.horizontal, 8)
159+
.padding(.vertical, 5)
160+
.background(Color.grey70)
161+
.cornerRadius(28, corners: .allCorners)
162+
.padding(.leading, 15)
163+
.padding(.top, 9)
164+
165+
VStack(spacing: 0) {
166+
TagsView(items: [dateFormatter.string(from: presenter.session.expiryDate)]) {
167+
Text($0)
168+
.foregroundColor(.cyanBackround)
169+
.font(.system(size: 13, weight: .semibold, design: .rounded))
170+
.padding(.horizontal, 8)
171+
.padding(.vertical, 3)
172+
.background(Color.cyanBackround.opacity(0.2))
173+
.cornerRadius(10, corners: .allCorners)
174+
}
175+
.padding(10)
176+
}
177+
.background(Color.whiteBackground)
178+
.cornerRadius(20, corners: .allCorners)
179+
.padding(.horizontal, 5)
180+
.padding(.bottom, 5)
181+
}
182+
.background(Color("grey95"))
183+
.cornerRadius(25, corners: .allCorners)
184+
.padding(.horizontal, 20)
185+
.padding(.top, 30)
186+
148187
Button {
149188
presenter.onDelete()
150189
} label: {

Sources/WalletConnectSign/Engine/Common/SessionEngine.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ final class SessionEngine {
5050
func hasSession(for topic: String) -> Bool {
5151
return sessionStore.hasSession(forTopic: topic)
5252
}
53-
53+
5454
func getSessions() -> [Session] {
55-
sessionStore.getAll().map {$0.publicRepresentation()}
55+
sessionStore.getAll().map { $0.publicRepresentation() }
5656
}
5757

5858
func request(_ request: Request) async throws {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import Foundation
2+
import Combine
3+
4+
final class SessionExtendRequestSubscriber {
5+
var onExtend: ((String, Date) -> Void)?
6+
7+
private let sessionStore: WCSessionStorage
8+
private let networkingInteractor: NetworkInteracting
9+
private var publishers = [AnyCancellable]()
10+
private let logger: ConsoleLogging
11+
12+
init(
13+
networkingInteractor: NetworkInteracting,
14+
sessionStore: WCSessionStorage,
15+
logger: ConsoleLogging
16+
) {
17+
self.networkingInteractor = networkingInteractor
18+
self.sessionStore = sessionStore
19+
self.logger = logger
20+
21+
setupSubscriptions()
22+
}
23+
}
24+
25+
// MARK: - Private functions
26+
extension SessionExtendRequestSubscriber {
27+
private func setupSubscriptions() {
28+
networkingInteractor.requestSubscription(on: SessionExtendProtocolMethod())
29+
.sink { [unowned self] (payload: RequestSubscriptionPayload<SessionType.UpdateExpiryParams>) in
30+
onSessionUpdateExpiry(payload: payload, updateExpiryParams: payload.request)
31+
}.store(in: &publishers)
32+
}
33+
34+
private func onSessionUpdateExpiry(payload: SubscriptionPayload, updateExpiryParams: SessionType.UpdateExpiryParams) {
35+
let protocolMethod = SessionExtendProtocolMethod()
36+
let topic = payload.topic
37+
guard var session = sessionStore.getSession(forTopic: topic) else {
38+
return respondError(payload: payload, reason: .noSessionForTopic, protocolMethod: protocolMethod)
39+
}
40+
guard session.peerIsController else {
41+
return respondError(payload: payload, reason: .unauthorizedExtendRequest, protocolMethod: protocolMethod)
42+
}
43+
do {
44+
try session.updateExpiry(to: updateExpiryParams.expiry)
45+
} catch {
46+
return respondError(payload: payload, reason: .invalidExtendRequest, protocolMethod: protocolMethod)
47+
}
48+
sessionStore.setSession(session)
49+
50+
Task(priority: .high) {
51+
try await networkingInteractor.respondSuccess(topic: payload.topic, requestId: payload.id, protocolMethod: protocolMethod)
52+
}
53+
54+
onExtend?(session.topic, session.expiryDate)
55+
}
56+
57+
private func respondError(payload: SubscriptionPayload, reason: SignReasonCode, protocolMethod: ProtocolMethod) {
58+
Task(priority: .high) {
59+
do {
60+
try await networkingInteractor.respondError(topic: payload.topic, requestId: payload.id, protocolMethod: protocolMethod, reason: reason)
61+
} catch {
62+
logger.error("Respond Error failed with: \(error.localizedDescription)")
63+
}
64+
}
65+
}
66+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Foundation
2+
3+
final class SessionExtendRequester {
4+
private let sessionStore: WCSessionStorage
5+
private let networkingInteractor: NetworkInteracting
6+
7+
init(
8+
sessionStore: WCSessionStorage,
9+
networkingInteractor: NetworkInteracting
10+
) {
11+
self.sessionStore = sessionStore
12+
self.networkingInteractor = networkingInteractor
13+
}
14+
15+
func extend(topic: String, by ttl: Int64) async throws {
16+
guard var session = sessionStore.getSession(forTopic: topic) else {
17+
throw WalletConnectError.noSessionMatchingTopic(topic)
18+
}
19+
20+
let protocolMethod = SessionExtendProtocolMethod()
21+
try session.updateExpiry(by: ttl)
22+
let newExpiry = Int64(session.expiryDate.timeIntervalSince1970)
23+
sessionStore.setSession(session)
24+
let request = RPCRequest(method: protocolMethod.method, params: SessionType.UpdateExpiryParams(expiry: newExpiry))
25+
try await networkingInteractor.request(request, topic: topic, protocolMethod: protocolMethod)
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import Foundation
2+
import Combine
3+
4+
final class SessionExtendResponseSubscriber {
5+
var onExtend: ((String, Date) -> Void)?
6+
7+
private let sessionStore: WCSessionStorage
8+
private let networkingInteractor: NetworkInteracting
9+
private var publishers = [AnyCancellable]()
10+
private let logger: ConsoleLogging
11+
12+
init(
13+
networkingInteractor: NetworkInteracting,
14+
sessionStore: WCSessionStorage,
15+
logger: ConsoleLogging
16+
) {
17+
self.networkingInteractor = networkingInteractor
18+
self.sessionStore = sessionStore
19+
self.logger = logger
20+
21+
setupSubscriptions()
22+
}
23+
24+
// MARK: - Handle Response
25+
private func setupSubscriptions() {
26+
networkingInteractor.responseSubscription(on: SessionExtendProtocolMethod())
27+
.sink { [unowned self] (payload: ResponseSubscriptionPayload<SessionType.UpdateExpiryParams, RPCResult>) in
28+
handleUpdateExpiryResponse(payload: payload)
29+
}
30+
.store(in: &publishers)
31+
}
32+
33+
private func handleUpdateExpiryResponse(payload: ResponseSubscriptionPayload<SessionType.UpdateExpiryParams, RPCResult>) {
34+
guard var session = sessionStore.getSession(forTopic: payload.topic) else { return }
35+
switch payload.response {
36+
case .response:
37+
do {
38+
try session.updateExpiry(to: payload.request.expiry)
39+
sessionStore.setSession(session)
40+
onExtend?(session.topic, session.expiryDate)
41+
} catch {
42+
logger.error("Update expiry error: \(error.localizedDescription)")
43+
}
44+
case .error:
45+
logger.error("Peer failed to extend session")
46+
}
47+
}
48+
}

Sources/WalletConnectSign/Engine/Controller/ControllerSessionStateMachine.swift

-36
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ import Foundation
22
import Combine
33

44
final class ControllerSessionStateMachine {
5-
65
var onNamespacesUpdate: ((String, [String: SessionNamespace]) -> Void)?
7-
var onExtend: ((String, Date) -> Void)?
86

97
private let sessionStore: WCSessionStorage
108
private let networkingInteractor: NetworkInteracting
@@ -35,31 +33,13 @@ final class ControllerSessionStateMachine {
3533
try await networkingInteractor.request(request, topic: topic, protocolMethod: protocolMethod)
3634
}
3735

38-
func extend(topic: String, by ttl: Int64) async throws {
39-
var session = try getSession(for: topic)
40-
let protocolMethod = SessionExtendProtocolMethod()
41-
try validateController(session)
42-
try session.updateExpiry(by: ttl)
43-
let newExpiry = Int64(session.expiryDate.timeIntervalSince1970 )
44-
sessionStore.setSession(session)
45-
let request = RPCRequest(method: protocolMethod.method, params: SessionType.UpdateExpiryParams(expiry: newExpiry))
46-
try await networkingInteractor.request(request, topic: topic, protocolMethod: protocolMethod)
47-
}
48-
4936
// MARK: - Handle Response
50-
5137
private func setupSubscriptions() {
5238
networkingInteractor.responseSubscription(on: SessionUpdateProtocolMethod())
5339
.sink { [unowned self] (payload: ResponseSubscriptionPayload<SessionType.UpdateParams, RPCResult>) in
5440
handleUpdateResponse(payload: payload)
5541
}
5642
.store(in: &publishers)
57-
58-
networkingInteractor.responseSubscription(on: SessionExtendProtocolMethod())
59-
.sink { [unowned self] (payload: ResponseSubscriptionPayload<SessionType.UpdateExpiryParams, RPCResult>) in
60-
handleUpdateExpiryResponse(payload: payload)
61-
}
62-
.store(in: &publishers)
6343
}
6444

6545
private func handleUpdateResponse(payload: ResponseSubscriptionPayload<SessionType.UpdateParams, RPCResult>) {
@@ -80,22 +60,6 @@ final class ControllerSessionStateMachine {
8060
}
8161
}
8262

83-
private func handleUpdateExpiryResponse(payload: ResponseSubscriptionPayload<SessionType.UpdateExpiryParams, RPCResult>) {
84-
guard var session = sessionStore.getSession(forTopic: payload.topic) else { return }
85-
switch payload.response {
86-
case .response:
87-
do {
88-
try session.updateExpiry(to: payload.request.expiry)
89-
sessionStore.setSession(session)
90-
onExtend?(session.topic, session.expiryDate)
91-
} catch {
92-
logger.error("Update expiry error: \(error.localizedDescription)")
93-
}
94-
case .error:
95-
logger.error("Peer failed to extend session")
96-
}
97-
}
98-
9963
// MARK: - Private
10064
private func getSession(for topic: String) throws -> WCSession {
10165
if let session = sessionStore.getSession(forTopic: topic) {

Sources/WalletConnectSign/Engine/NonController/NonControllerSessionStateMachine.swift

+6-34
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ import Foundation
22
import Combine
33

44
final class NonControllerSessionStateMachine {
5-
65
var onNamespacesUpdate: ((String, [String: SessionNamespace]) -> Void)?
7-
var onExtend: ((String, Date) -> Void)?
86

97
private let sessionStore: WCSessionStorage
108
private let networkingInteractor: NetworkInteracting
119
private let kms: KeyManagementServiceProtocol
1210
private var publishers = [AnyCancellable]()
1311
private let logger: ConsoleLogging
1412

15-
init(networkingInteractor: NetworkInteracting,
16-
kms: KeyManagementServiceProtocol,
17-
sessionStore: WCSessionStorage,
18-
logger: ConsoleLogging) {
13+
init(
14+
networkingInteractor: NetworkInteracting,
15+
kms: KeyManagementServiceProtocol,
16+
sessionStore: WCSessionStorage,
17+
logger: ConsoleLogging
18+
) {
1919
self.networkingInteractor = networkingInteractor
2020
self.kms = kms
2121
self.sessionStore = sessionStore
@@ -28,11 +28,6 @@ final class NonControllerSessionStateMachine {
2828
.sink { [unowned self] (payload: RequestSubscriptionPayload<SessionType.UpdateParams>) in
2929
onSessionUpdateNamespacesRequest(payload: payload, updateParams: payload.request)
3030
}.store(in: &publishers)
31-
32-
networkingInteractor.requestSubscription(on: SessionExtendProtocolMethod())
33-
.sink { [unowned self] (payload: RequestSubscriptionPayload<SessionType.UpdateExpiryParams>) in
34-
onSessionUpdateExpiry(payload: payload, updateExpiryParams: payload.request)
35-
}.store(in: &publishers)
3631
}
3732

3833
private func respondError(payload: SubscriptionPayload, reason: SignReasonCode, protocolMethod: ProtocolMethod) {
@@ -72,27 +67,4 @@ final class NonControllerSessionStateMachine {
7267

7368
onNamespacesUpdate?(session.topic, updateParams.namespaces)
7469
}
75-
76-
private func onSessionUpdateExpiry(payload: SubscriptionPayload, updateExpiryParams: SessionType.UpdateExpiryParams) {
77-
let protocolMethod = SessionExtendProtocolMethod()
78-
let topic = payload.topic
79-
guard var session = sessionStore.getSession(forTopic: topic) else {
80-
return respondError(payload: payload, reason: .noSessionForTopic, protocolMethod: protocolMethod)
81-
}
82-
guard session.peerIsController else {
83-
return respondError(payload: payload, reason: .unauthorizedExtendRequest, protocolMethod: protocolMethod)
84-
}
85-
do {
86-
try session.updateExpiry(to: updateExpiryParams.expiry)
87-
} catch {
88-
return respondError(payload: payload, reason: .invalidExtendRequest, protocolMethod: protocolMethod)
89-
}
90-
sessionStore.setSession(session)
91-
92-
Task(priority: .high) {
93-
try await networkingInteractor.respondSuccess(topic: payload.topic, requestId: payload.id, protocolMethod: protocolMethod)
94-
}
95-
96-
onExtend?(session.topic, session.expiryDate)
97-
}
9870
}

0 commit comments

Comments
 (0)