walletpair-sdk 1.0.2 → 1.0.5

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 (74) hide show
  1. package/README.md +13 -0
  2. package/dist/ble/framing.d.ts.map +1 -1
  3. package/dist/ble/framing.js +2 -2
  4. package/dist/ble/framing.js.map +1 -1
  5. package/dist/ble/index.d.ts +2 -2
  6. package/dist/ble/index.d.ts.map +1 -1
  7. package/dist/ble/index.js +2 -2
  8. package/dist/ble/index.js.map +1 -1
  9. package/dist/ble/web-ble-transport.d.ts +1 -1
  10. package/dist/ble/web-ble-transport.d.ts.map +1 -1
  11. package/dist/ble/web-ble-transport.js +23 -12
  12. package/dist/ble/web-ble-transport.js.map +1 -1
  13. package/dist/crypto.d.ts.map +1 -1
  14. package/dist/crypto.js +29 -12
  15. package/dist/crypto.js.map +1 -1
  16. package/dist/dapp-session.d.ts.map +1 -1
  17. package/dist/dapp-session.js +15 -5
  18. package/dist/dapp-session.js.map +1 -1
  19. package/dist/emitter.d.ts +1 -3
  20. package/dist/emitter.d.ts.map +1 -1
  21. package/dist/emitter.js +4 -2
  22. package/dist/emitter.js.map +1 -1
  23. package/dist/evm/eip1193.d.ts +2 -2
  24. package/dist/evm/eip1193.d.ts.map +1 -1
  25. package/dist/evm/eip1193.js +32 -18
  26. package/dist/evm/eip1193.js.map +1 -1
  27. package/dist/evm/index.d.ts +2 -2
  28. package/dist/evm/index.d.ts.map +1 -1
  29. package/dist/evm/index.js.map +1 -1
  30. package/dist/wallet-session.d.ts.map +1 -1
  31. package/dist/wallet-session.js +4 -3
  32. package/dist/wallet-session.js.map +1 -1
  33. package/dist/ws-transport.d.ts +3 -2
  34. package/dist/ws-transport.d.ts.map +1 -1
  35. package/dist/ws-transport.js +13 -4
  36. package/dist/ws-transport.js.map +1 -1
  37. package/package.json +20 -1
  38. package/src/__tests__/adversarial/crypto-attacks.test.ts +240 -233
  39. package/src/__tests__/adversarial/malicious-dapp.test.ts +228 -194
  40. package/src/__tests__/adversarial/malicious-relay.test.ts +292 -220
  41. package/src/__tests__/adversarial/malicious-wallet.test.ts +246 -180
  42. package/src/__tests__/spec-compliance/canonical-json.test.ts +105 -105
  43. package/src/__tests__/spec-compliance/crypto-vectors.test.ts +149 -154
  44. package/src/__tests__/spec-compliance/message-format.test.ts +180 -151
  45. package/src/__tests__/spec-compliance/sequence-numbers.test.ts +142 -149
  46. package/src/__tests__/spec-compliance/state-machine.test.ts +203 -180
  47. package/src/ble/framing.test.ts +122 -114
  48. package/src/ble/framing.ts +48 -51
  49. package/src/ble/index.ts +7 -7
  50. package/src/ble/web-ble-transport.test.ts +93 -84
  51. package/src/ble/web-ble-transport.ts +70 -57
  52. package/src/ble/web-bluetooth.d.ts +19 -19
  53. package/src/canonical-json.test.ts +301 -285
  54. package/src/crypto-directional.test.ts +155 -129
  55. package/src/crypto-hardening.test.ts +292 -283
  56. package/src/crypto.test.ts +364 -346
  57. package/src/crypto.ts +185 -175
  58. package/src/dapp-session.test.ts +522 -385
  59. package/src/dapp-session.ts +17 -11
  60. package/src/emitter.test.ts +122 -122
  61. package/src/emitter.ts +20 -18
  62. package/src/evm/eip1193.test.ts +283 -205
  63. package/src/evm/eip1193.ts +162 -138
  64. package/src/evm/index.ts +5 -5
  65. package/src/evm/wagmi.test.ts +1 -1
  66. package/src/integration.test.ts +329 -201
  67. package/src/security.test.ts +331 -238
  68. package/src/sequence-validation.test.ts +6 -9
  69. package/src/test-helpers.ts +102 -78
  70. package/src/types.test.ts +45 -50
  71. package/src/wallet-session.test.ts +611 -383
  72. package/src/wallet-session.ts +7 -9
  73. package/src/ws-transport.test.ts +141 -139
  74. package/src/ws-transport.ts +52 -41
