Skip to content

Commit

Permalink
Merge pull request #217 from WalletConnect/#216-Update-readme
Browse files Browse the repository at this point in the history
update readme, update Concurrency
  • Loading branch information
llbartekll authored May 19, 2022
2 parents 240334d + ee955b4 commit f6dfa0c
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 89 deletions.
64 changes: 1 addition & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,13 @@ Swift implementation of WalletConnect v.2 protocol for native iOS applications.
- XCode 13
- Swift 5

## Documentation
## Documentation & Usage
- In order to build API documentation in XCode go to Product -> Build Documentation
- [Getting started with wallet integration](https://docs.walletconnect.com/2.0/quick-start/wallets/swift)
- [Beginner guide to WalletConnect v2.0 for iOS Developers](https://medium.com/walletconnect/beginner-guide-to-walletconnect-v2-0-for-swift-developers-4534b0975218)
- [Protocol Documentation](https://docs.walletconnect.com/2.0/protocol/client-communication)
- [Glossary](https://docs.walletconnect.com/2.0/protocol/glossary)

## Usage
### Responder
Responder client is usually a wallet.
##### Instantiate a Client
You usually want to have a single instance of a client in you app.
```Swift
let metadata = AppMetadata(name: String?,
description: String?,
url: String?,
icons: [String]?)
let client = AuthClient(metadata: AppMetadata,
projectId: String,
relayHost: String)
```

After instantiation of a client set its delegate.
#### Pair Clients
Pair client with a uri generated by the `proposer` client.
```Swift
let uri = "wc:..."
try! client.pair(uri: uri)
```
#### Approve Session
Sessions are always proposed by the `Proposer` client so `Responder` client needs either reject or approve a session proposal.
```Swift
class ClientDelegate: AuthClientDelegate {
...
func didReceive(sessionProposal: Session.Proposal) {
client.approve(proposal: proposal, accounts: [String])
}
...
```
or
```Swift
func didReceive(sessionProposal: Session.Proposal) {
client.reject(proposal: proposal, reason: Reason)
}
```
NOTE: addresses provided in `accounts` array should follow [CAPI10](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md) semantics.
#### Handle Delegate methods
```Swift
func didReceive(sessionProposal: Session.Proposal) {
// handle session proposal
}
func didReceive(sessionRequest: Request) {
// handle session request
}
```
#### JSON-RPC Payloads
#### Receive
You can parse JSON-RPC Requests received from "Requester" in `didReceive(sessionRequest: Request)` delegate function.

Request parameters can be type casted based on request method as below:
```Swift
let params = try! sessionRequest.request.params.get([EthSendTransaction].self)
```
##### Respond

```Swift
let jsonrpcResponse = JSONRPCResponse<AnyCodable>(id: request.id, result: AnyCodable(responseParams))
client.respond(topic: sessionRequest.topic, response: .response(jsonrpcResponse))
```

## Installation
### Swift Package Manager
Expand Down
8 changes: 4 additions & 4 deletions Sources/WalletConnectAuth/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -176,18 +176,18 @@ public final class AuthClient {
/// - Parameters:
/// - topic: Topic of the session that is intended to be updated.
/// - methods: Sets of methods that will replace existing ones.
public func update(topic: String, namespaces: [String: SessionNamespace]) throws {
try controllerSessionStateMachine.update(topic: topic, namespaces: namespaces)
public func update(topic: String, namespaces: [String: SessionNamespace]) async throws {
try await controllerSessionStateMachine.update(topic: topic, namespaces: namespaces)
}

/// For controller to update expiry of a session
/// - Parameters:
/// - topic: Topic of the Session, it can be a pairing or a session topic.
/// - ttl: Time in seconds that a target session is expected to be extended for. Must be greater than current time to expire and than 7 days
public func extend(topic: String) throws {
public func extend(topic: String) async throws {
let ttl: Int64 = Session.defaultTimeToLive
if sessionEngine.hasSession(for: topic) {
try controllerSessionStateMachine.extend(topic: topic, by: ttl)
try await controllerSessionStateMachine.extend(topic: topic, by: ttl)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,23 @@ final class ControllerSessionStateMachine: SessionStateMachineValidating {
}

// TODO: Change to new namespace spec
func update(topic: String, namespaces: [String: SessionNamespace]) throws {
func update(topic: String, namespaces: [String: SessionNamespace]) async throws {
var session = try getSession(for: topic)
try validateControlledAcknowledged(session)
try Validator.validate(namespaces)
logger.debug("Controller will update methods")
session.updateNamespaces(namespaces)
sessionStore.setSession(session)
networkingInteractor.request(.wcSessionUpdate(SessionType.UpdateParams(namespaces: namespaces)), onTopic: topic)
try await networkingInteractor.request(.wcSessionUpdate(SessionType.UpdateParams(namespaces: namespaces)), onTopic: topic)
}

func extend(topic: String, by ttl: Int64) throws {
func extend(topic: String, by ttl: Int64) async throws {
var session = try getSession(for: topic)
try validateControlledAcknowledged(session)
try session.updateExpiry(by: ttl)
let newExpiry = Int64(session.expiryDate.timeIntervalSince1970 )
sessionStore.setSession(session)
networkingInteractor.request(.wcSessionExtend(SessionType.UpdateExpiryParams(expiry: newExpiry)), onTopic: topic)
try await networkingInteractor.request(.wcSessionExtend(SessionType.UpdateExpiryParams(expiry: newExpiry)), onTopic: topic)
}

// MARK: - Handle Response
Expand Down
13 changes: 13 additions & 0 deletions Tests/TestingUtils/XCTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,17 @@ extension XCTest {
errorHandler(error)
}
}

public func XCTAssertNoThrowAsync<T: Sendable>(
_ expression: @autoclosure () async throws -> T,
_ message: @autoclosure () -> String = "",
file: StaticString = #filePath,
line: UInt = #line
) async {
do {
_ = try await expression()
} catch {
XCTFail(message(), file: file, line: line)
}
}
}
32 changes: 16 additions & 16 deletions Tests/WalletConnectTests/ControllerSessionStateMachineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ class ControllerSessionStateMachineTests: XCTestCase {
// XCTAssertEqual(namespacesToUpdate, updatedSession?.namespaces)
// }

func testUpdateNamespacesErrorSessionNotFound() {
XCTAssertThrowsError(try sut.update(topic: "", namespaces: SessionNamespace.stubDictionary())) { error in
func testUpdateNamespacesErrorSessionNotFound() async {
await XCTAssertThrowsErrorAsync( try await sut.update(topic: "", namespaces: SessionNamespace.stubDictionary())) { error in
XCTAssertTrue(error.isNoSessionMatchingTopicError)
}
}

func testUpdateNamespacesErrorSessionNotAcknowledged() {
func testUpdateNamespacesErrorSessionNotAcknowledged() async {
let session = WCSession.stub(acknowledged: false)
storageMock.setSession(session)
XCTAssertThrowsError(try sut.update(topic: session.topic, namespaces: SessionNamespace.stubDictionary())) { error in
await XCTAssertThrowsErrorAsync( try await sut.update(topic: session.topic, namespaces: SessionNamespace.stubDictionary())) { error in
XCTAssertTrue(error.isSessionNotAcknowledgedError)
}
}
Expand All @@ -60,55 +60,55 @@ class ControllerSessionStateMachineTests: XCTestCase {
// }
// }

func testUpdateNamespacesErrorCalledByNonController() {
func testUpdateNamespacesErrorCalledByNonController() async {
let session = WCSession.stub(isSelfController: false)
storageMock.setSession(session)
XCTAssertThrowsError(try sut.update(topic: session.topic, namespaces: SessionNamespace.stubDictionary())) { error in
await XCTAssertThrowsErrorAsync( try await sut.update(topic: session.topic, namespaces: SessionNamespace.stubDictionary())) { error in
XCTAssertTrue(error.isUnauthorizedNonControllerCallError)
}
}

// MARK: - Update Expiry

func testUpdateExpirySuccess() {
func testUpdateExpirySuccess() async {
let tomorrow = TimeTraveler.dateByAdding(days: 1)
let session = WCSession.stub(isSelfController: true, expiryDate: tomorrow)
storageMock.setSession(session)
let twoDays = 2*Time.day
XCTAssertNoThrow(try sut.extend(topic: session.topic, by: Int64(twoDays)))
await XCTAssertNoThrowAsync(try await sut.extend(topic: session.topic, by: Int64(twoDays)))
let extendedSession = storageMock.getAcknowledgedSessions().first{$0.topic == session.topic}!
XCTAssertEqual(extendedSession.expiryDate.timeIntervalSinceReferenceDate, TimeTraveler.dateByAdding(days: 2).timeIntervalSinceReferenceDate, accuracy: 1)
}

func testUpdateExpirySessionNotSettled() {
func testUpdateExpirySessionNotSettled() async {
let tomorrow = TimeTraveler.dateByAdding(days: 1)
let session = WCSession.stub(isSelfController: false, expiryDate: tomorrow, acknowledged: false)
storageMock.setSession(session)
let twoDays = 2*Time.day
XCTAssertThrowsError(try sut.extend(topic: session.topic, by: Int64(twoDays)))
await XCTAssertThrowsErrorAsync(try await sut.extend(topic: session.topic, by: Int64(twoDays)))
}

func testUpdateExpiryOnNonControllerClient() {
func testUpdateExpiryOnNonControllerClient() async {
let tomorrow = TimeTraveler.dateByAdding(days: 1)
let session = WCSession.stub(isSelfController: false, expiryDate: tomorrow)
storageMock.setSession(session)
let twoDays = 2*Time.day
XCTAssertThrowsError(try sut.extend(topic: session.topic, by: Int64(twoDays)))
await XCTAssertThrowsErrorAsync( try await sut.extend(topic: session.topic, by: Int64(twoDays)))
}

func testUpdateExpiryTtlTooHigh() {
func testUpdateExpiryTtlTooHigh() async {
let tomorrow = TimeTraveler.dateByAdding(days: 1)
let session = WCSession.stub(isSelfController: true, expiryDate: tomorrow)
storageMock.setSession(session)
let tenDays = 10*Time.day
XCTAssertThrowsError(try sut.extend(topic: session.topic, by: Int64(tenDays)))
await XCTAssertThrowsErrorAsync( try await sut.extend(topic: session.topic, by: Int64(tenDays)))
}

func testUpdateExpiryTtlTooLow() {
func testUpdateExpiryTtlTooLow() async {
let dayAfterTommorow = TimeTraveler.dateByAdding(days: 2)
let session = WCSession.stub(isSelfController: true, expiryDate: dayAfterTommorow)
storageMock.setSession(session)
let oneDay = Int64(1*Time.day)
XCTAssertThrowsError(try sut.extend(topic: session.topic, by: oneDay))
await XCTAssertThrowsErrorAsync( try await sut.extend(topic: session.topic, by: oneDay))
}
}
3 changes: 1 addition & 2 deletions Tests/WalletConnectTests/PairEngineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,8 @@ final class PairEngineTests: XCTestCase {
func testPairMultipleTimesOnSameURIThrows() async {
let uri = WalletConnectURI.stub()
for i in 1...10 {
usleep(100)
if i == 1 {
XCTAssertNoThrow(Task{try await engine.pair(uri)})
await XCTAssertNoThrowAsync(try await engine.pair(uri))
} else {
await XCTAssertThrowsErrorAsync(try await engine.pair(uri))
}
Expand Down

0 comments on commit f6dfa0c

Please sign in to comment.