@rango-dev/provider-walletconnect-2 0.57.0 → 0.57.1-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/adapter/adapter.d.ts +39 -0
  3. package/dist/adapter/adapter.d.ts.map +1 -0
  4. package/dist/adapter/index.d.ts +3 -0
  5. package/dist/adapter/index.d.ts.map +1 -0
  6. package/dist/adapter/modal-cache.d.ts +14 -0
  7. package/dist/adapter/modal-cache.d.ts.map +1 -0
  8. package/dist/adapter/modal.d.ts +25 -0
  9. package/dist/adapter/modal.d.ts.map +1 -0
  10. package/dist/adapter/networks.d.ts +60 -0
  11. package/dist/adapter/networks.d.ts.map +1 -0
  12. package/dist/adapter/provider-client.d.ts +3 -0
  13. package/dist/adapter/provider-client.d.ts.map +1 -0
  14. package/dist/adapter/registry.d.ts +4 -0
  15. package/dist/adapter/registry.d.ts.map +1 -0
  16. package/dist/adapter/session-cache.d.ts +17 -0
  17. package/dist/adapter/session-cache.d.ts.map +1 -0
  18. package/dist/adapter/task-queue.d.ts +11 -0
  19. package/dist/adapter/task-queue.d.ts.map +1 -0
  20. package/dist/chunk-GEAT645O.js +2 -0
  21. package/dist/chunk-GEAT645O.js.map +7 -0
  22. package/dist/constants.d.ts +4 -48
  23. package/dist/constants.d.ts.map +1 -0
  24. package/dist/evm-3KFL5N77.js +2 -0
  25. package/dist/evm-3KFL5N77.js.map +7 -0
  26. package/dist/mod.d.ts +4 -0
  27. package/dist/mod.d.ts.map +1 -0
  28. package/dist/mod.js +2 -0
  29. package/dist/mod.js.map +7 -0
  30. package/dist/namespaces/evm/hooks.d.ts +18 -0
  31. package/dist/namespaces/evm/hooks.d.ts.map +1 -0
  32. package/dist/namespaces/evm/namespace.d.ts +4 -0
  33. package/dist/namespaces/evm/namespace.d.ts.map +1 -0
  34. package/dist/namespaces/subscriber.d.ts +24 -0
  35. package/dist/namespaces/subscriber.d.ts.map +1 -0
  36. package/dist/provider.d.ts +3 -0
  37. package/dist/provider.d.ts.map +1 -0
  38. package/dist/session/accounts.d.ts +17 -0
  39. package/dist/session/accounts.d.ts.map +1 -0
  40. package/dist/session/bip122.d.ts +23 -0
  41. package/dist/session/bip122.d.ts.map +1 -0
  42. package/dist/session/chain-state.d.ts +6 -0
  43. package/dist/session/chain-state.d.ts.map +1 -0
  44. package/dist/session/evm-chain.d.ts +29 -0
  45. package/dist/session/evm-chain.d.ts.map +1 -0
  46. package/dist/session/evm.d.ts +25 -0
  47. package/dist/session/evm.d.ts.map +1 -0
  48. package/dist/session/lifecycle.d.ts +30 -0
  49. package/dist/session/lifecycle.d.ts.map +1 -0
  50. package/dist/session/lookup.d.ts +6 -0
  51. package/dist/session/lookup.d.ts.map +1 -0
  52. package/dist/session/proposals.d.ts +27 -0
  53. package/dist/session/proposals.d.ts.map +1 -0
  54. package/dist/session/restore-cache.d.ts +6 -0
  55. package/dist/session/restore-cache.d.ts.map +1 -0
  56. package/dist/session/teardown.d.ts +24 -0
  57. package/dist/session/teardown.d.ts.map +1 -0
  58. package/dist/signer.d.ts +2 -2
  59. package/dist/signer.d.ts.map +1 -0
  60. package/dist/signers/evm.d.ts +6 -4
  61. package/dist/signers/evm.d.ts.map +1 -0
  62. package/dist/types.d.ts +28 -11
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/utils.d.ts +17 -0
  65. package/dist/utils.d.ts.map +1 -0
  66. package/dist/wcConstants.d.ts +61 -0
  67. package/dist/wcConstants.d.ts.map +1 -0
  68. package/package.json +18 -13
  69. package/readme.md +14 -2
  70. package/src/adapter/adapter.ts +289 -0
  71. package/src/adapter/index.ts +2 -0
  72. package/src/adapter/modal-cache.ts +23 -0
  73. package/src/adapter/modal.ts +121 -0
  74. package/src/adapter/networks.ts +85 -0
  75. package/src/adapter/provider-client.ts +13 -0
  76. package/src/adapter/registry.ts +17 -0
  77. package/src/adapter/session-cache.ts +38 -0
  78. package/src/adapter/task-queue.ts +32 -0
  79. package/src/constants.ts +41 -76
  80. package/src/mod.ts +10 -0
  81. package/src/namespaces/evm/hooks.ts +148 -0
  82. package/src/namespaces/evm/namespace.ts +102 -0
  83. package/src/namespaces/subscriber.ts +106 -0
  84. package/src/provider.ts +35 -0
  85. package/src/session/accounts.ts +44 -0
  86. package/src/session/bip122.ts +225 -0
  87. package/src/session/chain-state.ts +38 -0
  88. package/src/session/evm-chain.ts +185 -0
  89. package/src/session/evm.ts +198 -0
  90. package/src/session/lifecycle.ts +241 -0
  91. package/src/session/lookup.ts +54 -0
  92. package/src/session/proposals.ts +96 -0
  93. package/src/session/restore-cache.ts +38 -0
  94. package/src/session/teardown.ts +181 -0
  95. package/src/signer.ts +9 -17
  96. package/src/signers/evm.ts +19 -17
  97. package/src/types.ts +31 -12
  98. package/src/utils.ts +68 -0
  99. package/src/wcConstants.ts +94 -0
  100. package/dist/chunk-6V3WUFOU.js +0 -2
  101. package/dist/chunk-6V3WUFOU.js.map +0 -7
  102. package/dist/chunk-BPSEZJUF.js +0 -2
  103. package/dist/chunk-BPSEZJUF.js.map +0 -7
  104. package/dist/chunk-DXVBX5XQ.js +0 -2
  105. package/dist/chunk-DXVBX5XQ.js.map +0 -7
  106. package/dist/dist-6GI3ECE5.js +0 -139
  107. package/dist/dist-6GI3ECE5.js.map +0 -7
  108. package/dist/evm-3ID4XY4Y.js +0 -2
  109. package/dist/evm-3ID4XY4Y.js.map +0 -7
  110. package/dist/helpers.d.ts +0 -31
  111. package/dist/index.d.ts +0 -21
  112. package/dist/index.js +0 -2
  113. package/dist/index.js.map +0 -7
  114. package/dist/session.d.ts +0 -63
  115. package/dist/signers/solana.d.ts +0 -14
  116. package/dist/solana-MFA7C5XI.js +0 -2
  117. package/dist/solana-MFA7C5XI.js.map +0 -7
  118. package/src/helpers.ts +0 -238
  119. package/src/index.ts +0 -234
  120. package/src/session.ts +0 -376
  121. package/src/signers/solana.ts +0 -160
  122. package/src/wc-types.d.ts +0 -31
