Skip to content

Commit 80ac694

Browse files
Upgrade wallet connect (#135)
upgrade wallet connect
1 parent e745e01 commit 80ac694

File tree

7 files changed

+411
-359
lines changed

7 files changed

+411
-359
lines changed

examples/react-headless/src/components/App.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { useState } from 'react';
1111
const APP_NAME = 'Polkadot Demo';
1212

1313
const App = () => {
14-
let injectedWalletProvider = new InjectedWalletProvider(extensionConfig, APP_NAME);
15-
let walletConnectParams: WalletConnectConfiguration = {
14+
const injectedWalletProvider = new InjectedWalletProvider(extensionConfig, APP_NAME);
15+
const walletConnectParams: WalletConnectConfiguration = {
1616
projectId: '4fae85e642724ee66587fa9f37b997e2',
1717
relayUrl: 'wss://relay.walletconnect.com',
1818
metadata: {
@@ -22,10 +22,16 @@ const App = () => {
2222
icons: ['https://walletconnect.com/walletconnect-logo.png'],
2323
},
2424
chainIds: ['polkadot:e143f23803ac50e8f6f8e62695d1ce9e', 'polkadot:91b171bb158e2d3848fa23a9f1c25182'],
25+
optionalChainIds: ['polkadot:67f9723393ef76214df0118c34bbbd3d', 'polkadot:7c34d42fc815d392057c78b49f2755c7'],
26+
onSessionDelete: () => {
27+
// do something when session is removed
28+
}
2529
};
26-
let walletConnectProvider = new WalletConnectProvider(walletConnectParams, APP_NAME);
27-
let walletAggregator = new WalletAggregator([injectedWalletProvider, walletConnectProvider]);
28-
let [showWallets, setShowWallets] = useState(false);
30+
31+
const walletConnectProvider = new WalletConnectProvider(walletConnectParams, APP_NAME);
32+
const walletAggregator = new WalletAggregator([injectedWalletProvider, walletConnectProvider]);
33+
const [showWallets, setShowWallets] = useState(false);
34+
2935
return (
3036
<PolkadotWalletsContextProvider walletAggregator={walletAggregator}>
3137
<button

examples/react-next/components/ConnectContainer.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ const ConnectContainer = () => {
2323
icons: ['/images/wallet-connect.svg'],
2424
},
2525
chainIds: ['polkadot:e143f23803ac50e8f6f8e62695d1ce9e', 'polkadot:91b171bb158e2d3848fa23a9f1c25182'],
26+
optionalChainIds: ['polkadot:67f9723393ef76214df0118c34bbbd3d', 'polkadot:7c34d42fc815d392057c78b49f2755c7'],
27+
onSessionDelete: () => {
28+
// do something when session is removed
29+
}
2630
};
2731
let walletConnectProvider = new WalletConnectProvider(walletConnectParams, APP_NAME);
2832
let walletAggregator = new WalletAggregator([injectedWalletProvider, walletConnectProvider]);

packages/wallet-connect/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
},
2626
"dependencies": {
2727
"@polkadot-onboard/core": "0.1.0",
28-
"@walletconnect/qrcode-modal": "1.8.0",
29-
"@walletconnect/sign-client": "2.9.1"
28+
"@walletconnect/modal": "2.6.1",
29+
"@walletconnect/sign-client": "2.9.2"
3030
},
3131
"devDependencies": {
3232
"@polkadot/types": "10.9.1",
33-
"@walletconnect/types": "2.7.7",
33+
"@walletconnect/types": "2.9.2",
3434
"prettier": "3.0.0",
3535
"typescript": "5.1.6"
3636
}

packages/wallet-connect/src/signer.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import type { HexString } from '@polkadot/util/types';
1+
import { TypeRegistry } from '@polkadot/types';
22
import type { Signer, SignerResult } from '@polkadot/types/types';
33
import type { SignerPayloadJSON, SignerPayloadRaw } from '@polkadot/types/types';
4-
import type { SessionTypes } from '@walletconnect/types';
5-
6-
import { TypeRegistry } from '@polkadot/types';
4+
import type { HexString } from '@polkadot/util/types';
75
import SignClient from '@walletconnect/sign-client';
6+
import type { SessionTypes } from '@walletconnect/types';
87

9-
import { POLKADOT_CHAIN_ID } from './wallet-connect';
8+
import { POLKADOT_CHAIN_ID } from './wallet-connect.js';
109

1110
interface Signature {
1211
signature: HexString;
@@ -24,9 +23,8 @@ export class WalletConnectSigner implements Signer {
2423
this.registry = new TypeRegistry();
2524
}
2625

27-
// this method is set this way to be bound to this class.
2826
signPayload = async (payload: SignerPayloadJSON): Promise<SignerResult> => {
29-
let request = {
27+
const request = {
3028
topic: this.session.topic,
3129
chainId: `polkadot:${payload.genesisHash.replace('0x', '').substring(0, 32)}`,
3230
request: {
@@ -36,15 +34,14 @@ export class WalletConnectSigner implements Signer {
3634
params: { address: payload.address, transactionPayload: payload },
3735
},
3836
};
39-
let { signature } = await this.client.request<Signature>(request);
37+
38+
const { signature } = await this.client.request<Signature>(request);
39+
4040
return { id: ++this.id, signature };
4141
};
4242

43-
// this method is set this way to be bound to this class.
44-
// It might be used outside of the object context to sign messages.
45-
// ref: https://polkadot.js.org/docs/extension/cookbook#sign-a-message
4643
signRaw = async (raw: SignerPayloadRaw): Promise<SignerResult> => {
47-
let request = {
44+
const request = {
4845
topic: this.session.topic,
4946
chainId: POLKADOT_CHAIN_ID,
5047
request: {
@@ -54,7 +51,9 @@ export class WalletConnectSigner implements Signer {
5451
params: { address: raw.address, message: raw.data },
5552
},
5653
};
57-
let { signature } = await this.client.request<Signature>(request);
54+
55+
const { signature } = await this.client.request<Signature>(request);
56+
5857
return { id: ++this.id, signature };
5958
};
6059
}

packages/wallet-connect/src/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { SignClientTypes } from '@walletconnect/types';
22

33
export type WcAccount = `${string}:${string}:${string}`;
4+
45
export type PolkadotNamespaceChainId = `polkadot:${string}`;
6+
57
export interface WalletConnectConfiguration extends SignClientTypes.Options {
8+
// ToDo: Remove ```projectId``` when the following issue is resolved:
9+
// https://github.com/WalletConnect/walletconnect-monorepo/pull/3435
10+
projectId: string;
611
chainIds?: PolkadotNamespaceChainId[];
12+
optionalChainIds?: PolkadotNamespaceChainId[];
13+
onSessionDelete?: () => void;
714
}

packages/wallet-connect/src/wallet-connect.ts

Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
import type { Account, BaseWallet, BaseWalletProvider, WalletMetadata } from '@polkadot-onboard/core';
2+
import { WalletType } from '@polkadot-onboard/core';
23
import type { Signer } from '@polkadot/types/types';
4+
import { WalletConnectModal } from '@walletconnect/modal';
5+
import Client, { SignClient } from '@walletconnect/sign-client';
36
import type { SessionTypes } from '@walletconnect/types';
4-
import type { WalletConnectConfiguration, WcAccount } from './types.js';
57

6-
import { WalletType } from '@polkadot-onboard/core';
7-
import SignClient from '@walletconnect/sign-client';
8-
import QRCodeModal from '@walletconnect/qrcode-modal';
98
import { WalletConnectSigner } from './signer.js';
9+
import type { WalletConnectConfiguration, WcAccount } from './types.js';
1010

1111
export const POLKADOT_CHAIN_ID = 'polkadot:91b171bb158e2d3848fa23a9f1c25182';
1212
export const WC_VERSION = '2.0';
1313

14-
const toWalletAccount = (wcAccount: WcAccount) => {
15-
let address = wcAccount.split(':')[2];
16-
return { address };
17-
};
14+
const toWalletAccount = (wcAccount: WcAccount) => ({ address: wcAccount.split(':')[2] });
15+
16+
interface ModalState {
17+
open: boolean;
18+
}
1819

1920
class WalletConnectWallet implements BaseWallet {
2021
type = WalletType.WALLET_CONNECT;
2122
appName: string;
2223
metadata: WalletMetadata;
2324
config: WalletConnectConfiguration;
24-
client: SignClient | undefined;
25+
client: Client | undefined;
2526
signer: Signer | undefined;
2627
session: SessionTypes.Struct | undefined;
28+
walletConnectModal: WalletConnectModal;
2729

2830
constructor(config: WalletConnectConfiguration, appName: string) {
2931
if (!config.chainIds || config.chainIds.length === 0) config.chainIds = [POLKADOT_CHAIN_ID];
@@ -37,6 +39,10 @@ class WalletConnectWallet implements BaseWallet {
3739
iconUrl: config.metadata?.icons[0] || '',
3840
version: WC_VERSION,
3941
};
42+
this.walletConnectModal = new WalletConnectModal({
43+
projectId: config.projectId,
44+
chains: config.chainIds,
45+
});
4046
}
4147

4248
reset(): void {
@@ -47,50 +53,84 @@ class WalletConnectWallet implements BaseWallet {
4753

4854
async getAccounts(): Promise<Account[]> {
4955
let accounts: Account[] = [];
56+
5057
if (this.session) {
51-
let wcAccounts = Object.values(this.session.namespaces)
58+
const wcAccounts = Object.values(this.session.namespaces)
5259
.map((namespace) => namespace.accounts)
5360
.flat();
61+
5462
accounts = wcAccounts.map((wcAccount) => toWalletAccount(wcAccount as WcAccount));
5563
}
64+
5665
return accounts;
5766
}
5867

5968
async connect() {
60-
// reset the client
6169
this.reset();
6270

63-
// init the client
64-
let client = await SignClient.init(this.config);
65-
let params = {
71+
this.client = await SignClient.init(this.config);
72+
73+
this.client.on('session_delete', () => {
74+
this.reset();
75+
76+
if (this.config.onSessionDelete) {
77+
this.config.onSessionDelete();
78+
}
79+
});
80+
81+
const namespaces = {
6682
requiredNamespaces: {
6783
polkadot: {
68-
methods: ['polkadot_signTransaction', 'polkadot_signMessage'],
6984
chains: this.config.chainIds,
85+
methods: ['polkadot_signTransaction', 'polkadot_signMessage'],
86+
events: [],
87+
},
88+
},
89+
optionalNamespaces: {
90+
polkadot: {
91+
chains: this.config.optionalChainIds,
92+
methods: ['polkadot_signTransaction', 'polkadot_signMessage'],
7093
events: [],
7194
},
7295
},
7396
};
7497

75-
const { uri, approval } = await client.connect(params);
98+
const lastKeyIndex = this.client.session.getAll().length - 1;
99+
const lastSession = this.client.session.getAll()[lastKeyIndex];
100+
101+
if (lastSession) {
102+
return new Promise<void>((resolve) => {
103+
this.session = lastSession;
104+
this.signer = new WalletConnectSigner(this.client!, lastSession);
105+
resolve();
106+
});
107+
}
108+
109+
const { uri, approval } = await this.client.connect(namespaces);
110+
76111
return new Promise<void>((resolve, reject) => {
77-
// Open QRCode modal if a URI was returned (i.e. we're not connecting an existing pairing).
78112
if (uri) {
79-
QRCodeModal.open(uri, () => {
80-
reject(new Error('Canceled pairing. QR Code Modal closed.'));
81-
});
113+
this.walletConnectModal.openModal({ uri });
82114
}
83-
// Await session approval from the wallet.
115+
116+
const unsubscribeModal = this.walletConnectModal.subscribeModal((state: ModalState) => {
117+
if (state.open === false) {
118+
unsubscribeModal();
119+
resolve();
120+
}
121+
});
122+
84123
approval()
85124
.then((session) => {
86-
// setup the client
87-
this.client = client;
88125
this.session = session;
89-
this.signer = new WalletConnectSigner(client, session);
126+
this.signer = new WalletConnectSigner(this.client!, session);
127+
90128
resolve();
91129
})
92-
.catch(reject)
93-
.finally(() => QRCodeModal.close());
130+
.catch((error) => {
131+
reject(error);
132+
})
133+
.finally(() => this.walletConnectModal.closeModal());
94134
});
95135
}
96136

@@ -104,6 +144,7 @@ class WalletConnectWallet implements BaseWallet {
104144
},
105145
});
106146
}
147+
107148
this.reset();
108149
}
109150

0 commit comments

Comments
 (0)