@d10r/wagmi-superfluid-wallet 0.1.0-rc.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.
- package/README.md +52 -0
- package/dist/index.cjs +543 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +537 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @d10r/wagmi-superfluid-wallet
|
|
2
|
+
|
|
3
|
+
> Release candidate (`0.1.0-rc.0`). Install with `pnpm add @d10r/wagmi-superfluid-wallet@rc`.
|
|
4
|
+
|
|
5
|
+
wagmi v2 connector for [Superfluid Wallet](https://wallet.superfluid.org) — a hosted popup for auth and signing.
|
|
6
|
+
|
|
7
|
+
Your dapp keeps using normal wagmi hooks. The connector opens the wallet popup for signing, syncs chain ID on connect/switch, and uses your wagmi `transports` for everything else (reads, gas estimation, broadcast).
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @d10r/wagmi-superfluid-wallet@rc wagmi viem
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { createConfig, http } from 'wagmi'
|
|
17
|
+
import { superfluidWallet } from '@d10r/wagmi-superfluid-wallet'
|
|
18
|
+
|
|
19
|
+
const sfWallet = superfluidWallet() // defaults to https://wallet.superfluid.org
|
|
20
|
+
|
|
21
|
+
export const config = createConfig({
|
|
22
|
+
chains,
|
|
23
|
+
transports: { /* http / fallback per chain */ },
|
|
24
|
+
connectors: [
|
|
25
|
+
sfWallet.connector(),
|
|
26
|
+
// ...injected, walletConnect, etc.
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Local wallet: `superfluidWallet({ walletUrl: 'http://localhost:3001' })`
|
|
32
|
+
|
|
33
|
+
Env-gated registration is a one-liner in your wagmi config — no package helper needed.
|
|
34
|
+
|
|
35
|
+
## Before going live
|
|
36
|
+
|
|
37
|
+
1. Configure `chains` + `transports` in wagmi (RPC reliability lives here).
|
|
38
|
+
2. Add your dapp origin to the hosted wallet's `NEXT_PUBLIC_ALLOWED_DAPP_ORIGINS`.
|
|
39
|
+
3. Add the **wallet** origin (not the dapp) to Turnkey Auth Proxy allowed origins.
|
|
40
|
+
|
|
41
|
+
## Testing without Turnkey
|
|
42
|
+
|
|
43
|
+
Set `window.__SUPERFLUID_WALLET_MOCK_HANDLER__` before connecting. The provider skips the popup when present. See `src/eip1193-provider.test.ts`.
|
|
44
|
+
|
|
45
|
+
## Options
|
|
46
|
+
|
|
47
|
+
| Field | Default |
|
|
48
|
+
|-------|---------|
|
|
49
|
+
| `walletUrl` | `https://wallet.superfluid.org` |
|
|
50
|
+
| `connectorId` | `superfluidWallet` |
|
|
51
|
+
| `storageKey` | `SF:EIP1193Provider:store` |
|
|
52
|
+
| `popupTimeoutMs` | `300000` |
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@wagmi/core');
|
|
4
|
+
var viem = require('viem');
|
|
5
|
+
var wagmi = require('wagmi');
|
|
6
|
+
var actions = require('viem/actions');
|
|
7
|
+
var utils = require('viem/utils');
|
|
8
|
+
|
|
9
|
+
// src/config.ts
|
|
10
|
+
var DEFAULT_WALLET_URL = "https://wallet.superfluid.org";
|
|
11
|
+
var DEFAULT_CONNECTOR_ID = "superfluidWallet";
|
|
12
|
+
var DEFAULT_STORAGE_KEY = "SF:EIP1193Provider:store";
|
|
13
|
+
var DEFAULT_POPUP_TIMEOUT_MS = 3e5;
|
|
14
|
+
function resolveSuperfluidWalletConfig(config = {}) {
|
|
15
|
+
const walletUrl = (config.walletUrl ?? DEFAULT_WALLET_URL).trim().replace(/\/$/, "");
|
|
16
|
+
let walletOrigin;
|
|
17
|
+
try {
|
|
18
|
+
walletOrigin = new URL(walletUrl).origin;
|
|
19
|
+
} catch {
|
|
20
|
+
throw new Error(`Invalid walletUrl: ${config.walletUrl ?? walletUrl}`);
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
walletUrl,
|
|
24
|
+
walletOrigin,
|
|
25
|
+
connectorId: config.connectorId ?? DEFAULT_CONNECTOR_ID,
|
|
26
|
+
storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,
|
|
27
|
+
popupTimeoutMs: config.popupTimeoutMs ?? DEFAULT_POPUP_TIMEOUT_MS
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/event-emitter.ts
|
|
32
|
+
var EventEmitter = class {
|
|
33
|
+
listeners = /* @__PURE__ */ new Map();
|
|
34
|
+
on(event, listener) {
|
|
35
|
+
if (!this.listeners.has(event)) {
|
|
36
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
37
|
+
}
|
|
38
|
+
this.listeners.get(event)?.add(listener);
|
|
39
|
+
}
|
|
40
|
+
emit(event, ...args) {
|
|
41
|
+
for (const listener of this.listeners.get(event) ?? []) {
|
|
42
|
+
listener(...args);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
removeListener(event, listener) {
|
|
46
|
+
this.listeners.get(event)?.delete(listener);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// src/provider-store.ts
|
|
51
|
+
function createProviderStore(storageKey) {
|
|
52
|
+
const eventEmitter = new EventEmitter();
|
|
53
|
+
const getState = () => {
|
|
54
|
+
if (typeof localStorage === "undefined") {
|
|
55
|
+
return { accounts: [], organizationId: void 0, chainId: void 0 };
|
|
56
|
+
}
|
|
57
|
+
const stored = localStorage.getItem(storageKey);
|
|
58
|
+
return stored ? JSON.parse(stored) : { accounts: [], organizationId: void 0, chainId: void 0 };
|
|
59
|
+
};
|
|
60
|
+
const update = (updates) => {
|
|
61
|
+
const current = getState();
|
|
62
|
+
const next = { ...current, ...updates };
|
|
63
|
+
if (typeof localStorage !== "undefined") {
|
|
64
|
+
localStorage.setItem(storageKey, JSON.stringify(next));
|
|
65
|
+
}
|
|
66
|
+
if (updates.accounts && JSON.stringify(updates.accounts) !== JSON.stringify(current.accounts)) {
|
|
67
|
+
eventEmitter.emit("accountsChanged", updates.accounts);
|
|
68
|
+
}
|
|
69
|
+
if (updates.chainId !== void 0 && updates.chainId !== current.chainId) {
|
|
70
|
+
eventEmitter.emit("chainChanged", `0x${updates.chainId.toString(16)}`);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
storageKey,
|
|
75
|
+
getState,
|
|
76
|
+
setChainId: (chainId) => update({ chainId }),
|
|
77
|
+
update,
|
|
78
|
+
clear: () => {
|
|
79
|
+
if (typeof localStorage !== "undefined") {
|
|
80
|
+
localStorage.removeItem(storageKey);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
onAccountsChanged: (listener) => {
|
|
84
|
+
eventEmitter.on("accountsChanged", listener);
|
|
85
|
+
},
|
|
86
|
+
onChainChanged: (listener) => {
|
|
87
|
+
eventEmitter.on("chainChanged", listener);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function getStoredChainIdHex(store) {
|
|
92
|
+
const { chainId } = store.getState();
|
|
93
|
+
if (chainId === void 0) return void 0;
|
|
94
|
+
return `0x${chainId.toString(16)}`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/enrichPopupRequest.ts
|
|
98
|
+
function enrichSignTransactionParams(params, chainIdHex) {
|
|
99
|
+
const txParams = params;
|
|
100
|
+
const transaction = txParams?.[0];
|
|
101
|
+
if (!transaction) return params;
|
|
102
|
+
if (transaction.chainId !== void 0 && transaction.chainId !== null) {
|
|
103
|
+
return params;
|
|
104
|
+
}
|
|
105
|
+
if (!chainIdHex) {
|
|
106
|
+
throw new Error("No chain ID available. Select a network and retry.");
|
|
107
|
+
}
|
|
108
|
+
return [{ ...transaction, chainId: chainIdHex }];
|
|
109
|
+
}
|
|
110
|
+
function enrichPopupParams(method, params, chainIdHex) {
|
|
111
|
+
if (method === "eth_signTransaction") {
|
|
112
|
+
return enrichSignTransactionParams(params, chainIdHex);
|
|
113
|
+
}
|
|
114
|
+
return params;
|
|
115
|
+
}
|
|
116
|
+
function toOptionalBigInt(value, field) {
|
|
117
|
+
if (value === void 0 || value === null) return void 0;
|
|
118
|
+
if (typeof value === "number") return BigInt(value);
|
|
119
|
+
if (typeof value === "string" && value.startsWith("0x")) {
|
|
120
|
+
return viem.hexToBigInt(value);
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`Invalid ${field}: expected hex or number`);
|
|
123
|
+
}
|
|
124
|
+
function resolveChainIdFromTransaction(transaction, fallbackChainId) {
|
|
125
|
+
const parsed = toOptionalBigInt(transaction.chainId, "chainId");
|
|
126
|
+
if (parsed !== void 0) return Number(parsed);
|
|
127
|
+
if (fallbackChainId !== void 0) return fallbackChainId;
|
|
128
|
+
throw new Error("No chain ID available. Select a network and retry.");
|
|
129
|
+
}
|
|
130
|
+
async function prepareSignTransactionParams(params, options) {
|
|
131
|
+
const txParams = params;
|
|
132
|
+
const transaction = txParams?.[0];
|
|
133
|
+
if (!transaction) {
|
|
134
|
+
throw new Error("Missing transaction for eth_signTransaction");
|
|
135
|
+
}
|
|
136
|
+
if (!transaction.from) {
|
|
137
|
+
throw new Error("Transaction is missing from");
|
|
138
|
+
}
|
|
139
|
+
if (!transaction.to) {
|
|
140
|
+
throw new Error("Transaction is missing to");
|
|
141
|
+
}
|
|
142
|
+
const chainId = resolveChainIdFromTransaction(transaction, options.fallbackChainId);
|
|
143
|
+
const prepare = options.prepareRequest ?? actions.prepareTransactionRequest;
|
|
144
|
+
const prepareRequest = {
|
|
145
|
+
account: transaction.from,
|
|
146
|
+
to: transaction.to,
|
|
147
|
+
data: transaction.data,
|
|
148
|
+
value: toOptionalBigInt(transaction.value, "value"),
|
|
149
|
+
gas: toOptionalBigInt(transaction.gas ?? transaction.gasLimit, "gas"),
|
|
150
|
+
maxFeePerGas: toOptionalBigInt(transaction.maxFeePerGas, "maxFeePerGas"),
|
|
151
|
+
maxPriorityFeePerGas: toOptionalBigInt(
|
|
152
|
+
transaction.maxPriorityFeePerGas,
|
|
153
|
+
"maxPriorityFeePerGas"
|
|
154
|
+
),
|
|
155
|
+
nonce: toOptionalBigInt(transaction.nonce, "nonce") !== void 0 ? Number(toOptionalBigInt(transaction.nonce, "nonce")) : void 0,
|
|
156
|
+
chainId,
|
|
157
|
+
type: "eip1559"
|
|
158
|
+
};
|
|
159
|
+
const prepared = await prepare(
|
|
160
|
+
options.client,
|
|
161
|
+
// @ts-expect-error viem PrepareTransactionRequestParameters mismatch for dynamic RPC clients
|
|
162
|
+
prepareRequest
|
|
163
|
+
);
|
|
164
|
+
if (prepared.gas === void 0 || prepared.maxFeePerGas === void 0 || prepared.maxPriorityFeePerGas === void 0 || prepared.nonce === void 0) {
|
|
165
|
+
throw new Error("Failed to prepare a complete EIP-1559 transaction");
|
|
166
|
+
}
|
|
167
|
+
const rpcTx = {
|
|
168
|
+
from: transaction.from,
|
|
169
|
+
to: prepared.to,
|
|
170
|
+
gas: utils.numberToHex(prepared.gas),
|
|
171
|
+
maxFeePerGas: utils.numberToHex(prepared.maxFeePerGas),
|
|
172
|
+
maxPriorityFeePerGas: utils.numberToHex(prepared.maxPriorityFeePerGas),
|
|
173
|
+
nonce: utils.numberToHex(BigInt(prepared.nonce)),
|
|
174
|
+
value: prepared.value !== void 0 ? utils.numberToHex(prepared.value) : "0x0",
|
|
175
|
+
chainId: utils.numberToHex(BigInt(chainId))
|
|
176
|
+
};
|
|
177
|
+
if (prepared.data) {
|
|
178
|
+
rpcTx.data = prepared.data;
|
|
179
|
+
}
|
|
180
|
+
return [rpcTx];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// src/resolvePopupParams.ts
|
|
184
|
+
async function resolvePopupParams(method, params, chainIdHex, getClient) {
|
|
185
|
+
if (method !== "eth_signTransaction") {
|
|
186
|
+
return enrichPopupParams(method, params, chainIdHex);
|
|
187
|
+
}
|
|
188
|
+
const fallbackChainId = chainIdHex ? Number.parseInt(chainIdHex, 16) : void 0;
|
|
189
|
+
if (fallbackChainId === void 0 || Number.isNaN(fallbackChainId)) {
|
|
190
|
+
throw new Error("No chain ID available. Select a network and retry.");
|
|
191
|
+
}
|
|
192
|
+
const client = getClient({ chainId: fallbackChainId });
|
|
193
|
+
return prepareSignTransactionParams(params, {
|
|
194
|
+
fallbackChainId,
|
|
195
|
+
client
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/eip1193-provider.ts
|
|
200
|
+
var POPUP_METHODS = /* @__PURE__ */ new Set([
|
|
201
|
+
"eth_requestAccounts",
|
|
202
|
+
"eth_signTransaction",
|
|
203
|
+
"eth_sign",
|
|
204
|
+
"personal_sign"
|
|
205
|
+
]);
|
|
206
|
+
var PUBLIC_RPC_METHODS = /* @__PURE__ */ new Set([
|
|
207
|
+
"eth_sendRawTransaction",
|
|
208
|
+
"eth_subscribe",
|
|
209
|
+
"eth_unsubscribe",
|
|
210
|
+
"eth_blobBaseFee",
|
|
211
|
+
"eth_blockNumber",
|
|
212
|
+
"eth_call",
|
|
213
|
+
"eth_coinbase",
|
|
214
|
+
"eth_estimateGas",
|
|
215
|
+
"eth_feeHistory",
|
|
216
|
+
"eth_gasPrice",
|
|
217
|
+
"eth_getBalance",
|
|
218
|
+
"eth_getBlockByHash",
|
|
219
|
+
"eth_getBlockByNumber",
|
|
220
|
+
"eth_getBlockReceipts",
|
|
221
|
+
"eth_getBlockTransactionCountByHash",
|
|
222
|
+
"eth_getBlockTransactionCountByNumber",
|
|
223
|
+
"eth_getCode",
|
|
224
|
+
"eth_getFilterChanges",
|
|
225
|
+
"eth_getFilterLogs",
|
|
226
|
+
"eth_getLogs",
|
|
227
|
+
"eth_getProof",
|
|
228
|
+
"eth_getStorageAt",
|
|
229
|
+
"eth_getTransactionByBlockHashAndIndex",
|
|
230
|
+
"eth_getTransactionByBlockNumberAndIndex",
|
|
231
|
+
"eth_getTransactionByHash",
|
|
232
|
+
"eth_getTransactionCount",
|
|
233
|
+
"eth_getTransactionReceipt",
|
|
234
|
+
"eth_getUncleCountByBlockHash",
|
|
235
|
+
"eth_getUncleCountByBlockNumber",
|
|
236
|
+
"eth_maxPriorityFeePerGas",
|
|
237
|
+
"eth_newBlockFilter",
|
|
238
|
+
"eth_newFilter",
|
|
239
|
+
"eth_newPendingTransactionFilter",
|
|
240
|
+
"eth_syncing",
|
|
241
|
+
"eth_uninstallFilter"
|
|
242
|
+
]);
|
|
243
|
+
function requireStoredChainId(store, context) {
|
|
244
|
+
const { chainId } = store.getState();
|
|
245
|
+
if (chainId === void 0) {
|
|
246
|
+
throw new Error(context);
|
|
247
|
+
}
|
|
248
|
+
return chainId;
|
|
249
|
+
}
|
|
250
|
+
function createEIP1193Provider(config, store, getClient) {
|
|
251
|
+
let popup = null;
|
|
252
|
+
const eventEmitter = new EventEmitter();
|
|
253
|
+
store.onAccountsChanged((accounts) => {
|
|
254
|
+
eventEmitter.emit("accountsChanged", accounts);
|
|
255
|
+
});
|
|
256
|
+
store.onChainChanged((chain) => {
|
|
257
|
+
eventEmitter.emit("chainChanged", chain);
|
|
258
|
+
});
|
|
259
|
+
const requestQueue = {};
|
|
260
|
+
const handleMessage = (event) => {
|
|
261
|
+
if (event.origin !== config.walletOrigin || event.source !== popup) return;
|
|
262
|
+
const { method, result, error } = event.data;
|
|
263
|
+
if (method && requestQueue[method]) {
|
|
264
|
+
if (error) {
|
|
265
|
+
requestQueue[method].reject({
|
|
266
|
+
code: error.code,
|
|
267
|
+
message: error.message,
|
|
268
|
+
data: error.data
|
|
269
|
+
});
|
|
270
|
+
} else {
|
|
271
|
+
if (method === "eth_requestAccounts") {
|
|
272
|
+
const { accounts, organizationId } = result[0];
|
|
273
|
+
store.update({ accounts, organizationId });
|
|
274
|
+
requestQueue[method].resolve(accounts);
|
|
275
|
+
} else {
|
|
276
|
+
requestQueue[method].resolve(result);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
delete requestQueue[method];
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
if (typeof window !== "undefined") {
|
|
283
|
+
window.addEventListener("message", handleMessage);
|
|
284
|
+
}
|
|
285
|
+
const requestImpl = async (args) => {
|
|
286
|
+
const { method, params } = args;
|
|
287
|
+
if (typeof window === "undefined") {
|
|
288
|
+
throw new Error("Window is not defined");
|
|
289
|
+
}
|
|
290
|
+
if (method === "eth_sendTransaction") {
|
|
291
|
+
const [transaction] = params;
|
|
292
|
+
const signedTransaction = await requestImpl({
|
|
293
|
+
method: "eth_signTransaction",
|
|
294
|
+
params: [transaction]
|
|
295
|
+
});
|
|
296
|
+
return requestImpl({
|
|
297
|
+
method: "eth_sendRawTransaction",
|
|
298
|
+
params: [signedTransaction]
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
if (method === "eth_accounts") {
|
|
302
|
+
return store.getState().accounts;
|
|
303
|
+
}
|
|
304
|
+
if (method === "eth_chainId") {
|
|
305
|
+
const chainId = requireStoredChainId(
|
|
306
|
+
store,
|
|
307
|
+
"No chain ID available. Connect a wallet and select a network first."
|
|
308
|
+
);
|
|
309
|
+
return `0x${chainId.toString(16)}`;
|
|
310
|
+
}
|
|
311
|
+
if (PUBLIC_RPC_METHODS.has(method)) {
|
|
312
|
+
const chainId = requireStoredChainId(
|
|
313
|
+
store,
|
|
314
|
+
"No chain ID available for RPC request. Select a network and retry."
|
|
315
|
+
);
|
|
316
|
+
const client = getClient({ chainId });
|
|
317
|
+
return await client.request({
|
|
318
|
+
method,
|
|
319
|
+
params
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
if (POPUP_METHODS.has(method)) {
|
|
323
|
+
const mockHandler = window.__SUPERFLUID_WALLET_MOCK_HANDLER__;
|
|
324
|
+
if (mockHandler) {
|
|
325
|
+
const popupParams = await resolvePopupParams(
|
|
326
|
+
method,
|
|
327
|
+
params,
|
|
328
|
+
getStoredChainIdHex(store),
|
|
329
|
+
getClient
|
|
330
|
+
);
|
|
331
|
+
const result = await Promise.resolve(mockHandler(method, popupParams));
|
|
332
|
+
if (method === "eth_requestAccounts") {
|
|
333
|
+
const { accounts, organizationId } = result[0];
|
|
334
|
+
store.update({ accounts, organizationId });
|
|
335
|
+
return accounts;
|
|
336
|
+
}
|
|
337
|
+
return result;
|
|
338
|
+
}
|
|
339
|
+
if (popup && !popup.closed) {
|
|
340
|
+
popup.close();
|
|
341
|
+
popup = null;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (!popup || popup.closed) {
|
|
345
|
+
const width = 360;
|
|
346
|
+
const height = 600;
|
|
347
|
+
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
348
|
+
const top = window.screenY + (window.outerHeight - height) / 2;
|
|
349
|
+
const { organizationId } = store.getState();
|
|
350
|
+
const orgParam = organizationId ? `&organizationId=${organizationId}` : "";
|
|
351
|
+
const chainIdHex = getStoredChainIdHex(store);
|
|
352
|
+
const chainParam = chainIdHex ? `&chainId=${encodeURIComponent(chainIdHex)}` : "";
|
|
353
|
+
const popupParams = await resolvePopupParams(method, params, chainIdHex, getClient);
|
|
354
|
+
const dappOriginParam = `&dappOrigin=${encodeURIComponent(window.location.origin)}`;
|
|
355
|
+
popup = window.open(
|
|
356
|
+
`${config.walletUrl}?request=${encodeURIComponent(JSON.stringify({ method, params: popupParams }))}${orgParam}${chainParam}${dappOriginParam}`,
|
|
357
|
+
"Superfluid Wallet",
|
|
358
|
+
`width=${width},height=${height},left=${left},top=${top}`
|
|
359
|
+
);
|
|
360
|
+
if (!popup) {
|
|
361
|
+
throw new Error("Popup blocked. Allow popups for this site and try again.");
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return new Promise((resolve, reject) => {
|
|
365
|
+
requestQueue[method] = { resolve, reject };
|
|
366
|
+
setTimeout(() => {
|
|
367
|
+
if (requestQueue[method]) {
|
|
368
|
+
delete requestQueue[method];
|
|
369
|
+
if (popup?.closed) {
|
|
370
|
+
reject(new Error("Wallet popup was closed before the request completed."));
|
|
371
|
+
} else {
|
|
372
|
+
reject(new Error("Wallet request timed out."));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}, config.popupTimeoutMs);
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
return {
|
|
379
|
+
request: requestImpl,
|
|
380
|
+
on: eventEmitter.on.bind(eventEmitter),
|
|
381
|
+
removeListener: eventEmitter.removeListener.bind(eventEmitter)
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function createWagmiGetClient(wagmiConfig) {
|
|
385
|
+
return (parameters) => {
|
|
386
|
+
const chainId = parameters?.chainId;
|
|
387
|
+
if (chainId === void 0) {
|
|
388
|
+
throw new Error("chainId is required to resolve a wagmi client");
|
|
389
|
+
}
|
|
390
|
+
return getClientForChain(wagmiConfig, chainId, "wagmi client lookup failed");
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
function getClientForChain(wagmiConfig, chainId, context) {
|
|
394
|
+
const transport = wagmiConfig.transports?.[chainId];
|
|
395
|
+
if (!transport) {
|
|
396
|
+
throw new Error(
|
|
397
|
+
`${context}: no wagmi transport for chain ${chainId}. Configure transports in createConfig.`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const chain = wagmiConfig.chains.find((c) => c.id === chainId);
|
|
401
|
+
if (!chain) {
|
|
402
|
+
throw new Error(
|
|
403
|
+
`${context}: chain ${chainId} is not configured in wagmi. Add it to createConfig({ chains }).`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
return viem.createClient({ chain, transport });
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/connector.ts
|
|
410
|
+
function createSuperfluidWalletConnector(config, store) {
|
|
411
|
+
return wagmi.createConnector((wagmiConfig) => {
|
|
412
|
+
let provider = null;
|
|
413
|
+
let accountsChanged;
|
|
414
|
+
let chainChanged;
|
|
415
|
+
let disconnect;
|
|
416
|
+
const getProvider = () => {
|
|
417
|
+
if (!provider) {
|
|
418
|
+
provider = createEIP1193Provider(config, store, createWagmiGetClient(wagmiConfig));
|
|
419
|
+
}
|
|
420
|
+
return provider;
|
|
421
|
+
};
|
|
422
|
+
return {
|
|
423
|
+
id: config.connectorId,
|
|
424
|
+
name: "Superfluid Wallet",
|
|
425
|
+
type: "superfluidWallet",
|
|
426
|
+
async connect(_params) {
|
|
427
|
+
const initialChainId = _params?.chainId ?? wagmiConfig.chains[0]?.id;
|
|
428
|
+
if (initialChainId) {
|
|
429
|
+
store.setChainId(initialChainId);
|
|
430
|
+
}
|
|
431
|
+
const p = await this.getProvider();
|
|
432
|
+
let accounts = _params?.isReconnecting ? await p.request({ method: "eth_accounts" }) : [];
|
|
433
|
+
if (!accounts.length) {
|
|
434
|
+
accounts = await p.request({ method: "eth_requestAccounts" });
|
|
435
|
+
}
|
|
436
|
+
if (!accountsChanged) {
|
|
437
|
+
accountsChanged = this.onAccountsChanged.bind(this);
|
|
438
|
+
p.on("accountsChanged", accountsChanged);
|
|
439
|
+
}
|
|
440
|
+
if (!chainChanged) {
|
|
441
|
+
chainChanged = this.onChainChanged.bind(this);
|
|
442
|
+
p.on("chainChanged", chainChanged);
|
|
443
|
+
}
|
|
444
|
+
if (!disconnect) {
|
|
445
|
+
disconnect = this.onDisconnect.bind(this);
|
|
446
|
+
p.on("disconnect", disconnect);
|
|
447
|
+
}
|
|
448
|
+
const chainId = Number(await p.request({ method: "eth_chainId" }));
|
|
449
|
+
return { accounts, chainId };
|
|
450
|
+
},
|
|
451
|
+
async getProvider() {
|
|
452
|
+
return getProvider();
|
|
453
|
+
},
|
|
454
|
+
async disconnect() {
|
|
455
|
+
const p = await this.getProvider();
|
|
456
|
+
if (accountsChanged) {
|
|
457
|
+
p.removeListener("accountsChanged", accountsChanged);
|
|
458
|
+
accountsChanged = void 0;
|
|
459
|
+
}
|
|
460
|
+
if (chainChanged) {
|
|
461
|
+
p.removeListener("chainChanged", chainChanged);
|
|
462
|
+
chainChanged = void 0;
|
|
463
|
+
}
|
|
464
|
+
if (disconnect) {
|
|
465
|
+
p.removeListener("disconnect", disconnect);
|
|
466
|
+
disconnect = void 0;
|
|
467
|
+
}
|
|
468
|
+
store.clear();
|
|
469
|
+
},
|
|
470
|
+
async getAccounts() {
|
|
471
|
+
const p = await this.getProvider();
|
|
472
|
+
return await p.request({ method: "eth_accounts" });
|
|
473
|
+
},
|
|
474
|
+
async getChainId() {
|
|
475
|
+
const p = await this.getProvider();
|
|
476
|
+
return Number(await p.request({ method: "eth_chainId" }));
|
|
477
|
+
},
|
|
478
|
+
async switchChain({ chainId }) {
|
|
479
|
+
const chain = wagmiConfig.chains.find((x) => x.id === chainId);
|
|
480
|
+
if (!chain) {
|
|
481
|
+
throw new viem.SwitchChainError(new core.ChainNotConfiguredError());
|
|
482
|
+
}
|
|
483
|
+
store.setChainId(chainId);
|
|
484
|
+
return chain;
|
|
485
|
+
},
|
|
486
|
+
async isAuthorized() {
|
|
487
|
+
try {
|
|
488
|
+
return (await this.getAccounts()).length > 0;
|
|
489
|
+
} catch {
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
onAccountsChanged(accounts) {
|
|
494
|
+
if (accounts.length === 0) this.onDisconnect();
|
|
495
|
+
else {
|
|
496
|
+
wagmiConfig.emitter.emit("change", {
|
|
497
|
+
accounts: accounts.map((x) => viem.getAddress(x))
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
onChainChanged(chain) {
|
|
502
|
+
const chainId = Number(chain);
|
|
503
|
+
store.setChainId(chainId);
|
|
504
|
+
wagmiConfig.emitter.emit("change", { chainId });
|
|
505
|
+
},
|
|
506
|
+
async onDisconnect() {
|
|
507
|
+
wagmiConfig.emitter.emit("disconnect");
|
|
508
|
+
store.clear();
|
|
509
|
+
const p = await this.getProvider();
|
|
510
|
+
if (accountsChanged) {
|
|
511
|
+
p.removeListener("accountsChanged", accountsChanged);
|
|
512
|
+
accountsChanged = void 0;
|
|
513
|
+
}
|
|
514
|
+
if (chainChanged) {
|
|
515
|
+
p.removeListener("chainChanged", chainChanged);
|
|
516
|
+
chainChanged = void 0;
|
|
517
|
+
}
|
|
518
|
+
if (disconnect) {
|
|
519
|
+
p.removeListener("disconnect", disconnect);
|
|
520
|
+
disconnect = void 0;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// src/index.ts
|
|
528
|
+
function superfluidWallet(config = {}) {
|
|
529
|
+
const resolved = resolveSuperfluidWalletConfig(config);
|
|
530
|
+
const store = createProviderStore(resolved.storageKey);
|
|
531
|
+
return {
|
|
532
|
+
connectorId: resolved.connectorId,
|
|
533
|
+
connector: () => createSuperfluidWalletConnector(resolved, store)
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
exports.DEFAULT_CONNECTOR_ID = DEFAULT_CONNECTOR_ID;
|
|
538
|
+
exports.DEFAULT_POPUP_TIMEOUT_MS = DEFAULT_POPUP_TIMEOUT_MS;
|
|
539
|
+
exports.DEFAULT_STORAGE_KEY = DEFAULT_STORAGE_KEY;
|
|
540
|
+
exports.DEFAULT_WALLET_URL = DEFAULT_WALLET_URL;
|
|
541
|
+
exports.superfluidWallet = superfluidWallet;
|
|
542
|
+
//# sourceMappingURL=index.cjs.map
|
|
543
|
+
//# sourceMappingURL=index.cjs.map
|