Beginner’s Guide to WalletConnect v2.0 for iOS Developers

Bartek
WalletConnect
Published in
6 min readDec 23, 2021

Note: If you are a wallet developer and looking to integrate WalletConnect, please use the latest version of our tooling — the Web3Wallet SDK. For more information, you can refer to our docs.

WalletConnect is an open protocol designed to allow secure peer-to-peer communication between dapps and wallets. Clients can live on one or two separate devices and exchange messages through JSON-RPC methods defined by the protocol.

WalletConnect requests are transported over the Waku gossip network, which relays all the messages exchanged by the clients in the ecosystem. First, clients exchange keys with the Diffie-Hellman protocol to provide end-to-end encryption. Later, symmetrically encrypted messages are sent together with matching HMAC codes to grant message authenticity, and data integrity.

If you are not familiar with those concepts, you can think of HMACs as seals on envelopes. You trust the letter in the envelope has not been modified until the seal is broken or doesn’t match the sender. The image below should give you a grasp of what a Diffie-Hellman key exchange is:

Swift Client

In a common WalletConnect communication you can distinguish two different types of clients.

  1. The proposer client which generates the pairing uri and usually presents it in a form of a QR code. This client will propose a session and set itself as a non-controller client later — usually a dapp.
  2. The responder client which scans the QR code and approves the pairing and sessions.

The Swift client can act as a proposer client as well as a responder, but for the majority of cases you want your client to be a part of your wallet and that is the responder behaviour. The wallet client must also be a controller, which means the peer that controls communication permissions for allowed chains, notification types and JSON-RPC request methods. Vulnerability from malicious actions and unreliable peers is limited when the wallet is a controller.

Let’s initialise a Swift WalletConnect client instance:

let client = WalletConnectClient(metadata: <AppMetadata>, projectId: <String?>, isController: <Bool>, relayHost: <String>, keyValueStorage: <KeyValueStorage>, clientName: <String?>)
  1. AppMetadata — describes your application and will define pairing appearance in a web browser.
  2. projectId- is an optional parameter used to access the public WalletConnect infrastructure. Go to walletconnect.com for info.
  3. isController — as mentioned above, if you are developing a wallet you want your client to control permissions.
  4. relayHost — you want to connect to Waku network with some proxy server, if you are not planning to set up your own infrastructure you can use our relay.walletconnect.com relay. Our devops team has spent a lot of time giving it a Waku on steroids experience and I am sure you should give it a try.
  5. keyValueStorage — by default WalletConnect SDK will store pairing and sessions in UserDefaults but if for some reasons you want to provide your own storage you can inject it here.
  6. clientName — if your app requires more than one client you can call them with different names to distinguish logs source and prefix storage keys.

After the client is initialized you want to set its delegate and keep track of incoming events. What is also important to note, you usually want to have a single instance of a client when developing a wallet. The reason why WalletConnect client is not enforced to be a singleton is that there are special use cases where the app requires more than one instance. But if it is not the case for your app, instantiate a single client and let it live as long as your app lives.

Pair the clients

You probably started wondering what a pairing is. So, this is a special type of sequence that allows you to keep encrypted communication between a web browser and a wallet. You will use it to establish sessions for further communication between dapps and your wallet. What is cool about pairing is that it can be shared between applications in a browser so users don’t have to scan QR code over and over again. Instead, they will initiate new sessions with just a single button tap. If you had an experience with WalletConnect v1.0 I am sure you feel this is an enormous UX improvement.

Ok, so we already have our client instance, and we know what a pairing is. So let’s establish one. First you need a pairing uri which the dapp can generate and display as a QR code. It contains necessary information required to initialise communication like the proposer public key or topic by which your client will know where to publish and subscribe for events of your interest.

once you have a pairing URI you can call:

client.pair(uri: <String>)

under the hood, clients will agree on crypto keys and settle the pairing. The pairing will live for 30 days by default and will expire after on both peers. Keep in mind that even though pairing has an important role you do not necessarily need to list active pairings to the user as they will be more interested in sessions.

Establish a Session

Optimistically after clients settle the pairing, the dapp will propose a session with some permissions. Permissions will contain allowed blockchains and methods that later the dapp will be allowed to request. The user will either approve the session proposal (with allowed accounts) or reject it. Note that accounts should be provided according to CAIP10 specification and be prefixed with a chain identifier. `chain_id + “:” + account_address. You can find more on blockchain identifiers in CAIP2.

clientDelegate.onSessionProposal = { proposal in ...}client.approve(proposal: <SessionProposal>, accounts: <Set<String>>, completion: <(Result<Session, Error>) -> ()>)

Secure communication channels for sending payloads between wallets and dapps is ensured through sessions. In WalletConnect v2.0 protocol there is a significant improvement in session management. Each session has defined TTL (Time To Live) whose main purpose is to eliminate scenarios where one of the clients is not communicating the session deletion and its peer keeps the session alive. By default sessions will live for a week and then expire.

Talk to your peer

We already have a pairing and a session so we can begin talking with our peer. WalletConnect protocol has a special method for doing this: wc_sessionPayload. You may be thinking that usually a dapp will be performing session payload requests… and you are right, the dapp will usually request the wallet for transactions or messages to sign but it is not defined by the protocol itself so, if you have some genius idea how your app could talk to others over WalletConnect you are welcomed to put it into a practice.

You will be notified about incoming session requests in a delegate method:

func didReceive(sessionRequest: SessionRequest) {}

and one can simply respond for a request with either result or an error:

client.respond(topic: <String>, response: <JsonRpcResponseTypes>)

There are a lot of JSON RPC methods used by the Ethereum community already and there is more to be introduced not only to Ethereum but to other blockchains as well. We wanted the WalletConnect to be chain agnostic and allow wallet holders to sign transactions for any chain, but we also wanted WalletConnect to stay adjustable for future methods that can either be proposed by the community or be just your project’s specific idea. In order to allow it in the WalletConnect v. 2.0 protocol Swift implementation, we’ve introduced an AnyCodable type. You can wrap any type in it and send it over the network. When the request or response is received, the expected type can be easily derived from parameters or a result:

sessionRequest.params.get(<eth_signTypedData>.self)

What’s next?

It is important to mention that our SDK is still in its beta phase, but I am sure you might be interested to experiment with an integration with your project already. To learn more about the protocol check out our documentation, github and join our discord server to be a part of our community.

--

--