Why do you need it?
Whether you need to connect users wallet to your application and get their address, display their assets or do transactions, etc.
There exists two most popular ways for DApp (decentralized application, just your iOS application) connection like specific wallets’ SDK and WalletConnect protocol.
WalletConnect is a highly recommended and widely compatible method for connecting your DApp to a crypto wallet. By implementing WalletConnect SDK support, you can connect with various wallets that have integrated it, such as MetaMask, Rainbow, Trust, Zerion, and many others (which includes almost all existing wallets).
There are exist two ways to connect your DApp: Sign and Auth. Description from wallet connect:
- WalletConnect Sign is a remote signer protocol to communicate securely between web3 wallets and dapps. The protocol establishes a remote pairing between two apps and/or devices using a Relay server to relay payloads. These payloads are symmetrically encrypted through a shared key between the two peers. The pairing is initiated by one peer displaying a QR Code or deep link with a standard WalletConnect URI and is established when the counter-party approves this pairing request.
- WalletConnect Auth is an authentication protocol that can be used to log-in blockchain wallets into apps. With a simple and lean interface, this API verifies wallet address ownership through a single signature request, realizing login in one action. It enables apps to set up a decentralized and passwordless onboarding flow.
The main difference between them is the pairing between a DApp and a wallet in the Sign protocol, which allows initiating transactions from the user's application. Also Auth protocol authenticate a user in one step when Sign require two separate steps (wallet connection and sign) as it always was.
Table of Contents
Installation
Add WalletConnect SDK to your app. Link to installation process is below. It may be added using SPM or CocoaPods.
https://github.com/WalletConnect/WalletConnectSwiftV2#installation
Configuration
To configure the WalletConnect SDK with your app information, you need to provide the project ID. You can register for the project ID by clicking here with your crypto wallet.
And insert it in the projectId
property in code below.
import WalletConnectNetworking
Networking.configure(
projectId: "your-project-id",
socketFactory: WalletConnectSocketFactory(),
socketConnectionType: .automatic
)
Additionally, there is a WalletConnectSocketFactory()
class that you need to implement yourself. The WalletConnect SDK does not handle socket management on its own.
The easiest way is to use Starscream SDK of 3.1.2 version which completley complies with their WebSocketConnecting
protocol. (yep, it’s not new and may have some issues but it works)
import Foundation
import WalletConnectSign
import Starscream
struct WalletConnectSocketFactory: WebSocketFactory {
func create(with url: URL) -> WebSocketConnecting {
let socket = WalletConnectStarscreamSocket(url: url)
let queue = DispatchQueue(label: "com.walletconnect.sdk.socket", attributes: .concurrent)
socket.callbackQueue = queue
return socket
}
}
class WalletConnectStarscreamSocket: WebSocket, WebSocketConnecting { }
It also possible to write your own sockets implementation using URLSessionWebSocketTask
or any other library.
And the last step is to configure your app metadata.
import WalletConnectSign
let metadata = AppMetadata(
name: "Your app name",
description: "description",
url: "your app url",
icons: ["https://icon-url.com"],
redirect: .init(native: "native-link://", universal: "universal-link.com")
)
Pair.configure(metadata: metadata)
I think it's quite straightforward. You need to provide your app name, description, URL, and icon. Additionally, you need to pass your universal link and deep link to allow wallets to redirect back to the app.
It’s important to configure the SDK before your call any methods in it!
Wallet connection
After completing all the configurations, you are ready to connect your wallet. First, define the chains and methods that your DApp requires. In example below I have defined the Ethereum chain with a chain ID of 1 ("eip155:1"
) and the "personal_sign"
method. Pass these parameters to the Sign.instance.connect()
method. For more information, refer to the WalletConnect documentation.
func connect() async throws {
let requiredNamespaces: [String: ProposalNamespace] = [
"eip155": ProposalNamespace(
chains: [
Blockchain("eip155:1")!
],
methods: [
"personal_sign"
], events: []
)
]
do {
let pairUri = try await Pair.instance.create()
try await Sign.instance.connect(requiredNamespaces: requiredNamespaces,
// metamask doesn't handle a request without these dummy values
optionalNamespaces: [:],
topic: pairUri.topic)
} catch {
throw error
}
}
Note: here is defined optionalNamespaces
and sessionProperties
which are optional but MetaMask iOS wallet has an issue that requires passing dummy values in order to handle this request.
Also save pairUri
cause it will be required in the next step.
To redirect a user to a wallet app, you need to pass the pairUri
as a parameter in the wallet link, as shown in the example below.
The wc/
path and uri
parameter are standard for all wallets that support the WCv2 protocol. In this case, we are using the pairUri
that was saved in the previous step, along with the Metamask deep link.
func redirectToWallet() {
guard let deeplinkUrl = pairUri?.deeplinkUri,
let url = URL(string: "metamask://wc?uri=\(deeplinkUrl)") else { return }
UIApplication.shared.open(url)
}
After that, the user will be redirected to MetaMask, where the connection request will appear. The response will be received in the Sign.instance.sessionSettlePublisher
observer.
var publishers = Set<AnyCancellable>()
Sign.instance.sessionSettlePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] session in
let account = session.accounts.first
self?.sessionTopic = session.topic
self?.address = account?.address
}.store(in: &publishers)
If the request is successful, this observer will be triggered. It provides two main properties: wallet address and session topic. The session topic will be required in the next step to retrieve the session and send a Sign request.
Sign request
Next, you need to create a sign request and send it to the established session. Do not confuse the pairing topic with the session topic.
func sign() async {
guard let chain = Blockchain("eip155:1"),
let address, // previously saved
let topic = sessionTopic else { return } // previously saved
let method = "personal_sign"
let requestParams = AnyCodable(["Verefication message", address])
let request = Request(topic: topic,
method: method,
params: requestParams,
chainId: chain)
try? await Sign.instance.request(params: request)
}
And session response will be in Sign.instance.sessionResponsePublisher
observer.
var publishers = Set<AnyCancellable>()
Sign.instance.sessionResponsePublisher
.receive(on: DispatchQueue.main)
.sink { response in
switch response.result {
case .response:
print("Success")
case .error(let error):
print(error)
}
}.store(in: &publishers)
In this straightforward example we don’t parse response but It may be important if you pass many different request.
That's it! You’ve successfully authorized user’s wallet, have its address and can continue. You can skip step with requesting sign from user’s wallet but you won’t be sure if user really own this wallet.
Good luck! Fell free to contact me and leave your feedback.
Follow me on X/Twitter
Top comments (1)
Connecting a crypto wallet to an iOS Swift app can be quite straightforward if you follow the right steps. First, you'll want to choose a wallet that supports iOS, like MetaMask or Trust Wallet, and familiarize yourself with their SDKs. Integrating these wallets usually involves using a library that allows you to authenticate and send transactions securely. Also, don’t overlook the importance of ensuring that your app handles user data securely, as crypto transactions can be sensitive. For anyone interested in managing their crypto alongside traditional finance, I recommend exploring modern digital wallets like NonBank(nonbank.io/). It’s a comprehensive financial management solution that combines custodial and non-custodial features, letting you manage all your assets seamlessly. NonBank integrates banks, wallets, and exchanges in one platform, simplifying your financial life.