@@ -9,32 +9,32 @@
9
9
  * const provider = new WalletPairProvider({ session })
10
10
  */
11
11
 
12
- import type { DAppSession } from '../dapp-session.js';
13
- import { evmNumericChainId } from '../types.js';
14
- import { Emitter } from '../emitter.js';
12
+ import type { DAppSession } from '../dapp-session.js'
13
+ import { Emitter } from '../emitter.js'
14
+ import { evmNumericChainId } from '../types.js'
15
15
 
16
16
  // ---------------------------------------------------------------------------
17
17
  // EIP-1193 types
18
18
  // ---------------------------------------------------------------------------
19
19
 
20
20
  export interface EIP1193RequestArgs {
21
- method: string;
22
- params?: unknown[] | Record<string, unknown>;
21
+ method: string
22
+ params?: unknown[] | Record<string, unknown>
23
23
  }
24
24
 
25
25
  export interface EIP1193ProviderEvents {
26
- [key: string]: unknown;
27
- connect: { chainId: string };
28
- disconnect: { code: number; message: string };
29
- chainChanged: string;
30
- accountsChanged: string[];
31
- message: { type: string; data?: unknown | undefined };
26
+ [key: string]: unknown
27
+ connect: { chainId: string }
28
+ disconnect: { code: number; message: string }
29
+ chainChanged: string
30
+ accountsChanged: string[]
31
+ message: { type: string; data?: unknown | undefined }
32
32
  }
33
33
 
34
34
  export interface EIP1193Provider {
35
- request(args: EIP1193RequestArgs): Promise<unknown>;
36
- on(event: string, handler: (...args: any[]) => void): void;
37
- removeListener(event: string, handler: (...args: any[]) => void): void;
35
+ request(args: EIP1193RequestArgs): Promise<unknown>
36
+ on(event: string, handler: (...args: unknown[]) => void): void
37
+ removeListener(event: string, handler: (...args: unknown[]) => void): void
38
38
  }
39
39
 
40
40
  // ---------------------------------------------------------------------------