@@ -0,0 +1,102 @@
1
+ import type { Context } from '@hub3js/core';
2
+ import type { EvmActions } from '@hub3js/evm';
3
+
4
+ import { NamespaceBuilder } from '@hub3js/core';
5
+ import { actions, builders, utils } from '@hub3js/evm';
6
+ import * as commonBuilders from '@hub3js/std/builders';
7
+ import { standardizeAndThrowError } from '@hub3js/std/operators';
8
+
9
+ import { getAdapter } from '../../adapter/registry.js';
10
+ import { WALLET_ID } from '../../constants.js';
11
+ import { getAccountsFromSession } from '../../session/accounts.js';
12
+ import { filterEvmAccounts } from '../../session/evm.js';
13
+ import { chainReferenceToHex, parseChainReference } from '../../utils.js';
14
+
15
+ import {
16
+ sessionDeleteSubscriber,
17
+ sessionEventSubscriber,
18
+ sessionUpdateSubscriber,
19
+ } from './hooks.js';
20
+
21
+ const [sessionUpdate, sessionUpdateCleanup] = sessionUpdateSubscriber();
22
+ const [sessionEvent, sessionEventCleanup] = sessionEventSubscriber();
23
+ const [sessionDelete, sessionDeleteCleanup] = sessionDeleteSubscriber();
24
+
25
+ const connect = builders
26
+ .connect()
27
+ .action(async function (_context: Context<EvmActions>, chain?: string) {
28
+ const adapter = getAdapter();
29
+ // `chain` is set when connecting to a specific network (swap auto-switch or hub connect with network).
30
+ const requestedReference = chain ? parseChainReference(chain) : undefined;
31
+ const session = await adapter.ensureConnectedToChain(chain);
32
+ const activeReference =
33
+ requestedReference ?? (await adapter.resolveActiveChainReference());
34
+
35
+ if (!activeReference) {
36
+ throw new Error(
37
+ 'Unable to determine EVM chain id from WalletConnect session.'
38
+ );
39
+ }
40
+
41
+ const accounts = getAccountsFromSession(session);
42
+ const evmAccounts = filterEvmAccounts(accounts, activeReference);
43
+
44
+ if (!evmAccounts.length) {
45
+ throw new Error('No EVM accounts found in WalletConnect session.');
46
+ }
47
+
48
+ return {
49
+ accounts: utils.formatAccountsToCAIP(
50
+ evmAccounts.map((account) => account.accounts[0]),
51
+ activeReference
52
+ ),
53
+ network: chainReferenceToHex(activeReference),
54
+ };
55
+ })
56
+ .before(sessionUpdate)
57
+ .before(sessionEvent)
58
+ .before(sessionDelete)
59
+ .or(sessionUpdateCleanup)
60
+ .or(sessionEventCleanup)
61
+ .or(sessionDeleteCleanup)
62
+ .or((_, err) => {
63
+ void getAdapter().disconnectSession('evm');
64
+ return err;
65
+ })
66
+ .or(standardizeAndThrowError)
67
+ .build();
68
+
69
+ const canEagerConnect = builders
70
+ .canEagerConnect()
71
+ .action(async () => getAdapter().tryRestoreEagerSession('evm'))
72
+ .build();
73
+
74
+ const canSwitchNetwork = builders
75
+ .canSwitchNetwork()
76
+ .action(actions.canSwitchNetwork())
77
+ .build();
78
+
79
+ const disconnect = commonBuilders
80
+ .disconnect<EvmActions>()
81
+ .before(async () => {
82
+ await getAdapter().disconnectSession('evm');
83
+ })
84
+ .after(sessionUpdateCleanup)
85
+ .after(sessionEventCleanup)
86
+ .after(sessionDeleteCleanup)
87
+ .build();
88
+
89
+ const getChainId = builders
90
+ .getChainId()
91
+ .action(async () => getAdapter().getCurrentChainId())
92
+ .build();
93
+
94
+ const evm = new NamespaceBuilder<EvmActions>('EVM', WALLET_ID)
95
+ .action(connect)
96
+ .action(canEagerConnect)
97
+ .action(canSwitchNetwork)
98
+ .action(disconnect)
99
+ .action(getChainId)
100
+ .build();
101
+
102
+ export { evm };
@@ -0,0 +1,106 @@
1
+ import type { WalletConnectAdapter } from '../adapter/adapter.js';
2
+ import type { WalletConnectNamespace } from '../types.js';
3
+ import type {
4
+ Actions,
5
+ Context,
6
+ Subscriber,
7
+ SubscriberCleanUp,
8
+ } from '@hub3js/core';
9
+ import type { SessionTypes, SignClientTypes } from '@walletconnect/types';
10
+
11
+ import { debug } from '@rango-dev/logging-core';
12
+
13
+ import { getAdapter } from '../adapter/registry.js';
14
+
15
+ /** The WC client events a namespace subscribes to. */
16
+ export type SessionEventName =
17
+ | 'session_update'
18
+ | 'session_event'
19
+ | 'session_delete';
20
+
21
+ export type SessionEventHandler<
22
+ Name extends SessionEventName,
23
+ ActionsType extends Actions<ActionsType>
24
+ > = (event: {
25
+ args: SignClientTypes.EventArguments[Name];
26
+ /** The cached session this event was matched against. */
27
+ session: SessionTypes.Struct;
28
+ adapter: WalletConnectAdapter;
29
+ context: Context<ActionsType>;
30
+ }) => void | Promise<void>;
31
+
32
+ function logHandlerError(error: unknown) {
33
+ debug(error instanceof Error ? error : new Error(String(error)));
34
+ }
35
+
36
+ /**
37
+ * Builds a hub subscriber for one WC client event, scoped to one namespace.
38
+ *
39
+ * Every namespace hook needs the same four things - resolve the client, only act
40
+ * on events for the session this namespace has cached, register, and unregister
41
+ * the exact same handler reference. Getting the topic guard wrong is what makes a
42
+ * hook act on the other namespace's session, so it lives here rather than being
43
+ * repeated per hook.
44
+ */
45
+ export function createSessionSubscriber<
46
+ Name extends SessionEventName,
47
+ ActionsType extends Actions<ActionsType>
48
+ >(
49
+ namespace: WalletConnectNamespace,
50
+ event: Name,
51
+ handle: SessionEventHandler<Name, ActionsType>
52
+ ): [Subscriber<ActionsType>, SubscriberCleanUp<ActionsType>] {
53
+ let handler: ((args: SignClientTypes.EventArguments[Name]) => void) | null =
54
+ null;
55
+
56
+ return [
57
+ async (context) => {
58
+ const adapter = getAdapter();
59
+ const client = await adapter.getClient();
60
+
61
+ /*
62
+ * A namespace re-runs its `before` subscribers on every connect, so drop the
63
+ * previous registration first - otherwise each reconnect leaves another live
64
+ * handler behind and only the last one is ever removed.
65
+ */
66
+ if (handler) {
67
+ client.off(event, handler);
68
+ }
69
+
70
+ handler = (args) => {
71
+ const session = adapter.getSession(namespace);
72
+ if (!session || args.topic !== session.topic) {
73
+ return;
74
+ }
75
+
76
+ /*
77
+ * WC dispatches these from its own async request pipeline with nothing
78
+ * catching downstream, so a throw here (a payload shaped unlike anything
79
+ * the handler expects) would surface as an unhandled rejection and take
80
+ * the rest of that pipeline's processing with it. Async handlers are
81
+ * covered too - their rejection lands nowhere otherwise.
82
+ */
83
+ try {
84
+ const handled = handle({ args, session, adapter, context });
85
+ if (handled instanceof Promise) {
86
+ void handled.catch(logHandlerError);
87
+ }
88
+ } catch (error) {
89
+ logHandlerError(error);
90
+ }
91
+ };
92
+
93
+ client.on(event, handler);
94
+ },
95
+ (_, err) => {
96
+ const currentHandler = handler;
97
+ if (currentHandler) {
98
+ handler = null;
99
+ void getAdapter()
100
+ .getClient()
101
+ .then((client) => client.off(event, currentHandler));
102
+ }
103
+ return err;
104
+ },
105
+ ];
106
+ }
@@ -0,0 +1,35 @@
1
+ import type { Environments } from './types.js';
2
+
3
+ import { ProviderBuilder } from '@hub3js/core';
4
+
5
+ import { WalletConnectAdapter } from './adapter/adapter.js';
6
+ import { setAdapter } from './adapter/registry.js';
7
+ import { metadata, WALLET_ID } from './constants.js';
8
+ import { evm } from './namespaces/evm/namespace.js';
9
+
10
+ const buildProvider = () =>
11
+ new ProviderBuilder(WALLET_ID)
12
+ .init(function (context, environments: Environments) {
13
+ const [, setState] = context.state();
14
+
15
+ if (!environments.WC_PROJECT_ID) {
16
+ return;
17
+ }
18
+
19
+ setAdapter(
20
+ new WalletConnectAdapter({
21
+ projectId: environments.WC_PROJECT_ID,
22
+ meta: environments.meta || [],
23
+ disableModalLink: environments.DISABLE_MODAL_AND_OPEN_LINK,
24
+ themeMode: environments.themeMode,
25
+ modalZIndex: environments.modalZIndex,
26
+ })
27
+ );
28
+ setState('installed', true);
29
+ console.debug('[wallet-connect-2] provider initialized.', context);
30
+ })
31
+ .config('metadata', metadata)
32
+ .add('evm', evm)
33
+ .build();
34
+
35
+ export { buildProvider };
@@ -0,0 +1,44 @@
1
+ import type { SessionTypes, SignClientTypes } from '@walletconnect/types';
2
+
3
+ import { AccountId } from 'caip';
4
+
5
+ /**
6
+ * `accountsChanged` entries are CAIP-10 (`eip155:1:0x…`) from wallets that follow
7
+ * WC and a bare `0x…` from the ones forwarding the EIP-1193 payload as-is.
8
+ */
9
+ export function extractAddress(account: string): string {
10
+ return account.includes(':') ? new AccountId(account).address : account;
11
+ }
12
+
13
+ export function getAccountsFromSession(session: SessionTypes.Struct) {
14
+ const accounts = Object.values(session.namespaces)
15
+ .map((namespace) => namespace.accounts)
16
+ .flat()
17
+ .map((account) => {
18
+ const { address, chainId } = new AccountId(account);
19
+ return {
20
+ address,
21
+ chainId: chainId.reference,
22
+ };
23
+ });
24
+ return accounts;
25
+ }
26
+
27
+ export function getAccountsFromEvent(
28
+ event: SignClientTypes.BaseEventArgs<{
29
+ namespaces: SessionTypes.Namespaces;
30
+ }>
31
+ ) {
32
+ const accounts = Object.values(event.params.namespaces)
33
+ .map((namespace) => namespace.accounts)
34
+ .flat()
35
+ .map((account) => {
36
+ const { address, chainId } = new AccountId(account);
37
+ return {
38
+ accounts: [address],
39
+ chainId: chainId.reference,
40
+ };
41
+ });
42
+
43
+ return accounts;
44
+ }
@@ -0,0 +1,225 @@
1
+ import type { SignClientInstance } from '../types.js';
2
+ import type { SessionTypes, SignClientTypes } from '@walletconnect/types';
3
+
4
+ import { debug } from '@rango-dev/logging-core';
5
+ import { CAIP_BITCOIN_CHAIN_ID } from '@rango-dev/wallets-core/namespaces/utxo';
6
+ import { AccountId } from 'caip';
7
+
8
+ import { BitcoinEvents, NAMESPACES } from '../wcConstants.js';
9
+
10
+ export function getBip122AccountsFromSession(
11
+ session: SessionTypes.Struct
12
+ ): string[] {
13
+ return session.namespaces[NAMESPACES.BITCOIN]?.accounts ?? [];
14
+ }
15
+
16
+ export function filterBip122Accounts(session: SessionTypes.Struct) {
17
+ return getBip122AccountsFromSession(session).map((account) => ({
18
+ address: new AccountId(account).address,
19
+ }));
20
+ }
21
+
22
+ export type Bip122AddressEntry = {
23
+ address: string;
24
+ intention?: 'payment' | 'ordinal';
25
+ };
26
+
27
+ /**
28
+ * Every address a `bip122_addressesChanged` payload carries, in wallet order.
29
+ * Unlike {@link pickPaymentAddress} it makes no guess about which one is active.
30
+ */
31
+ export function getAnnouncedAddresses(
32
+ data: Bip122AddressEntry[] | string[] | undefined
33
+ ): string[] {
34
+ if (!data?.length) {
35
+ return [];
36
+ }
37
+
38
+ return data
39
+ .map((entry) => (typeof entry === 'string' ? entry : entry?.address))
40
+ .filter((address): address is string => !!address);
41
+ }
42
+
43
+ export function pickPaymentAddress(
44
+ data: Bip122AddressEntry[] | string[] | undefined
45
+ ): string | undefined {
46
+ if (!data?.length) {
47
+ return undefined;
48
+ }
49
+
50
+ const first = data[0];
51
+ if (typeof first === 'string') {
52
+ return first;
53
+ }
54
+
55
+ const entries = data as Bip122AddressEntry[];
56
+ return (
57
+ entries.find((entry) => entry.intention === 'payment')?.address ??
58
+ entries[0]?.address
59
+ );
60
+ }
61
+
62
+ export function patchBip122SessionAccount(
63
+ session: SessionTypes.Struct,
64
+ address: string
65
+ ): SessionTypes.Struct {
66
+ const btcNamespace = session.namespaces[NAMESPACES.BITCOIN];
67
+ if (!btcNamespace) {
68
+ return session;
69
+ }
70
+
71
+ const caipAccount = new AccountId({
72
+ chainId: {
73
+ namespace: NAMESPACES.BITCOIN,
74
+ reference: CAIP_BITCOIN_CHAIN_ID,
75
+ },
76
+ address,
77
+ }).toString();
78
+
79
+ const accounts = btcNamespace.accounts ?? [];
80
+ const hasAccount = accounts.some(
81
+ (account) =>
82
+ new AccountId(account).address.toLowerCase() === address.toLowerCase()
83
+ );
84
+
85
+ if (hasAccount) {
86
+ return session;
87
+ }
88
+
89
+ return {
90
+ ...session,
91
+ namespaces: {
92
+ ...session.namespaces,
93
+ [NAMESPACES.BITCOIN]: {
94
+ ...btcNamespace,
95
+ accounts: [...accounts, caipAccount],
96
+ },
97
+ },
98
+ };
99
+ }
100
+
101
+ const BIP122_ACCOUNT_TIMEOUT = 15_000;
102
+
103
+ /**
104
+ * Bitcoin wallets often approve bip122 without accounts in the session object.
105
+ * They emit bip122_addressesChanged or session_update shortly after approval.
106
+ */
107
+ export async function resolveBip122Session(
108
+ client: SignClientInstance,
109
+ session: SessionTypes.Struct
110
+ ): Promise<SessionTypes.Struct> {
111
+ const existing = filterBip122Accounts(session);
112
+ if (existing.length) {
113
+ return session;
114
+ }
115
+
116
+ const freshSession = client.session.get(session.topic) ?? session;
117
+ const freshAccounts = filterBip122Accounts(freshSession);
118
+ if (freshAccounts.length) {
119
+ return freshSession;
120
+ }
121
+
122
+ const { address, session: resolvedSession } =
123
+ await waitForBip122PaymentAddress(client, freshSession);
124
+
125
+ const patched = patchBip122SessionAccount(resolvedSession, address);
126
+ await persistSessionNamespaces(client, patched);
127
+ return patched;
128
+ }
129
+
130
+ /**
131
+ * The address the wallet reports via `bip122_addressesChanged` lands only on our
132
+ * patched copy, so write it back to `client.session` - the record that restore,
133
+ * teardown and staleness checks all read. Left unpersisted, the stored session
134
+ * keeps `bip122.accounts === []`: `cleanupStaleSessionsForNamespace` reads a live
135
+ * session as stale and disconnects it, and a reload waits again for an event the
136
+ * wallet only emits right after approval.
137
+ */
138
+ async function persistSessionNamespaces(
139
+ client: SignClientInstance,
140
+ session: SessionTypes.Struct
141
+ ): Promise<void> {
142
+ try {
143
+ await client.session.update(session.topic, {
144
+ namespaces: session.namespaces,
145
+ });
146
+ } catch (error) {
147
+ debug(error instanceof Error ? error : new Error(String(error)));
148
+ }
149
+ }
150
+
151
+ async function waitForBip122PaymentAddress(
152
+ client: SignClientInstance,
153
+ session: SessionTypes.Struct,
154
+ timeoutMs = BIP122_ACCOUNT_TIMEOUT
155
+ ): Promise<{ address: string; session: SessionTypes.Struct }> {
156
+ return await new Promise((resolve, reject) => {
157
+ const topic = session.topic;
158
+ let settled = false;
159
+
160
+ const finish = (address: string, updatedSession: SessionTypes.Struct) => {
161
+ if (settled) {
162
+ return;
163
+ }
164
+ settled = true;
165
+ cleanup();
166
+ resolve({ address, session: updatedSession });
167
+ };
168
+
169
+ const fail = (error: Error) => {
170
+ if (settled) {
171
+ return;
172
+ }
173
+ settled = true;
174
+ cleanup();
175
+ reject(error);
176
+ };
177
+
178
+ const timer = setTimeout(() => {
179
+ fail(
180
+ new Error(
181
+ 'Timed out waiting for Bitcoin account from wallet. Please try reconnecting.'
182
+ )
183
+ );
184
+ }, timeoutMs);
185
+
186
+ const cleanup = () => {
187
+ clearTimeout(timer);
188
+ client.off('session_event', onEvent);
189
+ client.off('session_update', onUpdate);
190
+ };
191
+
192
+ const onEvent = (args: SignClientTypes.EventArguments['session_event']) => {
193
+ if (args.topic !== topic) {
194
+ return;
195
+ }
196
+ if (args.params.event.name !== BitcoinEvents.ADDRESSES_CHANGED) {
197
+ return;
198
+ }
199
+
200
+ const address = pickPaymentAddress(
201
+ args.params.event.data as Bip122AddressEntry[]
202
+ );
203
+ if (address) {
204
+ finish(address, client.session.get(topic) ?? session);
205
+ }
206
+ };
207
+
208
+ const onUpdate = (
209
+ args: SignClientTypes.EventArguments['session_update']
210
+ ) => {
211
+ if (args.topic !== topic) {
212
+ return;
213
+ }
214
+
215
+ const updatedSession = client.session.get(topic) ?? session;
216
+ const accounts = filterBip122Accounts(updatedSession);
217
+ if (accounts.length) {
218
+ finish(accounts[0].address, updatedSession);
219
+ }
220
+ };
221
+
222
+ client.on('session_event', onEvent);
223
+ client.on('session_update', onUpdate);
224
+ });
225
+ }
@@ -0,0 +1,38 @@
1
+ import type { ISignClient } from '@walletconnect/types';
2
+ import type { BlockchainMeta } from 'rango-types';
3
+
4
+ import { CHAIN_ID_STORAGE } from '../wcConstants.js';
5
+
6
+ export async function persistCurrentChainId(
7
+ client: ISignClient,
8
+ chainId?: string
9
+ ) {
10
+ return client.core.storage.setItem(CHAIN_ID_STORAGE, {
11
+ defaultChainId: chainId ? parseInt(chainId) : '',
12
+ });
13
+ }
14
+
15
+ export async function getPersistedChainId(client: ISignClient) {
16
+ try {
17
+ const chainId = (await client.core.storage.getItem(CHAIN_ID_STORAGE))
18
+ ?.defaultChainId;
19
+ return !!chainId ? String(chainId) : undefined;
20
+ } catch {
21
+ return undefined;
22
+ }
23
+ }
24
+
25
+ export function getChainIdByNetworkName(
26
+ network: string,
27
+ meta: BlockchainMeta[]
28
+ ): string | undefined {
29
+ const targetBlockchain = meta.find(
30
+ (blockchain) => blockchain.name === network
31
+ );
32
+ const chainIdInHex = targetBlockchain?.chainId;
33
+ if (!chainIdInHex) {
34
+ return undefined;
35
+ }
36
+
37
+ return String(parseInt(chainIdInHex));
38
+ }