@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,96 @@
1
+ import type { WalletConnectNamespace } from '../types.js';
2
+ import type { ChainIdParams } from 'caip';
3
+
4
+ import { CAIP_BITCOIN_CHAIN_ID } from '@rango-dev/wallets-core/namespaces/utxo';
5
+ import { ChainId } from 'caip';
6
+
7
+ import {
8
+ DEFAULT_BITCOIN_EVENTS,
9
+ DEFAULT_BITCOIN_METHODS,
10
+ DEFAULT_ETHEREUM_EVENTS,
11
+ DEFAULT_ETHEREUM_METHODS,
12
+ NAMESPACES,
13
+ WC_NAMESPACE_TO_CAIP,
14
+ } from '../wcConstants.js';
15
+
16
+ /**
17
+ * `chains` is required here so the same shape is assignable both to the
18
+ * SignClient `ProposalTypes` (chains optional) and to the UniversalProvider
19
+ * `NamespaceConfig` (chains required).
20
+ */
21
+ export type FinalNamespaces = Record<
22
+ string,
23
+ { chains: string[]; methods: string[]; events: string[] }
24
+ >;
25
+
26
+ type NamespaceProposal = {
27
+ methods: string[];
28
+ events: string[];
29
+ resolveChains: (
30
+ chains: ChainIdParams[],
31
+ targetChainReference?: string
32
+ ) => ChainIdParams[];
33
+ };
34
+
35
+ /**
36
+ * Per-namespace proposal facts as data, keyed by `WalletConnectNamespace` so a
37
+ * newly-added alias is a compile error until it's configured here. The CAIP
38
+ * prefix comes from the shared `WC_NAMESPACE_TO_CAIP` map.
39
+ */
40
+ const NAMESPACE_PROPOSALS: Record<WalletConnectNamespace, NamespaceProposal> = {
41
+ evm: {
42
+ methods: DEFAULT_ETHEREUM_METHODS,
43
+ events: DEFAULT_ETHEREUM_EVENTS,
44
+ resolveChains: (chains, targetChainReference) => {
45
+ if (targetChainReference) {
46
+ return [
47
+ { namespace: NAMESPACES.ETHEREUM, reference: targetChainReference },
48
+ ];
49
+ }
50
+ return chains.length > 0
51
+ ? chains
52
+ : [{ namespace: NAMESPACES.ETHEREUM, reference: '1' }];
53
+ },
54
+ },
55
+ utxo: {
56
+ methods: DEFAULT_BITCOIN_METHODS,
57
+ events: DEFAULT_BITCOIN_EVENTS,
58
+ resolveChains: () => [
59
+ { namespace: NAMESPACES.BITCOIN, reference: CAIP_BITCOIN_CHAIN_ID },
60
+ ],
61
+ },
62
+ };
63
+
64
+ /**
65
+ * Builds a WalletConnect namespace proposal (chains, methods, events).
66
+ *
67
+ * The result always goes to `optionalNamespaces`: sign-client merges
68
+ * `requiredNamespaces` into `optionalNamespaces` and clears it before sending
69
+ * the proposal, so passing anything as required only earns a deprecation
70
+ * warning. Narrowing the proposal (see `targetChainReference`) is what actually
71
+ * constrains what the wallet can approve.
72
+ *
73
+ * @param targetChainReference - When set for EVM, limits the proposal to this
74
+ * single chain id (decimal string, e.g. `"137"`). Omit to include all EVM
75
+ * chains from `chains`.
76
+ */
77
+ export function generateOptionalNamespace(
78
+ chains: ChainIdParams[],
79
+ namespaces: WalletConnectNamespace[],
80
+ targetChainReference?: string
81
+ ): FinalNamespaces | undefined {
82
+ const proposal: FinalNamespaces = {};
83
+
84
+ for (const namespace of namespaces) {
85
+ const config = NAMESPACE_PROPOSALS[namespace];
86
+ proposal[WC_NAMESPACE_TO_CAIP[namespace]] = {
87
+ methods: config.methods,
88
+ events: config.events,
89
+ chains: config
90
+ .resolveChains(chains, targetChainReference)
91
+ .map((chain) => new ChainId(chain).toString()),
92
+ };
93
+ }
94
+
95
+ return Object.keys(proposal).length > 0 ? proposal : undefined;
96
+ }
@@ -0,0 +1,38 @@
1
+ import type { SessionCache } from '../adapter/session-cache.js';
2
+ import type { SignClientInstance, WalletConnectNamespace } from '../types.js';
3
+ import type { SessionTypes } from '@walletconnect/types';
4
+
5
+ import { debug } from '@rango-dev/logging-core';
6
+
7
+ import {
8
+ restoreWalletConnectSession,
9
+ type RestoreWalletConnectSessionOptions,
10
+ } from './lifecycle.js';
11
+
12
+ export async function restoreAndCacheSession(
13
+ client: SignClientInstance,
14
+ namespace: WalletConnectNamespace,
15
+ cache: SessionCache,
16
+ options?: RestoreWalletConnectSessionOptions,
17
+ onDisconnect?: (namespace: WalletConnectNamespace) => Promise<void>
18
+ ): Promise<SessionTypes.Struct | null> {
19
+ try {
20
+ const session = await restoreWalletConnectSession(
21
+ client,
22
+ namespace,
23
+ options
24
+ );
25
+ if (!session) {
26
+ return null;
27
+ }
28
+
29
+ cache.set(namespace, session);
30
+ return session;
31
+ } catch (error) {
32
+ debug(error instanceof Error ? error : new Error(String(error)));
33
+ if (cache.get(namespace)) {
34
+ await onDisconnect?.(namespace);
35
+ }
36
+ return null;
37
+ }
38
+ }
@@ -0,0 +1,181 @@
1
+ import type { SignClientInstance, WalletConnectNamespace } from '../types.js';
2
+ import type { ISignClient, SessionTypes } from '@walletconnect/types';
3
+ import type UniversalProvider from '@walletconnect/universal-provider';
4
+
5
+ import { debug } from '@rango-dev/logging-core';
6
+ import { getSdkError } from '@walletconnect/utils';
7
+
8
+ import { NAMESPACES } from '../wcConstants.js';
9
+
10
+ import { persistCurrentChainId } from './chain-state.js';
11
+ import { getSessionNamespace } from './lookup.js';
12
+
13
+ function isNoMatchingKeyError(error: unknown): boolean {
14
+ const message = error instanceof Error ? error.message : String(error);
15
+ return message.includes('No matching key');
16
+ }
17
+
18
+ export function hasActiveSession(client: ISignClient, topic: string): boolean {
19
+ try {
20
+ return !!client.session.get(topic);
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ export function hasActivePairing(
27
+ client: SignClientInstance,
28
+ topic: string
29
+ ): boolean {
30
+ return client.pairing.getAll().some((pairing) => pairing.topic === topic);
31
+ }
32
+
33
+ export async function expireWalletConnectTopic(
34
+ client: SignClientInstance,
35
+ topic: string
36
+ ) {
37
+ const sessions = client.session.getAll();
38
+ const pairings = client.pairing.getAll();
39
+
40
+ sessions.forEach((session: SessionTypes.Struct) => {
41
+ if (session.topic === topic || session.pairingTopic === topic) {
42
+ const requestForDeleteTopic =
43
+ session.pairingTopic === topic ? session.pairingTopic : session.topic;
44
+ client.core.expirer.set(requestForDeleteTopic, 0);
45
+ }
46
+ });
47
+
48
+ pairings.forEach((pairing) => {
49
+ if (pairing.topic === topic) {
50
+ client.core.expirer.set(topic, 0);
51
+ }
52
+ });
53
+ }
54
+
55
+ export async function removeSessionRecord(
56
+ client: SignClientInstance,
57
+ session: SessionTypes.Struct
58
+ ) {
59
+ const namespace = getSessionNamespace(session);
60
+ const pairingTopic = session.pairingTopic;
61
+
62
+ if (hasActiveSession(client, session.topic)) {
63
+ try {
64
+ await client.disconnect({
65
+ topic: session.topic,
66
+ reason: getSdkError('USER_DISCONNECTED'),
67
+ });
68
+ } catch (error) {
69
+ debug(error instanceof Error ? error : new Error(String(error)));
70
+ if (isNoMatchingKeyError(error)) {
71
+ await expireWalletConnectTopic(client, session.topic);
72
+ }
73
+ }
74
+ } else {
75
+ await expireWalletConnectTopic(client, session.topic);
76
+ }
77
+
78
+ const remainingOnPairing = client.session
79
+ .getAll()
80
+ .filter((item) => item.pairingTopic === pairingTopic);
81
+
82
+ if (!remainingOnPairing.length && pairingTopic) {
83
+ if (hasActivePairing(client, pairingTopic)) {
84
+ try {
85
+ await client.disconnect({
86
+ topic: pairingTopic,
87
+ reason: getSdkError('USER_DISCONNECTED'),
88
+ });
89
+ } catch (error) {
90
+ debug(error instanceof Error ? error : new Error(String(error)));
91
+ if (isNoMatchingKeyError(error)) {
92
+ await expireWalletConnectTopic(client, pairingTopic);
93
+ }
94
+ }
95
+ } else {
96
+ await expireWalletConnectTopic(client, pairingTopic);
97
+ }
98
+ }
99
+
100
+ if (namespace === 'evm') {
101
+ void persistCurrentChainId(client, undefined);
102
+ }
103
+ }
104
+
105
+ export async function purgeOrphanedSessions(
106
+ client: SignClientInstance
107
+ ): Promise<void> {
108
+ const pairingTopics = new Set(
109
+ client.pairing.getAll().map((pairing) => pairing.topic)
110
+ );
111
+
112
+ for (const session of [...client.session.getAll()]) {
113
+ const pairingOrphaned =
114
+ !!session.pairingTopic && !pairingTopics.has(session.pairingTopic);
115
+ const sessionMissing = !hasActiveSession(client, session.topic);
116
+
117
+ if (pairingOrphaned || sessionMissing) {
118
+ await removeSessionRecord(client, session);
119
+ }
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Drops pairings that no session is using.
125
+ *
126
+ * The inverse of {@link purgeOrphanedSessions}, and the only thing that collects
127
+ * them: a cancelled connect leaves behind the pairing `client.connect()` minted,
128
+ * and `cleanupPendingPairings` only unsubscribes pairings - it never deletes the
129
+ * record. Without this they accumulate in `client.pairing` and in storage for the
130
+ * lifetime of the origin.
131
+ *
132
+ * Only safe to call while no connect is in flight (the adapter's `#sessionQueue`
133
+ * guarantees that): a pairing awaiting its first approval has no session yet, so
134
+ * dropping it would kill that handshake.
135
+ */
136
+ export async function purgeOrphanedPairings(
137
+ client: SignClientInstance
138
+ ): Promise<void> {
139
+ const usedPairingTopics = new Set(
140
+ client.session
141
+ .getAll()
142
+ .map((session) => session.pairingTopic)
143
+ .filter((topic): topic is string => !!topic)
144
+ );
145
+
146
+ for (const pairing of [...client.pairing.getAll()]) {
147
+ if (usedPairingTopics.has(pairing.topic)) {
148
+ continue;
149
+ }
150
+
151
+ try {
152
+ await client.disconnect({
153
+ topic: pairing.topic,
154
+ reason: getSdkError('USER_DISCONNECTED'),
155
+ });
156
+ } catch (error) {
157
+ debug(error instanceof Error ? error : new Error(String(error)));
158
+ await expireWalletConnectTopic(client, pairing.topic);
159
+ }
160
+ }
161
+ }
162
+
163
+ export async function cleanupStaleSessionsForNamespace(
164
+ client: UniversalProvider['client'],
165
+ namespace: WalletConnectNamespace
166
+ ): Promise<void> {
167
+ for (const existing of client.session.getAll()) {
168
+ if (getSessionNamespace(existing) !== namespace) {
169
+ continue;
170
+ }
171
+
172
+ const btc = existing.namespaces[NAMESPACES.BITCOIN];
173
+ if (
174
+ btc &&
175
+ (btc.chains?.length ?? 0) > 0 &&
176
+ (btc.accounts?.length ?? 0) === 0
177
+ ) {
178
+ await removeSessionRecord(client, existing);
179
+ }
180
+ }
181
+ }
package/src/signer.ts CHANGED
@@ -1,35 +1,27 @@
1
- import type { WCInstance } from './types.js';
2
1
  import type { SignerFactory } from 'rango-types';
3
2
 
4
3
  import { dynamicImportWithRefinedError } from '@rango-dev/wallets-shared';
5
4
  import { DefaultSignerFactory, TransactionType as TxType } from 'rango-types';
6
5
 
7
- export default async function getSigners(
8
- instance: WCInstance
9
- ): Promise<SignerFactory> {
10
- if (!instance.session) {
11
- throw new Error('Session is required for wallet connect signers.');
6
+ import { getAdapter } from './adapter/registry.js';
7
+
8
+ export default async function getSigners(): Promise<SignerFactory> {
9
+ const adapter = getAdapter();
10
+ if (!adapter) {
11
+ throw new Error('WalletConnect provider has not been initialized.');
12
12
  }
13
13
 
14
+ const client = await adapter.getClient();
15
+
14
16
  const signers = new DefaultSignerFactory();
15
17
  const EVMSigner = (
16
18
  await dynamicImportWithRefinedError(
17
19
  async () => await import('./signers/evm.js')
18
20
  )
19
21
  ).default;
20
- const SOLANASigner = (
21
- await dynamicImportWithRefinedError(
22
- async () => await import('./signers/solana.js')
23
- )
24
- ).default;
25
-
26
22
  signers.registerSigner(
27
23
  TxType.EVM,
28
- new EVMSigner(instance.client, instance.session)
29
- );
30
- signers.registerSigner(
31
- TxType.SOLANA,
32
- new SOLANASigner(instance.client, instance.session)
24
+ new EVMSigner(client, () => adapter.getSession('evm'))
33
25
  );
34
26
 
35
27
  return signers;
@@ -1,16 +1,17 @@
1
- import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
2
- import type { SessionTypes } from '@walletconnect/types';
1
+ import type { ISignClient, SessionTypes } from '@walletconnect/types';
3
2
  import type { EvmTransaction } from 'rango-types/mainApi';
4
3
 
5
4
  import { cleanEvmError, toHexQuantity } from '@rango-dev/signer-evm';
6
- import * as encoding from '@walletconnect/encoding';
7
5
  import { AccountId, ChainId } from 'caip';
8
6
  import { type GenericSigner } from 'rango-types';
9
7
 
10
- import { EthereumRPCMethods, NAMESPACES } from '../constants.js';
8
+ import { utf8ToHex } from '../utils.js';
9
+ import { EthereumRPCMethods, NAMESPACES } from '../wcConstants.js';
11
10
 
12
11
  const NAMESPACE_NAME = NAMESPACES.ETHEREUM;
13
12
 
13
+ type SessionGetter = () => SessionTypes.Struct | null;
14
+
14
15
  type WalletConnectEvmTx = {
15
16
  from?: string;
16
17
  to?: string;
@@ -24,12 +25,20 @@ type WalletConnectEvmTx = {
24
25
  };
25
26
 
26
27
  class EVMSigner implements GenericSigner<EvmTransaction> {
27
- private client: SignClient;
28
- private session: SessionTypes.Struct;
28
+ private client: ISignClient;
29
+ private getSession: SessionGetter;
29
30
 
30
- constructor(client: SignClient, session: SessionTypes.Struct) {
31
+ constructor(client: ISignClient, getSession: SessionGetter) {
31
32
  this.client = client;
32
- this.session = session;
33
+ this.getSession = getSession;
34
+ }
35
+
36
+ private get session(): SessionTypes.Struct {
37
+ const session = this.getSession();
38
+ if (!session) {
39
+ throw new Error('EVM WalletConnect session is not available.');
40
+ }
41
+ return session;
33
42
  }
34
43
 
35
44
  /**
@@ -89,7 +98,7 @@ class EVMSigner implements GenericSigner<EvmTransaction> {
89
98
  namespace: NAMESPACE_NAME,
90
99
  reference: requestedFor.chainId,
91
100
  });
92
- const hexMsg = encoding.utf8ToHex(msg, true);
101
+ const hexMsg = utf8ToHex(msg, true);
93
102
 
94
103
  const params = [hexMsg, address];
95
104
 
@@ -141,6 +150,7 @@ class EVMSigner implements GenericSigner<EvmTransaction> {
141
150
  `Received an invalid hash on signing the transaction. (hash=${hash})`
142
151
  );
143
152
  }
153
+
144
154
  return {
145
155
  hash,
146
156
  };
@@ -165,7 +175,6 @@ class EVMSigner implements GenericSigner<EvmTransaction> {
165
175
  const { address, chainId } = requestedFor;
166
176
 
167
177
  if (!chainId) {
168
- console.log('isNetworkAndAccountExistInSession', requestedFor);
169
178
  throw new Error(
170
179
  'You need to set your chain for signing message/transaction.'
171
180
  );
@@ -191,13 +200,6 @@ class EVMSigner implements GenericSigner<EvmTransaction> {
191
200
  );
192
201
 
193
202
  if (!addresses || !addresses.includes(caipAddress.toString())) {
194
- console.warn(
195
- 'Available adresses and requested address:',
196
- addresses,
197
- caipAddress.toString(),
198
- chainId,
199
- address
200
- );
201
203
  throw new Error(
202
204
  `Your requested address doesn't exist on your wallect connect session. Please reconnect your wallet.`
203
205
  );
package/src/types.ts CHANGED
@@ -1,26 +1,45 @@
1
- import type { SignClient } from '@walletconnect/sign-client/dist/types/client';
2
- import type { ProposalTypes, SessionTypes } from '@walletconnect/types';
1
+ import type { ProposalTypes } from '@walletconnect/types';
2
+ import type { ChainIdParams } from 'caip';
3
3
  import type { BlockchainMeta } from 'rango-types';
4
4
 
5
- export interface Environments extends Record<string, string | undefined> {
5
+ import { SignClient } from '@walletconnect/sign-client';
6
+
7
+ export { SignClient };
8
+
9
+ export type SignClientInstance = InstanceType<typeof SignClient>;
10
+
11
+ export interface Environments {
6
12
  WC_PROJECT_ID: string;
7
13
  // This is useful for directly opening a listed WC wallet. you will need to pass a url.
8
14
  DISABLE_MODAL_AND_OPEN_LINK?: string;
15
+ meta?: BlockchainMeta[];
16
+ themeMode?: 'light' | 'dark';
17
+ modalZIndex?: number;
9
18
  }
10
- export interface WCInstance {
11
- client: SignClient;
12
- session: SessionTypes.Struct | null;
13
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
- request: (params: any) => Promise<string>;
15
- }
19
+
20
+ export type WalletConnectNamespace = 'evm' | 'utxo';
16
21
 
17
22
  export interface CreateSessionParams {
18
- requiredNamespaces: ProposalTypes.RequiredNamespaces;
19
- optionalNamespaces?: ProposalTypes.OptionalNamespaces;
23
+ /**
24
+ * The whole proposal goes here - sign-client folds `requiredNamespaces` into
25
+ * this and clears it, so proposing anything as required is deprecated.
26
+ */
27
+ optionalNamespaces: ProposalTypes.OptionalNamespaces;
20
28
  pairingTopic?: string;
21
29
  }
22
30
 
23
31
  export interface ConnectParams {
24
- meta: BlockchainMeta[];
32
+ /**
33
+ * Chains to propose, as CAIP-2 ids. Callers convert rango `BlockchainMeta`
34
+ * at the boundary (see `evmMetaToCaipChainIds`) so the connect path stays
35
+ * decoupled from rango-types' chain shape.
36
+ */
37
+ chains: ChainIdParams[];
25
38
  envs: Environments;
39
+ namespace: WalletConnectNamespace;
40
+ /**
41
+ * Decimal EVM chain reference (e.g. `"137"`).
42
+ * When set, it is the only EVM chain proposed during session creation.
43
+ */
44
+ chainReference?: string;
26
45
  }
package/src/utils.ts ADDED
@@ -0,0 +1,68 @@
1
+ import type { Chain } from '@hub3js/evm';
2
+ import type { ChainIdParams } from 'caip';
3
+ import type { BlockchainMeta } from 'rango-types';
4
+
5
+ import { isEvmBlockchain } from 'rango-types';
6
+
7
+ import { NAMESPACES } from './wcConstants.js';
8
+
9
+ const HEX_RADIX = 16;
10
+
11
+ export function utf8ToHex(value: string, prefixed = false): string {
12
+ const hex = Array.from(new TextEncoder().encode(value))
13
+ .map((byte) => byte.toString(HEX_RADIX).padStart(2, '0'))
14
+ .join('');
15
+
16
+ return prefixed ? `0x${hex}` : hex;
17
+ }
18
+
19
+ /** Normalizes hub chain input (hex, decimal, or AddEthereumChainParameter) to a decimal reference. */
20
+ export function parseChainReference(
21
+ chain?: string | Chain
22
+ ): string | undefined {
23
+ if (!chain) {
24
+ return undefined;
25
+ }
26
+
27
+ if (typeof chain === 'string') {
28
+ return chain.startsWith('0x')
29
+ ? String(parseInt(chain))
30
+ : String(parseInt(chain, 10) || chain);
31
+ }
32
+
33
+ return String(parseInt(chain.chainId));
34
+ }
35
+
36
+ /** Maps a chain reference to a Rango network name using blockchain meta. */
37
+ export function resolveNetworkName(
38
+ chain: string | Chain | null | undefined,
39
+ meta: BlockchainMeta[]
40
+ ): string | undefined {
41
+ const reference = parseChainReference(chain ?? undefined);
42
+ if (!reference) {
43
+ return undefined;
44
+ }
45
+
46
+ return meta.find(
47
+ (blockchain) =>
48
+ isEvmBlockchain(blockchain) &&
49
+ String(parseInt(blockchain.chainId)) === reference
50
+ )?.name;
51
+ }
52
+
53
+ /** Converts a decimal EVM chain reference to the `0x`-prefixed hex expected by hub EVM actions. */
54
+ export function chainReferenceToHex(reference: string): `0x${string}` {
55
+ return `0x${parseInt(reference).toString(HEX_RADIX)}`;
56
+ }
57
+
58
+ /**
59
+ * Converts rango EVM blockchain meta to CAIP-2 chain ids - the only chain data the
60
+ * connect/proposal path needs. This is the single boundary where rango-types' chain
61
+ * shape is translated; everything downstream uses caip's ChainIdParams.
62
+ */
63
+ export function evmMetaToCaipChainIds(meta: BlockchainMeta[]): ChainIdParams[] {
64
+ return meta.filter(isEvmBlockchain).map((blockchain) => ({
65
+ namespace: NAMESPACES.ETHEREUM,
66
+ reference: String(parseInt(blockchain.chainId)),
67
+ }));
68
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * WalletConnect protocol constants shared across the hub path (session/,
3
+ * adapter/, signers/, namespaces/). Kept separate from `constants.ts` (which
4
+ * holds the hub provider identity/metadata) so this module stays a dependency
5
+ * leaf and importing it never pulls in the signer/provider graph (the
6
+ * `WalletConnectNamespace` import below is type-only, so it is erased at runtime).
7
+ */
8
+ import type { WalletConnectNamespace } from './types.js';
9
+
10
+ export const PING_TIMEOUT = 10_000;
11
+
12
+ export enum NAMESPACES {
13
+ ETHEREUM = 'eip155',
14
+ BITCOIN = 'bip122',
15
+ POLKADOT = 'polkadot',
16
+ CARDANO = 'cip34',
17
+ ERLOND = 'elrond',
18
+ MULTIVERSX = 'multiversx',
19
+ }
20
+
21
+ /**
22
+ * Single source of truth for the namespace-alias -> CAIP-2 prefix relationship
23
+ * (`evm -> eip155`, `utxo -> bip122`). `proposals` and `lookup` read from this
24
+ * instead of re-encoding it. `Record<WalletConnectNamespace, …>` makes a new
25
+ * alias a compile error until it's mapped.
26
+ */
27
+ export const WC_NAMESPACE_TO_CAIP: Record<WalletConnectNamespace, string> = {
28
+ evm: NAMESPACES.ETHEREUM,
29
+ utxo: NAMESPACES.BITCOIN,
30
+ };
31
+
32
+ export const CHAIN_ID_STORAGE = 'wc@2:client//namespaces';
33
+
34
+ // Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/ethereum-rpc
35
+ export enum EthereumRPCMethods {
36
+ PERSONAL_SIGN = 'personal_sign',
37
+ SIGN = 'eth_sign',
38
+ SIGN_TYPED_DATA = 'eth_signTypedData',
39
+ SIGN_TRANSACTION = 'eth_signTransaction',
40
+ SEND_TRANSACTION = 'eth_sendTransaction',
41
+ SEND_RAW_TRANSACTION = 'eth_sendRawTransaction',
42
+ SWITCH_CHAIN = 'wallet_switchEthereumChain',
43
+ ADD_CHAIN = 'wallet_addEthereumChain',
44
+ GET_CHAIN = 'eth_chainId',
45
+ }
46
+
47
+ export enum EthereumEvents {
48
+ CHAIN_CHANGED = 'chainChanged',
49
+ ACCOUNTS_CHANGED = 'accountsChanged',
50
+ }
51
+
52
+ export const DEFAULT_ETHEREUM_EVENTS: EthereumEvents[] = [
53
+ EthereumEvents.CHAIN_CHANGED,
54
+ EthereumEvents.ACCOUNTS_CHANGED,
55
+ ];
56
+
57
+ export const DEFAULT_ETHEREUM_METHODS = [
58
+ EthereumRPCMethods.PERSONAL_SIGN,
59
+ EthereumRPCMethods.SEND_TRANSACTION,
60
+ EthereumRPCMethods.SIGN_TRANSACTION,
61
+ EthereumRPCMethods.SWITCH_CHAIN,
62
+ EthereumRPCMethods.ADD_CHAIN,
63
+ EthereumRPCMethods.GET_CHAIN,
64
+ ];
65
+
66
+ // Reference: https://docs.reown.com/advanced/multichain/rpc-reference/bitcoin-rpc
67
+ export enum BitcoinRPCMethods {
68
+ SIGN_PSBT = 'signPsbt',
69
+ GET_ACCOUNT_ADDRESSES = 'getAccountAddresses',
70
+ SIGN_MESSAGE = 'signMessage',
71
+ SEND_TRANSFER = 'sendTransfer',
72
+ }
73
+
74
+ export enum BitcoinEvents {
75
+ ADDRESSES_CHANGED = 'bip122_addressesChanged',
76
+ }
77
+
78
+ export const DEFAULT_BITCOIN_EVENTS: BitcoinEvents[] = [
79
+ BitcoinEvents.ADDRESSES_CHANGED,
80
+ ];
81
+
82
+ export const DEFAULT_BITCOIN_METHODS = [
83
+ BitcoinRPCMethods.SIGN_PSBT,
84
+ BitcoinRPCMethods.GET_ACCOUNT_ADDRESSES,
85
+ ];
86
+
87
+ export const DEFAULT_APP_METADATA = {
88
+ name: 'Rango Exchange',
89
+ description: 'The Ultimate Cross-Chain Solution',
90
+ url: 'https://app.rango.exchange/',
91
+ icons: ['https://app.rango.exchange/logo-rounded.png'],
92
+ };
93
+
94
+ export const RELAY_URL = 'wss://relay.walletconnect.com';
@@ -1,2 +0,0 @@
1
- import{Networks as n}from"@rango-dev/wallets-shared";var T=n.ETHEREUM,A=1e4;var e="wc@2:client//namespaces";var t=["chainChanged","accountsChanged"],N=["personal_sign","eth_sendTransaction","eth_signTransaction","wallet_switchEthereumChain","wallet_addEthereumChain","eth_chainId"];var a="4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ",o={name:"Rango Exchange",description:"The Ultimate Cross-Chain Solution",url:"https://app.rango.exchange/",icons:["https://app.rango.exchange/logo-rounded.png"]},s="wss://relay.walletconnect.com";export{T as a,A as b,e as c,t as d,N as e,a as f,o as g,s as h};
2
- //# sourceMappingURL=chunk-6V3WUFOU.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/constants.ts"],
4
- "sourcesContent": ["import { Networks } from '@rango-dev/wallets-shared';\n\nexport const DEFAULT_NETWORK = Networks.ETHEREUM;\nexport const PING_TIMEOUT = 10_000;\n\nexport enum NAMESPACES {\n ETHEREUM = 'eip155',\n SOLANA = 'solana',\n POLKADOT = 'polkadot',\n CARDANO = 'cip34',\n ERLOND = 'elrond',\n MULTIVERSX = 'multiversx',\n}\n\nexport const CHAIN_ID_STORAGE = 'wc@2:client//namespaces';\n\n// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/solana-rpc\nexport enum SolanaRPCMethods {\n GET_ACCOUNTS = 'solana_getAccounts',\n REQUEST_ACCOUNTS = 'solana_requestAccounts',\n SIGN_TRANSACTION = 'solana_signTransaction',\n SIGN_MESSAGE = 'solana_signMessage',\n}\n\n// Refrence: https://docs.walletconnect.com/2.0/advanced/rpc-reference/ethereum-rpc\nexport enum EthereumRPCMethods {\n PERSONAL_SIGN = 'personal_sign',\n SIGN = 'eth_sign',\n SIGN_TYPED_DATA = 'eth_signTypedData',\n SIGN_TRANSACTION = 'eth_signTransaction',\n SEND_TRANSACTION = 'eth_sendTransaction',\n SEND_RAW_TRANSACTION = 'eth_sendRawTransaction',\n SWITCH_CHAIN = 'wallet_switchEthereumChain',\n ADD_CHAIN = 'wallet_addEthereumChain',\n GET_CHAIN = 'eth_chainId',\n}\n\nexport enum StarknetRPCMethods {\n REQUEST_ADD_INVOKE_TRANSACTION = 'starknet_requestAddInvokeTransaction',\n SIGN_TYPED_DATA = 'starknet_signTypedData',\n}\n\nexport enum EthereumEvents {\n CHAIN_CHANGED = 'chainChanged',\n ACCOUNTS_CHANGED = 'accountsChanged',\n}\n\nexport const DEFAULT_ETHEREUM_EVENTS: EthereumEvents[] = [\n EthereumEvents.CHAIN_CHANGED,\n EthereumEvents.ACCOUNTS_CHANGED,\n];\n\nexport const DEFAULT_ETHEREUM_METHODS = [\n EthereumRPCMethods.PERSONAL_SIGN,\n EthereumRPCMethods.SEND_TRANSACTION,\n EthereumRPCMethods.SIGN_TRANSACTION,\n EthereumRPCMethods.SWITCH_CHAIN,\n EthereumRPCMethods.ADD_CHAIN,\n EthereumRPCMethods.GET_CHAIN,\n];\n\nexport const DEFAULT_SOLANA_METHODS = [\n SolanaRPCMethods.SIGN_TRANSACTION,\n SolanaRPCMethods.SIGN_MESSAGE,\n];\n\n// refrence: https://github.com/ChainAgnostic/namespaces/blob/main/solana/caip2.md\nexport const DEFAULT_SOLANA_CHAIN_ID = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';\n\nexport const DEFAULT_APP_METADATA = {\n name: 'Rango Exchange',\n description: 'The Ultimate Cross-Chain Solution',\n url: 'https://app.rango.exchange/',\n icons: ['https://app.rango.exchange/logo-rounded.png'],\n};\n\nexport const RELAY_URL = 'wss://relay.walletconnect.com';\n"],
5
- "mappings": "AAAA,OAAS,YAAAA,MAAgB,4BAElB,IAAMC,EAAkBD,EAAS,SAC3BE,EAAe,IAWrB,IAAMC,EAAmB,0BAiCzB,IAAMC,EAA4C,CACvD,eACA,iBACF,EAEaC,EAA2B,CACtC,gBACA,sBACA,sBACA,6BACA,0BACA,aACF,EAQO,IAAMC,EAA0B,mCAE1BC,EAAuB,CAClC,KAAM,iBACN,YAAa,oCACb,IAAK,8BACL,MAAO,CAAC,6CAA6C,CACvD,EAEaC,EAAY",
6
- "names": ["Networks", "DEFAULT_NETWORK", "PING_TIMEOUT", "CHAIN_ID_STORAGE", "DEFAULT_ETHEREUM_EVENTS", "DEFAULT_ETHEREUM_METHODS", "DEFAULT_SOLANA_CHAIN_ID", "DEFAULT_APP_METADATA", "RELAY_URL"]
7
- }