@@ -42,24 +42,26 @@ export interface EIP1193Provider {
42
42
  // ---------------------------------------------------------------------------
43
43
 
44
44
  export interface MethodMapper {
45
- mapRequest(method: string, params?: unknown): { method: string; params?: unknown | undefined } | null;
46
- mapResponse(method: string, result: unknown): unknown;
45
+ mapRequest(
46
+ method: string,
47
+ params?: unknown,
48
+ ): { method: string; params?: unknown | undefined } | null
49
+ mapResponse(method: string, result: unknown): unknown
47
50
  }
48
51
 
49
52
  /** Convert hex chainId "0x89" to CAIP-2 "eip155:137". */
50
53
  function hexChainToCaip2(hex: string): string {
51
- return `eip155:${Number.parseInt(hex, 16)}`;
54
+ return `eip155:${Number.parseInt(hex, 16)}`
52
55
  }
53
56
 
54
57
  /** Validate that a transaction object contains all required fields. */
55
58
  function validateTxFields(tx: Record<string, unknown> | undefined): void {
56
- const required = ['value', 'data', 'type', 'chainId'];
57
- const missing = required.filter(f => tx?.[f] === undefined || tx?.[f] === null);
59
+ const required = ['value', 'data', 'type', 'chainId']
60
+ const missing = required.filter((f) => tx?.[f] === undefined || tx?.[f] === null)
58
61
  if (missing.length > 0) {
59
- throw Object.assign(
60
- new Error(`Missing required transaction fields: ${missing.join(', ')}`),
61
- { code: -32602 },
62
- );
62
+ throw Object.assign(new Error(`Missing required transaction fields: ${missing.join(', ')}`), {
63
+ code: -32602,
64
+ })
63
65
  }
64
66
  }
65
67
 
@@ -68,86 +70,92 @@ const defaultMapper: MethodMapper = {
68
70
  switch (method) {
69
71
  case 'eth_requestAccounts':
70
72
  case 'eth_accounts':
71
- return { method: 'wallet_getAccounts' };
73
+ return { method: 'wallet_getAccounts' }
72
74
  case 'personal_sign': {
73
75
  // personal_sign params: [message, address] where message is hex-encoded bytes
74
- const p = params as [string, string] | undefined;
75
- const msg = p?.[0];
76
+ const p = params as [string, string] | undefined
77
+ const msg = p?.[0]
76
78
  // EIP-1193 personal_sign: message is always hex-encoded bytes.
77
79
  // Decode hex to UTF-8 text and route to wallet_signMessage.
78
- let text = msg ?? '';
79
- if (msg && msg.startsWith('0x')) {
80
+ let text = msg ?? ''
81
+ if (msg?.startsWith('0x')) {
80
82
  try {
81
- const hex = msg.slice(2);
82
- const bytes = new Uint8Array(hex.length / 2);
83
+ const hex = msg.slice(2)
84
+ const bytes = new Uint8Array(hex.length / 2)
83
85
  for (let i = 0; i < bytes.length; i++) {
84
- bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
86
+ bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16)
85
87
  }
86
- text = new TextDecoder().decode(bytes);
88
+ text = new TextDecoder().decode(bytes)
87
89
  } catch {
88
- text = msg;
90
+ text = msg
89
91
  }
90
92
  }
91
- return { method: 'wallet_signMessage', params: { message: text, address: p?.[1] } };
93
+ return { method: 'wallet_signMessage', params: { message: text, address: p?.[1] } }
92
94
  }
93
95
  case 'eth_signTypedData_v4': {
94
96
  // params: [address, typedDataJSON]
95
- const p = params as [string, string] | undefined;
96
- let typedData: unknown;
97
- try { typedData = typeof p?.[1] === 'string' ? JSON.parse(p[1]) : p?.[1]; }
98
- catch { typedData = p?.[1]; }
99
- return { method: 'wallet_signTypedData', params: { address: p?.[0], typedData } };
97
+ const p = params as [string, string] | undefined
98
+ let typedData: unknown
99
+ try {
100
+ typedData = typeof p?.[1] === 'string' ? JSON.parse(p[1]) : p?.[1]
101
+ } catch {
102
+ typedData = p?.[1]
103
+ }
104
+ return { method: 'wallet_signTypedData', params: { address: p?.[0], typedData } }
100
105
  }
101
106
  case 'eth_sendTransaction': {
102
107
  // params: [txObject] — maps to wallet_sendTransaction (sign + broadcast)
103
- const p = params as [Record<string, unknown>] | undefined;
104
- const tx = p?.[0];
105
- validateTxFields(tx);
106
- return { method: 'wallet_sendTransaction', params: { address: tx?.from, tx } };
108
+ const p = params as [Record<string, unknown>] | undefined
109
+ const tx = p?.[0]
110
+ validateTxFields(tx)
111
+ return { method: 'wallet_sendTransaction', params: { address: tx?.from, tx } }
107
112
  }
108
113
  case 'eth_signTransaction': {
109
114
  // params: [txObject] — maps to wallet_signTransaction (sign only)
110
- const p = params as [Record<string, unknown>] | undefined;
111
- const tx = p?.[0];
112
- validateTxFields(tx);
113
- return { method: 'wallet_signTransaction', params: { address: tx?.from, tx } };
115
+ const p = params as [Record<string, unknown>] | undefined
116
+ const tx = p?.[0]
117
+ validateTxFields(tx)
118
+ return { method: 'wallet_signTransaction', params: { address: tx?.from, tx } }
114
119
  }
115
120
  case 'wallet_switchEthereumChain': {
116
121
  // params: [{ chainId: "0x89" }] — convert hex to CAIP-2
117
- const p = params as [{ chainId: string }] | undefined;
118
- const hexId = p?.[0]?.chainId;
119
- return { method: 'wallet_switchChain', params: { chain: hexId ? hexChainToCaip2(hexId) : undefined } };
122
+ const p = params as [{ chainId: string }] | undefined
123
+ const hexId = p?.[0]?.chainId
124
+ return {
125
+ method: 'wallet_switchChain',
126
+ params: { chain: hexId ? hexChainToCaip2(hexId) : undefined },
127
+ }
120
128
  }
121
129
  case 'wallet_addEthereumChain':
122
- return null; // unsupported — mapRequest returning null triggers unsupported_method error
130
+ return null // unsupported — mapRequest returning null triggers unsupported_method error
123
131
  default:
124
- return null; // unknown method — routed to rpcProvider or rejected before reaching here
132
+ return null // unknown method — routed to rpcProvider or rejected before reaching here
125
133
  }
126
134
  },
127
135
  mapResponse(method, result) {
128
136
  // Unwrap wallet_getAccounts result to EIP-1193 format (string[])
129
137
  if (method === 'eth_requestAccounts' || method === 'eth_accounts') {
130
- const r = result as { accounts?: { address: string }[] } | undefined;
131
- if (r?.accounts) return r.accounts.map((a) => a.address);
138
+ const r = result as { accounts?: { address: string }[] } | undefined
139
+ if (r?.accounts) return r.accounts.map((a) => a.address)
132
140
  }
133
141
  // Unwrap wallet_sendTransaction result
134
142
  if (method === 'eth_sendTransaction') {
135
- const r = result as { txHash?: string } | undefined;
136
- if (r?.txHash) return r.txHash;
143
+ const r = result as { txHash?: string } | undefined
144
+ if (r?.txHash) return r.txHash
137
145
  }
138
146
  // Unwrap wallet_signTransaction result
139
147
  if (method === 'eth_signTransaction') {
140
- const r = result as { signedTx?: string } | undefined;
141
- if (r?.signedTx) return r.signedTx;
148
+ const r = result as { signedTx?: string } | undefined
149
+ if (r?.signedTx) return r.signedTx
142
150
  }
143
151
  // Unwrap signature results
144
152
  if (method === 'personal_sign' || method === 'eth_signTypedData_v4') {
145
- const r = result as { signature?: string } | undefined;
146
- if (r?.signature) return r.signature;
153
+ const r = result as { signature?: string } | undefined
154
+ if (r?.signature) return r.signature
147
155
  }
148
- return result;
156
+ return result
149
157
  },
150
- };
158
+ }
151
159
 
