Interfaces for interacting with wallets along with implementations for Browser Wallet and WalletConnect (v2). It’s written in TypeScript and has no dependencies to any UI framework.
The library takes away the complexity involved with interacting with both Browser Wallet and Mobile Wallets (via WalletConnect) such that dApps only need to interact with interfaces that abstract away the underlying protocol.
An object of this type represents some connection type and manages connections over the corresponding protocol.
The main method of this interface is .connect()
, which attempts to initiate a connection.
If successful, the returned promise resolves to a WalletConnection
.
Connectors usually hold a WalletConnectionDelegate
reference that they share with the application.
Relevant events pass from the connectors to the application through this delegate.
Implementations may support multiple active connections from the same connector.
A connection allows the application to interact with a wallet. The following interactions are supported:
signMessage
: Ask the wallet to sign a message and return it back to the dApp.signAndSendTransaction
: Ask the wallet to sign a transaction and submit it to a node.
The wallet is responsible for prompting its user for approval of all interactions.
A collection of generic event handlers for common events. Applications usually define a single delegate that they share between all connectors. This allows the application to handle all events from all kinds of connections in a single place.
First define a delegate MyDelegate
for keeping track of the connected account and chain for each connection:
import {
BrowserWalletConnector,
WalletConnectConnector,
WalletConnection,
WalletConnectionDelegate,
} from '@concordium/wallet-connectors';
class MyDelegate implements WalletConnectionDelegate {
accounts = new Map<WalletConnection, string | undefined>();
chains = new Map<WalletConnection, string | undefined>();
onAccountChanged = (connection: WalletConnection, address: string | undefined) => {
this.accounts.set(connection, address);
};
onChainChanged = (connection: WalletConnection, genesisHash: string) => {
this.chains.set(connection, genesisHash);
};
onConnected = (connection: WalletConnection, address: string | undefined) => {
this.onAccountChanged(connection, address);
};
onDisconnected = (connection: WalletConnection) => {
this.accounts.delete(connection);
this.chains.delete(connection);
};
}
Then write some application code that only references the connection through the generic WalletConnection
interface:
async function doSomethingInteresting(connection: WalletConnection, account: string, ...) {
...
const txHash = await connection.signAndSendTransaction(account, ...);
...
}
In the appropriate context, set up connectors for both Browser Wallet and WalletConnect
(adding appropriate values of walletConnectOpts
and network
) and open connections to both of them:
const delegate = new MyDelegate();
const browserWalletConnector = await BrowserWalletConnector.create(delegate);
const walletConnectConnector = await WalletConnectConnector.create(walletConnectOpts, delegate, network);
const browserWalletConnection = await browserWalletConnector.connect();
const walletConnectConnection = await walletConnectConnector.connect();
The current state of all connections is available in the fields of delegate
.
This is used when invoking the application function above:
doSomethingInteresting(connection, delegate.accounts.get(connection)!, ...)
where connection
is either browserWalletConnection
or walletConnectConnection
.
Use the React component WithWalletConnector
in
@concordium/react-components
to easily integrate this library into a React app.
Run
yarn
yarn build
to compile the TypeScript files into ./dist
along with type declarations and source maps.