Integrate with WalletConnect
How to integrate the Venly Wallet API with WalletConnect and build your own wallet that is compatible with every Dapp
WalletConnect is an open-source protocol designed to provide users with a secure way to link their cryptocurrency wallets to DApp websites. This technology enables seamless, direct peer-to-peer interactions between a user's wallet and a DApp, eliminating the need for intermediaries or browser extensions.
Venly's Wallet API enhances this experience by bridging the gap between WalletConnect and DApp websites. This integration allows for efficient interaction with blockchain assets and operations, ensuring a smooth and secure connection for users engaging with decentralized applications.
This guide is intended for wallet app developers looking to implement WalletConnect.
Getting Started
The quickest way to get started is by cloning the repo for our example wallet app (Nextjs/React) and running it locally.
You can test your integration by using it in conjunction with the WalletConnect demo dapp.
Head over to WalletConnect Cloud to sign in or sign up. Create your project and copy its associated Project ID. We will need this in a later step.
Install the Web3Wallet SDK package.
npm install @walletconnect/web3wallet
Initialization
Create a new instance of Core
and initialize it with the Project ID created earlier. Next, create a web3Wallet
instance while passing a metadata
object containing metadata about your app.
import { Core } from '@walletconnect/core'
import { Web3Wallet } from '@walletconnect/web3wallet'
let core, web3wallet
core = new Core({
projectId: process.env.PROJECT_ID
})
web3wallet = await Web3Wallet.init({
core,
metadata: {
name: 'Venly Demo',
description: 'Venly WalletConnect Demo App',
url: 'https://walletconnect.venly.io',
icons: ['https://storage.venly.io/brand/icon-gradient-background.png']
}
})
Pairing
await web3wallet.core.pairing.pair({ uri })
The connection between a dapp and your wallet is established using a pairing URI which can be obtained through one of two ways:
- Passed as a URL parameter when your wallet is opened by the Web3Modal ex.
?uri=...
- Copy/pasted into your wallet app
You can test the pairing flow with the WalletConnect demo dapp. Use the copy icon on the top-right of the Web3Modal to copy the pairing URI.
Events
Once the pairing has been established, the dapp is then able to send requests to your wallet which can be approved/rejected by the user.
Typically, dapps will follow one of two flows:
- A session proposal followed by one or more session requests. This is used when the dapp needs the user to perform specific actions, such as sending a transaction or signing a message.
- A single auth request used to authenticate the user. This is done by requesting a signed message.
While this guide only covers essential events, you can find more detailed information about all the different event types on the WalletConnect documentation.
Session Proposal
The session_proposal
event is emitted when a dapp initiates a new session with a user's wallet. The event will include a proposal
object with information about the dapp and requested permissions.
You will want to display a dialog for the user to select their desired wallets and approve or reject the session.
web3wallet.on('session_proposal', (event) => {
// Show session proposal dialog
})
Approve Session
To approve the session, call approveSession
and pass in the proposal.id
and approved namespaces
. Your namespaces
will depend on the user’s selected wallets and respective chains.
See the example wallet app for details on how to build the namespaces
object using the buildApprovedNamespaces
helper function.
import { buildApprovedNamespaces } from "@walletconnect/utils"
const { id, params } = event
const supportedNamespaces = {
// accounts: ...
// chains: ...
events: ['chainChanged', 'accountsChanged'],
methods: ['eth_sendTransaction', 'personal_sign', 'eth_sign', 'eth_signTransaction', 'eth_signTypedData']
}
const approvedNamespaces = buildApprovedNamespaces({
proposal: params,
supportedNamespaces,
})
await web3wallet.approveSession({
id: proposal.id,
namespaces
})
Reject Session
To reject the session proposal, call the rejectSession
method. The getSdkError
function comes from @walletconnect/utils
.
import { getSdkError} from "@walletconnect/utils"
await web3wallet.rejectSession({
id: proposal.id,
reason: getSdkError('USER_REJECTED_METHODS')
})
Disconnect Session
If the dapp decides to disconnect the session, the session_delete
event will be emitted. Your app should listen for this event in order to update the UI.
You can use the getActiveSessions
function to get an updated list of active session pairings.
web3wallet.on('session_delete', (event) => {
// Update UI with web3wallet.getActiveSessions()
})
To disconnect a session from your wallet, call the disconnectSession
function and pass in the topic
and reason.
await web3wallet.disconnectSession({
topic,
reason: getSdkError('USER_DISCONNECTED')
})
Session Request
The session_request
event is triggered by a dapp when it needs the wallet to perform a specific action, such as signing a message. The event contains a request
object which will vary depending on the method requested.
To see a list of possible methods, you can refer to the relevant WalletConnect documentation.
web3wallet.on('session_request', (event) => {
// Show session request dialog
})
Example: Sign Message
For example if the dapp asks for a signed message by requesting the personal_sign
method, you will need to implement the logic for signing the message and then call respondSessionRequest
with the resulting signature.
const { topic, params, id } = event
const [message, walletAddress] = params.request.params
// Find specified wallet and use it to sign the message
const wallet = EXAMPLE.findWallet(walletAddress)
const signature = EXAMPLE.signMessage(wallet, message)
const response = { id, jsonrpc: '2.0', result: signature }
await web3wallet.respondSessionRequest({ topic, response })
Refer to the example wallet app for examples of other methods.
Auth Request
The auth_request
event is emitted when there is a request for authentication from a dapp. Your wallet should respond to this request by signing the provided message and returning the resulting signature. If a user has multiple wallets, you should allow them to select which one they want to authenticate with.
const { id, params } = event
const iss = `did:pkh:eip155:1:${wallet.address}`
const message = web3wallet.formatMessage(params.cacaoPayload, iss)
const signature = EXAMPLE.signMessage(wallet, message)
await web3wallet.respondAuthRequest(
{
id,
signature: {
s: signature,
t: 'eip191'
}
},
iss
)
You can also reject the auth_request by providing an error object instead.
const iss = `did:pkh:eip155:1:${wallet.address}`
await web3wallet.respondAuthRequest(
{
id: event.id,
error: getSdkError('USER_REJECTED')
},
iss
)
Final Step
The last step to complete your integration is to submit your app for approval on the WalletConnect Cloud Explorer. Make sure to follow the Explorer Guidelines to ensure your app meets all the necessary criteria.
Updated 6 months ago