152
160
  // ---------------------------------------------------------------------------
153
161
  // RPC routing: wallet methods vs read-only RPC
@@ -155,24 +163,26 @@ const defaultMapper: MethodMapper = {
155
163
 
156
164
  /** Methods that MUST go through WalletPair (require wallet signing/authorization). */
157
165
  const WALLET_METHODS = new Set([
158
- 'eth_requestAccounts', 'eth_accounts',
166
+ 'eth_requestAccounts',
167
+ 'eth_accounts',
159
168
  'personal_sign',
160
- 'eth_signTypedData_v4', 'eth_signTypedData_v3',
161
- 'eth_sendTransaction', 'eth_signTransaction',
162
- 'wallet_switchEthereumChain', 'wallet_addEthereumChain',
163
- ]);
169
+ 'eth_signTypedData_v4',
170
+ 'eth_signTypedData_v3',
171
+ 'eth_sendTransaction',
172
+ 'eth_signTransaction',
173
+ 'wallet_switchEthereumChain',
174
+ 'wallet_addEthereumChain',
175
+ ])
164
176
 
165
177
  /** Methods handled locally by the provider (no RPC or WalletPair needed). */
166
- const LOCAL_METHODS = new Set([
167
- 'eth_chainId', 'net_version',
168
- ]);
178
+ const LOCAL_METHODS = new Set(['eth_chainId', 'net_version'])
169
179
 
170
180
  /**
171
181
  * An RPC provider that handles read-only Ethereum JSON-RPC calls.
172
182
  * Pass any EIP-1193-compatible provider, or a simple fetch-based JSON-RPC client.
173
183
  */
174
184
  export interface RpcProvider {
175
- request(args: EIP1193RequestArgs): Promise<unknown>;
185
+ request(args: EIP1193RequestArgs): Promise<unknown>
176
186
  }
177
187
 
178
188
  // ---------------------------------------------------------------------------
