@etherplay/wallet-connector-ethereum 0.0.4 → 0.0.6

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.
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # @etherplay/wallet-connector-ethereum
2
+
3
+ Ethereum wallet connector implementation for the `@etherplay/connect` ecosystem. This package provides EIP-6963 provider detection, account management, and chain switching support for Ethereum-compatible wallets.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @etherplay/wallet-connector-ethereum
9
+ # or
10
+ pnpm add @etherplay/wallet-connector-ethereum
11
+ # or
12
+ yarn add @etherplay/wallet-connector-ethereum
13
+ ```
14
+
15
+ ## Features
16
+
17
+ - **EIP-6963 Support**: Automatic detection of multiple wallet providers via the EIP-6963 standard
18
+ - **Account Generation**: Generate Ethereum accounts from BIP-39 mnemonics using standard derivation paths (m/44'/60'/0'/0/x)
19
+ - **Message Signing**: Support for EIP-191 personal_sign messages
20
+ - **Chain Management**: Switch and add Ethereum chains
21
+ - **Always-On Provider**: Fallback RPC provider for read operations
22
+
23
+ ## Usage
24
+
25
+ ### Basic Setup
26
+
27
+ ```typescript
28
+ import {EthereumWalletConnector} from '@etherplay/wallet-connector-ethereum';
29
+
30
+ const connector = new EthereumWalletConnector();
31
+
32
+ // Fetch available wallets (EIP-6963)
33
+ connector.fetchWallets((walletHandle) => {
34
+ console.log('Wallet found:', walletHandle.info.name);
35
+ // walletHandle.walletProvider is ready to use
36
+ });
37
+ ```
38
+
39
+ ### Account Generation
40
+
41
+ Generate Ethereum accounts from a BIP-39 mnemonic phrase:
42
+
43
+ ```typescript
44
+ const connector = new EthereumWalletConnector();
45
+
46
+ // Generate account at index 0
47
+ const account = connector.accountGenerator.fromMnemonicToAccount(
48
+ 'your twelve word mnemonic phrase goes here and more words',
49
+ 0,
50
+ );
51
+
52
+ console.log(account.address); // 0x...
53
+ console.log(account.publicKey); // 0x...
54
+ console.log(account.privateKey); // 0x...
55
+ ```
56
+
57
+ ### Message Signing
58
+
59
+ Sign messages using EIP-191 personal_sign:
60
+
61
+ ```typescript
62
+ const connector = new EthereumWalletConnector();
63
+
64
+ const signature = await connector.accountGenerator.signTextMessage('Hello, Ethereum!', account.privateKey);
65
+ ```
66
+
67
+ ### Always-On Provider
68
+
69
+ Create a provider that falls back to an RPC endpoint when no wallet is connected:
70
+
71
+ ```typescript
72
+ const connector = new EthereumWalletConnector();
73
+
74
+ const provider = connector.createAlwaysOnProvider({
75
+ endpoint: 'https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY',
76
+ chainId: '1',
77
+ prioritizeWalletProvider: true, // Use wallet if available
78
+ requestsPerSecond: 10,
79
+ });
80
+
81
+ // The provider can now be used for read operations
82
+ // even when no wallet is connected
83
+ ```
84
+
85
+ ### Wallet Provider Operations
86
+
87
+ ```typescript
88
+ connector.fetchWallets(async (walletHandle) => {
89
+ const {walletProvider} = walletHandle;
90
+
91
+ // Request account access
92
+ const accounts = await walletProvider.requestAccounts();
93
+
94
+ // Get current chain
95
+ const chainId = await walletProvider.getChainId();
96
+
97
+ // Sign a message
98
+ const signature = await walletProvider.signMessage('Sign this message', accounts[0]);
99
+
100
+ // Switch to a different chain
101
+ await walletProvider.switchChain('0x89'); // Polygon
102
+
103
+ // Add a new chain
104
+ await walletProvider.addChain({
105
+ chainId: '0x89',
106
+ chainName: 'Polygon Mainnet',
107
+ rpcUrls: ['https://polygon-rpc.com'],
108
+ nativeCurrency: {
109
+ name: 'MATIC',
110
+ symbol: 'MATIC',
111
+ decimals: 18,
112
+ },
113
+ blockExplorerUrls: ['https://polygonscan.com'],
114
+ });
115
+
116
+ // Listen for account changes
117
+ walletProvider.listenForAccountsChanged((accounts) => {
118
+ console.log('Accounts changed:', accounts);
119
+ });
120
+
121
+ // Listen for chain changes
122
+ walletProvider.listenForChainChanged((chainId) => {
123
+ console.log('Chain changed:', chainId);
124
+ });
125
+ });
126
+ ```
127
+
128
+ ## API Reference
129
+
130
+ ### EthereumWalletConnector
131
+
132
+ Main connector class implementing `WalletConnector<CurriedRPC<Methods>>`:
133
+
134
+ ```typescript
135
+ class EthereumWalletConnector {
136
+ accountGenerator: AccountGenerator;
137
+ fetchWallets(walletAnnounced: (walletHandle: WalletHandle<CurriedRPC<Methods>>) => void): void;
138
+ createAlwaysOnProvider(params: {
139
+ endpoint: string | UnderlyingEthereumProvider;
140
+ chainId: string;
141
+ prioritizeWalletProvider?: boolean;
142
+ requestsPerSecond?: number;
143
+ }): AlwaysOnProviderWrapper<CurriedRPC<Methods>>;
144
+ }
145
+ ```
146
+
147
+ ### EthereumAccountGenerator
148
+
149
+ Account generator for Ethereum using BIP-32/BIP-39 standards:
150
+
151
+ ```typescript
152
+ class EthereumAccountGenerator implements AccountGenerator {
153
+ type: 'ethereum';
154
+ fromMnemonicToAccount(mnemonic: string, index: number): PrivateKeyAccount;
155
+ signTextMessage(message: string, privateKey: `0x${string}`): Promise<`0x${string}`>;
156
+ }
157
+ ```
158
+
159
+ ### EthereumWalletProvider
160
+
161
+ Wrapper for EIP-1193 wallet providers:
162
+
163
+ ```typescript
164
+ class EthereumWalletProvider implements WalletProvider<CurriedRPC<Methods>> {
165
+ underlyingProvider: CurriedRPC<Methods>;
166
+ signMessage(message: string, account: `0x${string}`): Promise<`0x${string}`>;
167
+ getChainId(): Promise<`0x${string}`>;
168
+ getAccounts(): Promise<`0x${string}`[]>;
169
+ requestAccounts(): Promise<`0x${string}`[]>;
170
+ listenForAccountsChanged(handler: (accounts: `0x${string}`[]) => void): void;
171
+ stopListenForAccountsChanged(handler: (accounts: `0x${string}`[]) => void): void;
172
+ listenForChainChanged(handler: (chainId: `0x${string}`) => void): void;
173
+ stopListenForChainChanged(handler: (chainId: `0x${string}`) => void): void;
174
+ switchChain(chainId: string): Promise<null | any>;
175
+ addChain(chainInfo: ChainInfo): Promise<null | any>;
176
+ }
177
+ ```
178
+
179
+ ## Utility Functions
180
+
181
+ ```typescript
182
+ // Add 0x prefix to hex string
183
+ add0x(hex: string): string;
184
+
185
+ // Remove 0x prefix from hex string
186
+ strip0x(hex: string): string;
187
+
188
+ // Get checksummed address
189
+ addChecksum(nonChecksummedAddress: string): string;
190
+
191
+ // Derive address from public key
192
+ fromPublicKey(key: string | Uint8Array): string;
193
+
194
+ // Derive address from private key
195
+ fromPrivateKey(key: string | Uint8Array): string;
196
+
197
+ // Hash a text message for signing (EIP-191)
198
+ hashTextMessage(str: string): string;
199
+
200
+ // Derive HD key from mnemonic
201
+ fromMnemonicToHDKey(mnemonic: string, index: number): HDKey;
202
+ ```
203
+
204
+ ## Dependencies
205
+
206
+ - `@etherplay/wallet-connector` - Core interfaces
207
+ - `@noble/curves` - Cryptographic curve operations
208
+ - `@noble/hashes` - Hash functions
209
+ - `@scure/bip32` - HD wallet derivation
210
+ - `@scure/bip39` - Mnemonic phrase handling
211
+ - `remote-procedure-call` - RPC utilities
212
+
213
+ ## Related Packages
214
+
215
+ - [`@etherplay/wallet-connector`](../etherplay-wallet-connector) - Core wallet connector interfaces
216
+ - [`@etherplay/connect`](../etherplay-connect) - Main connection library
217
+ - [`@etherplay/alchemy`](../etherplay-alchemy) - Social login mechanisms
218
+
219
+ ## License
220
+
221
+ MIT
package/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ export declare class EthereumWalletConnector implements WalletConnector<CurriedR
31
31
  accountGenerator: AccountGenerator;
32
32
  fetchWallets(walletAnnounced: (walletInfo: WalletHandle<CurriedRPC<Methods>>) => void): void;
33
33
  createAlwaysOnProvider(params: {
34
- endpoint: string;
34
+ endpoint: string | UnderlyingEthereumProvider;
35
35
  chainId: string;
36
36
  prioritizeWalletProvider?: boolean;
37
37
  requestsPerSecond?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import type { Methods } from 'eip-1193';
2
2
  import { CurriedRPC } from 'remote-procedure-call';
3
3
  import { AlwaysOnProviderWrapper } from '@etherplay/wallet-connector';
4
+ import { UnderlyingEthereumProvider } from './index.js';
4
5
  export declare function createProvider(params: {
5
- endpoint: string;
6
+ endpoint: string | UnderlyingEthereumProvider;
6
7
  chainId: string;
7
8
  prioritizeWalletProvider?: boolean;
8
9
  requestsPerSecond?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsE,OAAO,EAAC,MAAM,UAAU,CAAC;AAC3G,OAAO,EAAuB,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EAAC,uBAAuB,EAAC,MAAM,6BAA6B,CAAC;AAoGpE,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,uBAAuB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAE/C"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsE,OAAO,EAAC,MAAM,UAAU,CAAC;AAC3G,OAAO,EAAuB,UAAU,EAAC,MAAM,uBAAuB,CAAC;AAEvE,OAAO,EACN,uBAAuB,EASvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAC,0BAA0B,EAAC,MAAM,YAAY,CAAC;AAiNtD,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACtC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B,GAAG,uBAAuB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAE/C"}
package/dist/provider.js CHANGED
@@ -1,5 +1,22 @@
1
1
  import { createCurriedJSONRPC } from 'remote-procedure-call';
2
2
  import { withTimeout } from './utils.js';
3
+ import { TRACKED_REQUEST_METHODS, TRANSACTION_METHODS, } from '@etherplay/wallet-connector';
4
+ // Type guard for transaction methods
5
+ function isTransactionMethod(method) {
6
+ return TRANSACTION_METHODS.includes(method);
7
+ }
8
+ // Helper to create a properly typed PendingRequest
9
+ function createPendingRequest(id, method, startedAt) {
10
+ if (isTransactionMethod(method)) {
11
+ return { id, method, kind: 'transaction', startedAt };
12
+ }
13
+ // TypeScript knows method is SignatureMethod here
14
+ return { id, method: method, kind: 'signature', startedAt };
15
+ }
16
+ // Helper to check if method should be tracked
17
+ function isTrackedMethod(method) {
18
+ return TRACKED_REQUEST_METHODS.includes(method);
19
+ }
3
20
  const signerMethods = [
4
21
  'eth_accounts',
5
22
  'eth_sign',
@@ -16,62 +33,134 @@ class AlwaysOnEthereumProviderWrapper {
16
33
  walletProvider;
17
34
  jsonRPC;
18
35
  status = 'disconnected';
36
+ // Request tracking fields
37
+ pendingRequests = new Map();
38
+ requestHandlers = new Set();
39
+ requestCounter = 0;
19
40
  constructor(params) {
20
41
  const self = this;
21
42
  this.chainId = params.chainId;
22
43
  this.jsonRPC = createCurriedJSONRPC(params.endpoint);
23
44
  const provider = {
24
45
  async request(req) {
25
- const signingMethod = signerMethods.includes(req.method) ||
26
- connectedAccountMethods.includes(req.method) ||
27
- walletOnlyMethods.includes(req.method) ||
28
- req.method.indexOf('sign') != -1;
29
- if (self.walletProvider) {
30
- if (params.prioritizeWalletProvider || signingMethod) {
31
- if (signingMethod) {
32
- if (self.status !== 'connected') {
33
- return Promise.reject({ message: 'wallet provider is not connected', code: 4001 });
34
- }
35
- }
36
- let currentChainIdAsHex;
37
- try {
38
- currentChainIdAsHex = await withTimeout(self.walletProvider.request({
39
- method: 'eth_chainId',
40
- }));
41
- }
42
- catch (err) {
43
- if (signingMethod) {
44
- return Promise.reject(err);
45
- }
46
- else {
47
- // we fallback on jsonRPc if error while getting chain and not a signing method
48
- return self.jsonRPC.request(req);
49
- }
50
- }
51
- const currentChainId = Number(currentChainIdAsHex).toString();
52
- if (self.chainId !== currentChainId) {
53
- if (signingMethod) {
54
- return Promise.reject({
55
- message: `wallet provider is connected to a different chain, expected ${self.chainId} but got ${currentChainId}`,
56
- code: 4001,
57
- });
58
- }
59
- else {
60
- // we fallback on jsonRPc if invalid chain and not a signing method
61
- return self.jsonRPC.request(req);
62
- }
63
- }
64
- return self.walletProvider.request(req);
65
- }
66
- }
67
- if (signingMethod) {
68
- return Promise.reject(new Error('wallet provider is not connected'));
46
+ // Check if this is a tracked method
47
+ if (isTrackedMethod(req.method)) {
48
+ return self.executeTrackedRequest(req, params.prioritizeWalletProvider);
69
49
  }
70
- return self.jsonRPC.request(req);
50
+ // Non-tracked methods - execute directly
51
+ return self.executeRequest(req, params.prioritizeWalletProvider);
71
52
  },
72
53
  };
73
54
  this.provider = createCurriedJSONRPC(provider, { requestsPerSecond: params.requestsPerSecond });
74
55
  }
56
+ // Event subscription
57
+ onRequest(handler) {
58
+ this.requestHandlers.add(handler);
59
+ return () => {
60
+ this.requestHandlers.delete(handler);
61
+ };
62
+ }
63
+ // Get current pending requests
64
+ getPendingRequests() {
65
+ return Array.from(this.pendingRequests.values());
66
+ }
67
+ // Emit event to all handlers
68
+ emitRequestEvent(event) {
69
+ for (const handler of this.requestHandlers) {
70
+ try {
71
+ handler(event);
72
+ }
73
+ catch (e) {
74
+ console.error('Request event handler error:', e);
75
+ }
76
+ }
77
+ }
78
+ // Generate unique request ID
79
+ generateRequestId() {
80
+ return `req_${++this.requestCounter}_${Date.now()}`;
81
+ }
82
+ // Execute tracked request with event emission
83
+ async executeTrackedRequest(req, prioritizeWalletProvider) {
84
+ const method = req.method;
85
+ const requestId = this.generateRequestId();
86
+ const pendingRequest = createPendingRequest(requestId, method, Date.now());
87
+ // Track and emit start event
88
+ this.pendingRequests.set(requestId, pendingRequest);
89
+ this.emitRequestEvent({ type: 'requestStart', request: pendingRequest });
90
+ try {
91
+ const result = await this.executeRequest(req, prioritizeWalletProvider);
92
+ // Emit success event
93
+ this.pendingRequests.delete(requestId);
94
+ this.emitRequestEvent({
95
+ type: 'requestEnd',
96
+ request: pendingRequest,
97
+ result: 'success',
98
+ });
99
+ return result;
100
+ }
101
+ catch (error) {
102
+ // Determine if user rejected
103
+ const isRejected = error?.code === 4001;
104
+ // Emit end event
105
+ this.pendingRequests.delete(requestId);
106
+ this.emitRequestEvent({
107
+ type: 'requestEnd',
108
+ request: pendingRequest,
109
+ result: isRejected ? 'rejected' : 'error',
110
+ error: isRejected ? undefined : error,
111
+ });
112
+ throw error;
113
+ }
114
+ }
115
+ // Execute request (original request routing logic)
116
+ async executeRequest(req, prioritizeWalletProvider) {
117
+ const signingMethod = signerMethods.includes(req.method) ||
118
+ connectedAccountMethods.includes(req.method) ||
119
+ walletOnlyMethods.includes(req.method) ||
120
+ req.method.indexOf('sign') != -1;
121
+ if (this.walletProvider) {
122
+ if (prioritizeWalletProvider || signingMethod) {
123
+ if (signingMethod) {
124
+ if (this.status !== 'connected') {
125
+ return Promise.reject({ message: 'wallet provider is not connected', code: 4001 });
126
+ }
127
+ }
128
+ let currentChainIdAsHex;
129
+ try {
130
+ currentChainIdAsHex = await withTimeout(this.walletProvider.request({
131
+ method: 'eth_chainId',
132
+ }));
133
+ }
134
+ catch (err) {
135
+ if (signingMethod) {
136
+ return Promise.reject(err);
137
+ }
138
+ else {
139
+ // we fallback on jsonRPc if error while getting chain and not a signing method
140
+ return this.jsonRPC.request(req);
141
+ }
142
+ }
143
+ const currentChainId = Number(currentChainIdAsHex).toString();
144
+ if (this.chainId !== currentChainId) {
145
+ if (signingMethod) {
146
+ return Promise.reject({
147
+ message: `wallet provider is connected to a different chain, expected ${this.chainId} but got ${currentChainId}`,
148
+ code: 4001,
149
+ });
150
+ }
151
+ else {
152
+ // we fallback on jsonRPc if invalid chain and not a signing method
153
+ return this.jsonRPC.request(req);
154
+ }
155
+ }
156
+ return this.walletProvider.request(req);
157
+ }
158
+ }
159
+ if (signingMethod) {
160
+ return Promise.reject(new Error('wallet provider is not connected'));
161
+ }
162
+ return this.jsonRPC.request(req);
163
+ }
75
164
  setWalletProvider(walletProvider) {
76
165
  this.walletProvider = walletProvider;
77
166
  }
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,31 @@
1
1
  {
2
2
  "name": "@etherplay/wallet-connector-ethereum",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
+ "description": "Ethereum wallet connector implementation for @etherplay/connect - provides EIP-6963 provider detection, account management, and chain switching support",
5
+ "keywords": [
6
+ "ethereum",
7
+ "wallet",
8
+ "connector",
9
+ "eip-6963",
10
+ "metamask",
11
+ "web3",
12
+ "provider",
13
+ "chain-switching",
14
+ "account-management",
15
+ "typescript",
16
+ "eth_sign",
17
+ "personal_sign"
18
+ ],
19
+ "homepage": "https://github.com/wighawag/etherplay-connect#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/wighawag/etherplay-connect.git",
23
+ "directory": "packages/etherplay-wallet-connector-ethereum"
24
+ },
25
+ "bugs": {
26
+ "url": "https://github.com/wighawag/etherplay-connect/issues"
27
+ },
28
+ "author": "Ronan Sandford",
4
29
  "license": "MIT",
5
30
  "publishConfig": {
6
31
  "access": "public"
@@ -30,12 +55,12 @@
30
55
  "@noble/curves": "1.8.1",
31
56
  "@noble/secp256k1": "^2.2.3",
32
57
  "remote-procedure-call": "^0.1.1",
33
- "@etherplay/wallet-connector": "0.0.3"
58
+ "@etherplay/wallet-connector": "0.0.5"
34
59
  },
35
60
  "scripts": {
36
61
  "build": "tsc --project tsconfig.json",
37
62
  "dev": "as-soon -w src pnpm build",
38
63
  "format:check": "prettier --check .",
39
- "format:write": "prettier --write ."
64
+ "format": "prettier --write ."
40
65
  }
41
66
  }
package/src/index.ts CHANGED
@@ -141,7 +141,7 @@ export class EthereumWalletConnector implements WalletConnector<CurriedRPC<Metho
141
141
  }
142
142
 
143
143
  createAlwaysOnProvider(params: {
144
- endpoint: string;
144
+ endpoint: string | UnderlyingEthereumProvider;
145
145
  chainId: string;
146
146
  prioritizeWalletProvider?: boolean;
147
147
  requestsPerSecond?: number;
package/src/provider.ts CHANGED
@@ -1,7 +1,37 @@
1
1
  import type {EIP1193Provider, EIP1193WalletProvider, EIP1193WindowWalletProvider, Methods} from 'eip-1193';
2
2
  import {createCurriedJSONRPC, CurriedRPC} from 'remote-procedure-call';
3
3
  import {withTimeout} from './utils.js';
4
- import {AlwaysOnProviderWrapper} from '@etherplay/wallet-connector';
4
+ import {
5
+ AlwaysOnProviderWrapper,
6
+ PendingRequest,
7
+ RequestEvent,
8
+ RequestEventHandler,
9
+ TrackedRequestMethod,
10
+ TRACKED_REQUEST_METHODS,
11
+ TRANSACTION_METHODS,
12
+ TransactionMethod,
13
+ SignatureMethod,
14
+ } from '@etherplay/wallet-connector';
15
+ import {UnderlyingEthereumProvider} from './index.js';
16
+
17
+ // Type guard for transaction methods
18
+ function isTransactionMethod(method: TrackedRequestMethod): method is TransactionMethod {
19
+ return (TRANSACTION_METHODS as readonly string[]).includes(method);
20
+ }
21
+
22
+ // Helper to create a properly typed PendingRequest
23
+ function createPendingRequest(id: string, method: TrackedRequestMethod, startedAt: number): PendingRequest {
24
+ if (isTransactionMethod(method)) {
25
+ return {id, method, kind: 'transaction', startedAt};
26
+ }
27
+ // TypeScript knows method is SignatureMethod here
28
+ return {id, method: method as SignatureMethod, kind: 'signature', startedAt};
29
+ }
30
+
31
+ // Helper to check if method should be tracked
32
+ function isTrackedMethod(method: string): method is TrackedRequestMethod {
33
+ return (TRACKED_REQUEST_METHODS as readonly string[]).includes(method);
34
+ }
5
35
 
6
36
  const signerMethods = [
7
37
  'eth_accounts',
@@ -23,8 +53,13 @@ class AlwaysOnEthereumProviderWrapper implements AlwaysOnProviderWrapper<Curried
23
53
  private jsonRPC: CurriedRPC<Methods>;
24
54
  private status: 'connected' | 'locked' | 'disconnected' = 'disconnected';
25
55
 
56
+ // Request tracking fields
57
+ private pendingRequests: Map<string, PendingRequest> = new Map();
58
+ private requestHandlers: Set<RequestEventHandler> = new Set();
59
+ private requestCounter = 0;
60
+
26
61
  constructor(params: {
27
- endpoint: string;
62
+ endpoint: string | UnderlyingEthereumProvider;
28
63
  chainId: string;
29
64
  prioritizeWalletProvider?: boolean;
30
65
  requestsPerSecond?: number;
@@ -35,63 +70,148 @@ class AlwaysOnEthereumProviderWrapper implements AlwaysOnProviderWrapper<Curried
35
70
 
36
71
  const provider = {
37
72
  async request(req: {method: string; params?: any[]}) {
38
- const signingMethod =
39
- signerMethods.includes(req.method) ||
40
- connectedAccountMethods.includes(req.method) ||
41
- walletOnlyMethods.includes(req.method) ||
42
- req.method.indexOf('sign') != -1;
43
-
44
- if (self.walletProvider) {
45
- if (params.prioritizeWalletProvider || signingMethod) {
46
- if (signingMethod) {
47
- if (self.status !== 'connected') {
48
- return Promise.reject({message: 'wallet provider is not connected', code: 4001});
49
- }
50
- }
51
-
52
- let currentChainIdAsHex: string;
53
- try {
54
- currentChainIdAsHex = await withTimeout(
55
- self.walletProvider.request({
56
- method: 'eth_chainId',
57
- }),
58
- );
59
- } catch (err) {
60
- if (signingMethod) {
61
- return Promise.reject(err);
62
- } else {
63
- // we fallback on jsonRPc if error while getting chain and not a signing method
64
- return self.jsonRPC.request(req as any);
65
- }
66
- }
67
-
68
- const currentChainId = Number(currentChainIdAsHex).toString();
69
- if (self.chainId !== currentChainId) {
70
- if (signingMethod) {
71
- return Promise.reject({
72
- message: `wallet provider is connected to a different chain, expected ${self.chainId} but got ${currentChainId}`,
73
- code: 4001,
74
- });
75
- } else {
76
- // we fallback on jsonRPc if invalid chain and not a signing method
77
- return self.jsonRPC.request(req as any);
78
- }
79
- }
80
- return self.walletProvider.request(req as any);
81
- }
73
+ // Check if this is a tracked method
74
+ if (isTrackedMethod(req.method)) {
75
+ return self.executeTrackedRequest(req, params.prioritizeWalletProvider);
82
76
  }
83
77
 
84
- if (signingMethod) {
85
- return Promise.reject(new Error('wallet provider is not connected'));
86
- }
87
-
88
- return self.jsonRPC.request(req as any);
78
+ // Non-tracked methods - execute directly
79
+ return self.executeRequest(req, params.prioritizeWalletProvider);
89
80
  },
90
81
  } as unknown as EIP1193Provider;
91
82
 
92
83
  this.provider = createCurriedJSONRPC<Methods>(provider, {requestsPerSecond: params.requestsPerSecond});
93
84
  }
94
85
 
86
+ // Event subscription
87
+ onRequest(handler: RequestEventHandler): () => void {
88
+ this.requestHandlers.add(handler);
89
+ return () => {
90
+ this.requestHandlers.delete(handler);
91
+ };
92
+ }
93
+
94
+ // Get current pending requests
95
+ getPendingRequests(): PendingRequest[] {
96
+ return Array.from(this.pendingRequests.values());
97
+ }
98
+
99
+ // Emit event to all handlers
100
+ private emitRequestEvent(event: RequestEvent): void {
101
+ for (const handler of this.requestHandlers) {
102
+ try {
103
+ handler(event);
104
+ } catch (e) {
105
+ console.error('Request event handler error:', e);
106
+ }
107
+ }
108
+ }
109
+
110
+ // Generate unique request ID
111
+ private generateRequestId(): string {
112
+ return `req_${++this.requestCounter}_${Date.now()}`;
113
+ }
114
+
115
+ // Execute tracked request with event emission
116
+ private async executeTrackedRequest(
117
+ req: {method: string; params?: any[]},
118
+ prioritizeWalletProvider?: boolean,
119
+ ): Promise<any> {
120
+ const method = req.method as TrackedRequestMethod;
121
+ const requestId = this.generateRequestId();
122
+ const pendingRequest = createPendingRequest(requestId, method, Date.now());
123
+
124
+ // Track and emit start event
125
+ this.pendingRequests.set(requestId, pendingRequest);
126
+ this.emitRequestEvent({type: 'requestStart', request: pendingRequest});
127
+
128
+ try {
129
+ const result = await this.executeRequest(req, prioritizeWalletProvider);
130
+
131
+ // Emit success event
132
+ this.pendingRequests.delete(requestId);
133
+ this.emitRequestEvent({
134
+ type: 'requestEnd',
135
+ request: pendingRequest,
136
+ result: 'success',
137
+ });
138
+
139
+ return result;
140
+ } catch (error) {
141
+ // Determine if user rejected
142
+ const isRejected = (error as any)?.code === 4001;
143
+
144
+ // Emit end event
145
+ this.pendingRequests.delete(requestId);
146
+ this.emitRequestEvent({
147
+ type: 'requestEnd',
148
+ request: pendingRequest,
149
+ result: isRejected ? 'rejected' : 'error',
150
+ error: isRejected ? undefined : error,
151
+ });
152
+
153
+ throw error;
154
+ }
155
+ }
156
+
157
+ // Execute request (original request routing logic)
158
+ private async executeRequest(
159
+ req: {method: string; params?: any[]},
160
+ prioritizeWalletProvider?: boolean,
161
+ ): Promise<any> {
162
+ const signingMethod =
163
+ signerMethods.includes(req.method) ||
164
+ connectedAccountMethods.includes(req.method) ||
165
+ walletOnlyMethods.includes(req.method) ||
166
+ req.method.indexOf('sign') != -1;
167
+
168
+ if (this.walletProvider) {
169
+ if (prioritizeWalletProvider || signingMethod) {
170
+ if (signingMethod) {
171
+ if (this.status !== 'connected') {
172
+ return Promise.reject({message: 'wallet provider is not connected', code: 4001});
173
+ }
174
+ }
175
+
176
+ let currentChainIdAsHex: string;
177
+ try {
178
+ currentChainIdAsHex = await withTimeout(
179
+ this.walletProvider.request({
180
+ method: 'eth_chainId',
181
+ }),
182
+ );
183
+ } catch (err) {
184
+ if (signingMethod) {
185
+ return Promise.reject(err);
186
+ } else {
187
+ // we fallback on jsonRPc if error while getting chain and not a signing method
188
+ return this.jsonRPC.request(req as any);
189
+ }
190
+ }
191
+
192
+ const currentChainId = Number(currentChainIdAsHex).toString();
193
+ if (this.chainId !== currentChainId) {
194
+ if (signingMethod) {
195
+ return Promise.reject({
196
+ message: `wallet provider is connected to a different chain, expected ${this.chainId} but got ${currentChainId}`,
197
+ code: 4001,
198
+ });
199
+ } else {
200
+ // we fallback on jsonRPc if invalid chain and not a signing method
201
+ return this.jsonRPC.request(req as any);
202
+ }
203
+ }
204
+ return this.walletProvider.request(req as any);
205
+ }
206
+ }
207
+
208
+ if (signingMethod) {
209
+ return Promise.reject(new Error('wallet provider is not connected'));
210
+ }
211
+
212
+ return this.jsonRPC.request(req as any);
213
+ }
214
+
95
215
  setWalletProvider(walletProvider: CurriedRPC<Methods> | undefined) {
96
216
  this.walletProvider = walletProvider;
97
217
  }
@@ -102,7 +222,7 @@ class AlwaysOnEthereumProviderWrapper implements AlwaysOnProviderWrapper<Curried
102
222
  }
103
223
 
104
224
  export function createProvider(params: {
105
- endpoint: string;
225
+ endpoint: string | UnderlyingEthereumProvider;
106
226
  chainId: string;
107
227
  prioritizeWalletProvider?: boolean;
108
228
  requestsPerSecond?: number;