@etherplay/wallet-connector-ethereum 0.0.5 → 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 +221 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +134 -45
- package/dist/provider.js.map +1 -1
- package/package.json +28 -3
- package/src/provider.ts +169 -50
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/provider.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|
}
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,oBAAoB,EAAa,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAC,WAAW,EAAC,MAAM,YAAY,CAAC;
|
|
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.
|
|
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.
|
|
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
|
|
64
|
+
"format": "prettier --write ."
|
|
40
65
|
}
|
|
41
66
|
}
|
package/src/provider.ts
CHANGED
|
@@ -1,9 +1,38 @@
|
|
|
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 {
|
|
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';
|
|
5
15
|
import {UnderlyingEthereumProvider} from './index.js';
|
|
6
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
|
+
}
|
|
35
|
+
|
|
7
36
|
const signerMethods = [
|
|
8
37
|
'eth_accounts',
|
|
9
38
|
'eth_sign',
|
|
@@ -24,6 +53,11 @@ class AlwaysOnEthereumProviderWrapper implements AlwaysOnProviderWrapper<Curried
|
|
|
24
53
|
private jsonRPC: CurriedRPC<Methods>;
|
|
25
54
|
private status: 'connected' | 'locked' | 'disconnected' = 'disconnected';
|
|
26
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
|
+
|
|
27
61
|
constructor(params: {
|
|
28
62
|
endpoint: string | UnderlyingEthereumProvider;
|
|
29
63
|
chainId: string;
|
|
@@ -36,63 +70,148 @@ class AlwaysOnEthereumProviderWrapper implements AlwaysOnProviderWrapper<Curried
|
|
|
36
70
|
|
|
37
71
|
const provider = {
|
|
38
72
|
async request(req: {method: string; params?: any[]}) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
walletOnlyMethods.includes(req.method) ||
|
|
43
|
-
req.method.indexOf('sign') != -1;
|
|
44
|
-
|
|
45
|
-
if (self.walletProvider) {
|
|
46
|
-
if (params.prioritizeWalletProvider || signingMethod) {
|
|
47
|
-
if (signingMethod) {
|
|
48
|
-
if (self.status !== 'connected') {
|
|
49
|
-
return Promise.reject({message: 'wallet provider is not connected', code: 4001});
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let currentChainIdAsHex: string;
|
|
54
|
-
try {
|
|
55
|
-
currentChainIdAsHex = await withTimeout(
|
|
56
|
-
self.walletProvider.request({
|
|
57
|
-
method: 'eth_chainId',
|
|
58
|
-
}),
|
|
59
|
-
);
|
|
60
|
-
} catch (err) {
|
|
61
|
-
if (signingMethod) {
|
|
62
|
-
return Promise.reject(err);
|
|
63
|
-
} else {
|
|
64
|
-
// we fallback on jsonRPc if error while getting chain and not a signing method
|
|
65
|
-
return self.jsonRPC.request(req as any);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const currentChainId = Number(currentChainIdAsHex).toString();
|
|
70
|
-
if (self.chainId !== currentChainId) {
|
|
71
|
-
if (signingMethod) {
|
|
72
|
-
return Promise.reject({
|
|
73
|
-
message: `wallet provider is connected to a different chain, expected ${self.chainId} but got ${currentChainId}`,
|
|
74
|
-
code: 4001,
|
|
75
|
-
});
|
|
76
|
-
} else {
|
|
77
|
-
// we fallback on jsonRPc if invalid chain and not a signing method
|
|
78
|
-
return self.jsonRPC.request(req as any);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return self.walletProvider.request(req as any);
|
|
82
|
-
}
|
|
73
|
+
// Check if this is a tracked method
|
|
74
|
+
if (isTrackedMethod(req.method)) {
|
|
75
|
+
return self.executeTrackedRequest(req, params.prioritizeWalletProvider);
|
|
83
76
|
}
|
|
84
77
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return self.jsonRPC.request(req as any);
|
|
78
|
+
// Non-tracked methods - execute directly
|
|
79
|
+
return self.executeRequest(req, params.prioritizeWalletProvider);
|
|
90
80
|
},
|
|
91
81
|
} as unknown as EIP1193Provider;
|
|
92
82
|
|
|
93
83
|
this.provider = createCurriedJSONRPC<Methods>(provider, {requestsPerSecond: params.requestsPerSecond});
|
|
94
84
|
}
|
|
95
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
|
+
|
|
96
215
|
setWalletProvider(walletProvider: CurriedRPC<Methods> | undefined) {
|
|
97
216
|
this.walletProvider = walletProvider;
|
|
98
217
|
}
|