@@ -180,167 +190,181 @@ export interface RpcProvider {
180
190
  // ---------------------------------------------------------------------------
181
191
 
182
192
  export interface WalletPairProviderOptions {
183
- session: DAppSession;
193
+ session: DAppSession
184
194
  /** Initial EVM chain ID (numeric). Default 1 (mainnet). */
185
- chainId?: number | undefined;
195
+ chainId?: number | undefined
186
196
  /** Custom method mapper. */
187
- mapper?: MethodMapper | undefined;
197
+ mapper?: MethodMapper | undefined
188
198
  /**
189
199
  * Optional RPC provider for read-only methods (eth_call, eth_getBalance,
190
200
  * eth_blockNumber, etc.). If provided, any method not handled by WalletPair
191
201
  * is routed here instead of being sent to the wallet. If omitted, unknown
192
202
  * methods throw unsupported_method (4200).
193
203
  */
194
- rpcProvider?: RpcProvider | undefined;
204
+ rpcProvider?: RpcProvider | undefined
195
205
  }
196
206
 
197
207
  export class WalletPairProvider implements EIP1193Provider {
198
- private session: DAppSession;
199
- private mapper: MethodMapper;
200
- private rpcProvider: RpcProvider | undefined;
201
- private emitter = new Emitter<EIP1193ProviderEvents>();
202
- private chainId: number;
203
- private accounts: string[] = [];
204
- private connected = false;
205
- private disconnected = false;
208
+ private session: DAppSession
209
+ private mapper: MethodMapper
210
+ private rpcProvider: RpcProvider | undefined
211
+ private emitter = new Emitter<EIP1193ProviderEvents>()
212
+ private chainId: number
213
+ private accounts: string[] = []
214
+ private connected = false
215
+ private disconnected = false
206
216
 
207
217
  constructor(options: WalletPairProviderOptions) {
208
- this.session = options.session;
209
- this.mapper = options.mapper ?? defaultMapper;
210
- this.rpcProvider = options.rpcProvider;
211
- this.chainId = options.chainId ?? 1;
218
+ this.session = options.session
219
+ this.mapper = options.mapper ?? defaultMapper
220
+ this.rpcProvider = options.rpcProvider
221
+ this.chainId = options.chainId ?? 1
212
222
 
213
223
  this.session.on('phase', (phase) => {
214
224
  if (phase === 'connected' && !this.connected) {
215
- this.connected = true;
216
- this.emitter.emit('connect', { chainId: `0x${this.chainId.toString(16)}` });
225
+ this.connected = true
226
+ this.emitter.emit('connect', { chainId: `0x${this.chainId.toString(16)}` })
217
227
  } else if ((phase === 'closed' || phase === 'disconnected') && this.connected) {
218
- this.connected = false;
219
- this.emitter.emit('disconnect', { code: 4900, message: 'Disconnected' });
228
+ this.connected = false
229
+ this.emitter.emit('disconnect', { code: 4900, message: 'Disconnected' })
220
230
  }
221
- });
231
+ })
222
232
 
223
233
  this.session.on('event', ({ event, data }) => {
224
234
  if (event === 'disconnect') {
225
- this.connected = false;
226
- this.disconnected = true;
227
- const reason = (data as any)?.reason ?? 'unknown';
228
- const msg = (data as any)?.message ?? `Disconnected by wallet (${reason})`;
229
- this.emitter.emit('disconnect', { code: 4900, message: msg });
230
- this.session.close('normal');
231
- return;
235
+ this.connected = false
236
+ this.disconnected = true
237
+ const d = data as Record<string, unknown>
238
+ const reason = String(d?.reason ?? 'unknown')
239
+ const msg =
240
+ typeof d?.message === 'string' ? d.message : `Disconnected by wallet (${reason})`
241
+ this.emitter.emit('disconnect', { code: 4900, message: msg })
242
+ this.session.close('normal')
243
+ return
232
244
  }
233
245
  if (event === 'accountsChanged') {
234
246
  // Handle both formats:
235
247
  // - Simple: { accounts: ['0x...'] } or just ['0x...']
236
248
  // - Sub-protocol: { accounts: [{ address: '0x...', chains?: [...] }] }
237
- const payload = data as { accounts?: (string | { address: string })[] } | string[];
238
- const rawAccounts = Array.isArray(payload) ? payload : (payload as any)?.accounts;
249
+ const payload = data as { accounts?: (string | { address: string })[] } | string[]
250
+ const rawAccounts = Array.isArray(payload) ? payload : payload?.accounts
239
251
  if (Array.isArray(rawAccounts)) {
240
252
  this.accounts = rawAccounts.map((a: string | { address: string }) =>
241
253
  typeof a === 'string' ? a : a.address,
242
- );
243
- this.emitter.emit('accountsChanged', this.accounts);
254
+ )
255
+ this.emitter.emit('accountsChanged', this.accounts)
244
256
  }
245
257
  } else if (event === 'chainChanged') {
246
258
  // Handle multiple formats:
247
259
  // - { chainId: 'eip155:137' } or { chainId: '0x89' } or { chainId: 137 }
248
260
  // - { chain: 'eip155:137' }
249
261
  // - raw string 'eip155:137' or '0x89'
250
- const raw = typeof data === 'object' && data !== null
251
- ? (data as any).chainId ?? (data as any).chain
252
- : data;
253
- let newChainId: number | null = null;
262
+ const raw =
263
+ typeof data === 'object' && data !== null
264
+ ? ((data as Record<string, unknown>).chainId ?? (data as Record<string, unknown>).chain)
265
+ : data
266
+ let newChainId: number | null = null
254
267
  if (typeof raw === 'string') {
255
268
  if (raw.startsWith('eip155:')) {
256
- newChainId = evmNumericChainId(raw);
269
+ newChainId = evmNumericChainId(raw)
257
270
  } else if (raw.startsWith('0x')) {
258
- newChainId = Number.parseInt(raw, 16);
271
+ newChainId = Number.parseInt(raw, 16)
259
272
  } else {
260
- newChainId = Number.parseInt(raw, 10) || null;
273
+ newChainId = Number.parseInt(raw, 10) || null
261
274
  }
262
275
  } else if (typeof raw === 'number') {
263
- newChainId = raw;
276
+ newChainId = raw
264
277
  }
265
278
  if (newChainId != null && newChainId !== this.chainId) {
266
- this.chainId = newChainId;
267
- this.emitter.emit('chainChanged', `0x${newChainId.toString(16)}`);
279
+ this.chainId = newChainId
280
+ this.emitter.emit('chainChanged', `0x${newChainId.toString(16)}`)
268
281
  }
269
282
  }
270
- });
283
+ })
271
284
  }
272
285
 
273
286
  async request(args: EIP1193RequestArgs): Promise<unknown> {
274
287
  if (this.disconnected) {
275
- throw Object.assign(new Error('Provider is disconnected'), { code: 4900 });
288
+ throw Object.assign(new Error('Provider is disconnected'), { code: 4900 })
276
289
  }
277
290
 
278
- const { method, params } = args;
291
+ const { method, params } = args
279
292
 
280
293
  if (method === 'eth_chainId') {
281
- return `0x${this.chainId.toString(16)}`;
294
+ return `0x${this.chainId.toString(16)}`
282
295
  }
283
296
  if (method === 'net_version') {
284
- return String(this.chainId);
297
+ return String(this.chainId)
285
298
  }
286
299
 
287
300
  // Route non-wallet methods to RPC provider if available
288
301
  if (!WALLET_METHODS.has(method) && !LOCAL_METHODS.has(method)) {
289
302
  if (this.rpcProvider) {
290
- return this.rpcProvider.request(args);
303
+ return this.rpcProvider.request(args)
291
304
  }
292
- throw Object.assign(new Error(`Unsupported method: ${method}. Pass rpcProvider to handle read-only RPC calls.`), { code: 4200 });
305
+ throw Object.assign(
306
+ new Error(`Unsupported method: ${method}. Pass rpcProvider to handle read-only RPC calls.`),
307
+ { code: 4200 },
308
+ )
293
309
  }
294
310
 
295
- const mapped = this.mapper.mapRequest(method, params);
311
+ const mapped = this.mapper.mapRequest(method, params)
296
312
  if (!mapped) {
297
- throw Object.assign(new Error(`Unsupported method: ${method}`), { code: 4200 });
313
+ throw Object.assign(new Error(`Unsupported method: ${method}`), { code: 4200 })
298
314
  }
299
315
 
300
316
  // Inject chain for methods that require it per EVM sub-protocol
301
317
  const chainRequiredMethods = [
302
- 'wallet_signMessage', 'wallet_signTypedData',
303
- 'wallet_signTransaction', 'wallet_sendTransaction',
318
+ 'wallet_signMessage',
319
+ 'wallet_signTypedData',
320
+ 'wallet_signTransaction',
321
+ 'wallet_sendTransaction',
304
322
  'wallet_getAccounts',
305
- ];
306
- if (mapped.params && typeof mapped.params === 'object' && chainRequiredMethods.includes(mapped.method)) {
307
- const p = mapped.params as Record<string, unknown>;
323
+ ]
324
+ if (
325
+ mapped.params &&
326
+ typeof mapped.params === 'object' &&
327
+ chainRequiredMethods.includes(mapped.method)
328
+ ) {
329
+ const p = mapped.params as Record<string, unknown>
308
330
  if (!p.chain) {
309
- p.chain = `eip155:${this.chainId}`;
331
+ p.chain = `eip155:${this.chainId}`
310
332
  }
311
333
  }
312
334
 
313
- const result = await this.session.request(mapped.method, mapped.params);
314
- const mappedResult = this.mapper.mapResponse(method, result);
335
+ const result = await this.session.request(mapped.method, mapped.params)
336
+ const mappedResult = this.mapper.mapResponse(method, result)
315
337
 
316
338
  if (method === 'eth_requestAccounts' || method === 'eth_accounts') {
317
- if (Array.isArray(mappedResult)) this.accounts = mappedResult;
339
+ if (Array.isArray(mappedResult)) this.accounts = mappedResult
318
340
  }
319
341
 
320
- return mappedResult;
342
+ return mappedResult
321
343
  }
322
344
 
345
+ // biome-ignore lint/suspicious/noExplicitAny: EIP-1193 interface requires generic handler signature
323
346
  on(event: string, handler: (...args: any[]) => void): void {
324
- this.emitter.on(event as keyof EIP1193ProviderEvents, handler as any);
347
+ this.emitter.on(event as keyof EIP1193ProviderEvents, handler as (data: unknown) => void)
325
348
  }
326
349
 
350
+ // biome-ignore lint/suspicious/noExplicitAny: EIP-1193 interface requires generic handler signature
327
351
  removeListener(event: string, handler: (...args: any[]) => void): void {
328
- this.emitter.off(event as keyof EIP1193ProviderEvents, handler as any);
352
+ this.emitter.off(event as keyof EIP1193ProviderEvents, handler as (data: unknown) => void)
329
353
  }
330
354
 
331
355
  getChainId(): string {
332
- return `0x${this.chainId.toString(16)}`;
356
+ return `0x${this.chainId.toString(16)}`
333
357
  }
334
358
 
335
359
  getAccounts(): string[] {
336
- return this.accounts;
360
+ return this.accounts
337
361
  }
338
362
 
339
363
  isConnected(): boolean {
340
- return this.connected;
364
+ return this.connected
341
365
  }
342
366
 
343
367
  getSession(): DAppSession {
344
- return this.session;
368
+ return this.session
345
369
  }
346
370
  }
package/src/evm/index.ts CHANGED
@@ -5,15 +5,15 @@
5
5
  */
6
6
 
7
7
  export {
8
- WalletPairProvider,
9
- type WalletPairProviderOptions,
10
8
  type EIP1193Provider,
11
9
  type EIP1193ProviderEvents,
12
10
  type EIP1193RequestArgs,
13
11
  type MethodMapper,
14
- } from './eip1193.js';
12
+ WalletPairProvider,
13
+ type WalletPairProviderOptions,
14
+ } from './eip1193.js'
15
15
 
16
16
  export {
17
- walletPair,
18
17
  type WalletPairConnectorOptions,
19
- } from './wagmi.js';
18
+ walletPair,
19
+ } from './wagmi.js'
@@ -391,6 +391,6 @@ describe('walletPair connector factory', () => {
391
391
 
392
392
  // switchChain will fail because session isn't connected, but the chain validation
393
393
  // happens after the request. We test the error path.
394
- await expect(connector.switchChain!({ chainId: 999 })).rejects.toThrow()
394
+ await expect(connector.switchChain?.({ chainId: 999 })).rejects.toThrow()
395
395
  })
396
396
  })