@chipi-stack/starknet-connector 0.3.0 → 0.4.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 +41 -0
- package/dist/index.cjs +286 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -6
- package/dist/index.d.ts +142 -6
- package/dist/index.js +285 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,12 +72,31 @@ chipi({
|
|
|
72
72
|
name: "Connect with Chipi", // display name
|
|
73
73
|
icon: "data:image/svg+xml;base64,...", // display icon
|
|
74
74
|
register: true, // self-register on window (default)
|
|
75
|
+
transport: {
|
|
76
|
+
openTimeoutMs: 180_000, // ready handshake; on timeout the popup is closed
|
|
77
|
+
requestTimeoutMs: 120_000, // per request; 0 disables
|
|
78
|
+
},
|
|
75
79
|
});
|
|
76
80
|
```
|
|
77
81
|
|
|
78
82
|
`chipi(options)` is a thin wrapper: `new ChipiConnector(options)` still works
|
|
79
83
|
identically if you prefer instantiating the class directly.
|
|
80
84
|
|
|
85
|
+
## Events and errors
|
|
86
|
+
|
|
87
|
+
- The connector forwards the wallet's `accountsChanged` / `networkChanged` as
|
|
88
|
+
starknet-react `change` events (`{ account, chainId }`); an empty account list
|
|
89
|
+
emits `disconnect`.
|
|
90
|
+
- `connect({ chainIdHint })` rejects with `code: "UNSUPPORTED_CHAIN"` for any
|
|
91
|
+
chain other than mainnet (`SN_MAIN`), before opening a popup.
|
|
92
|
+
- A request that gets no answer within `requestTimeoutMs` rejects with
|
|
93
|
+
`code: "REQUEST_TIMEOUT"`.
|
|
94
|
+
- If the user closes the wallet window, later requests reject with
|
|
95
|
+
`code: "POPUP_CLOSED"` instead of reopening it (browsers block popups outside
|
|
96
|
+
a click). Call `connect()` again from a click.
|
|
97
|
+
- `disconnect()` closes the popup and removes `window.starknet_chipi`; the next
|
|
98
|
+
`connect()` registers it again.
|
|
99
|
+
|
|
81
100
|
## Compatibility
|
|
82
101
|
|
|
83
102
|
- `@starknet-react/core` **>= 3** (peer) · tested against `5.x`
|
|
@@ -95,6 +114,28 @@ avoid a duplicate entry in a picker that already lists the connector
|
|
|
95
114
|
explicitly). It's a no-op during SSR. You can also call
|
|
96
115
|
`registerChipiWallet(swo)` directly.
|
|
97
116
|
|
|
117
|
+
### Wallet Standard (get-starknet v5+ discovery)
|
|
118
|
+
|
|
119
|
+
For dApps that discover wallets through the Wallet Standard
|
|
120
|
+
(`@starknet-io/get-starknet-discovery`, `@starknet-start/react`), register Chipi
|
|
121
|
+
as a `WalletWithStarknetFeatures` (`starknet:walletApi`, `standard:connect`,
|
|
122
|
+
`standard:disconnect`, `standard:events`) backed by the same popup:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { registerChipiStandardWallet } from "@chipi-stack/starknet-connector";
|
|
126
|
+
|
|
127
|
+
const unregister = registerChipiStandardWallet({
|
|
128
|
+
walletUrl: "https://wallet.chipipay.com", // default
|
|
129
|
+
});
|
|
130
|
+
// later: unregister();
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
It dispatches `wallet-standard:register-wallet` and answers
|
|
134
|
+
`wallet-standard:app-ready`, with no extra dependency. Accounts are on
|
|
135
|
+
`starknet:0x534e5f4d41494e` (mainnet). `connect({ silent: true })` never opens a
|
|
136
|
+
popup. Use `createChipiStandardWallet(options)` to build the wallet object
|
|
137
|
+
without registering it.
|
|
138
|
+
|
|
98
139
|
## Notes / limits (v1)
|
|
99
140
|
|
|
100
141
|
- **Popup-based** (external dApps). The in-app-browser ("parent") mode is in the
|
package/dist/index.cjs
CHANGED
|
@@ -15,6 +15,22 @@ function isChipiDappMessage(data) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
// src/transport.ts
|
|
18
|
+
function transportError(code, message) {
|
|
19
|
+
const err = Object.assign(new Error(message), { code });
|
|
20
|
+
err.name = code;
|
|
21
|
+
return err;
|
|
22
|
+
}
|
|
23
|
+
function stripUndefined(value) {
|
|
24
|
+
if (Array.isArray(value)) return value.map((v) => stripUndefined(v));
|
|
25
|
+
if (value === null || typeof value !== "object") return value;
|
|
26
|
+
const proto = Object.getPrototypeOf(value);
|
|
27
|
+
if (proto !== Object.prototype && proto !== null) return value;
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const [k, v] of Object.entries(value)) {
|
|
30
|
+
if (v !== void 0) out[k] = stripUndefined(v);
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
18
34
|
function deferred() {
|
|
19
35
|
let resolve;
|
|
20
36
|
let reject;
|
|
@@ -39,18 +55,19 @@ var ChipiPopupTransport = class {
|
|
|
39
55
|
this.readyDeferred = null;
|
|
40
56
|
this.openPromise = null;
|
|
41
57
|
this.closeWatch = null;
|
|
58
|
+
/** True once this transport opened a popup. A later request with no live
|
|
59
|
+
* popup means the user closed it: reject instead of reopening off-gesture. */
|
|
60
|
+
this.hadPopup = false;
|
|
42
61
|
this.onMessage = (e) => {
|
|
43
62
|
if (e.origin !== this.walletOrigin || !isChipiWalletMessage(e.data)) return;
|
|
44
|
-
if (this.target
|
|
63
|
+
if (!this.target || e.source !== this.target) return;
|
|
45
64
|
const msg = e.data;
|
|
46
65
|
if (msg.type === "ready") {
|
|
47
66
|
this.ready = true;
|
|
48
67
|
this.readyDeferred?.resolve();
|
|
49
68
|
this.readyDeferred = null;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.target.postMessage(p.message, this.walletOrigin);
|
|
53
|
-
}
|
|
69
|
+
for (const p of this.pending.values()) {
|
|
70
|
+
this.target.postMessage(p.message, this.walletOrigin);
|
|
54
71
|
}
|
|
55
72
|
return;
|
|
56
73
|
}
|
|
@@ -58,6 +75,7 @@ var ChipiPopupTransport = class {
|
|
|
58
75
|
const p = this.pending.get(msg.id);
|
|
59
76
|
if (!p) return;
|
|
60
77
|
this.pending.delete(msg.id);
|
|
78
|
+
if (p.timer) clearTimeout(p.timer);
|
|
61
79
|
if (msg.ok) p.resolve(msg.result);
|
|
62
80
|
else p.reject(Object.assign(new Error(msg.error.message), { code: msg.error.code }));
|
|
63
81
|
return;
|
|
@@ -116,9 +134,26 @@ var ChipiPopupTransport = class {
|
|
|
116
134
|
);
|
|
117
135
|
this.ownsTarget = true;
|
|
118
136
|
if (!this.target) throw Object.assign(new Error("Popup blocked"), { code: "popup_blocked" });
|
|
137
|
+
this.hadPopup = true;
|
|
119
138
|
}
|
|
139
|
+
const opened = this.target;
|
|
120
140
|
this.readyDeferred = deferred();
|
|
121
|
-
|
|
141
|
+
try {
|
|
142
|
+
await this.awaitReady();
|
|
143
|
+
} catch (err) {
|
|
144
|
+
if (this.target === opened) this.resetTarget();
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** Close the popup (if we own one) and forget the target + ready state. */
|
|
149
|
+
resetTarget() {
|
|
150
|
+
try {
|
|
151
|
+
if (this.ownsTarget) this.target?.close();
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
this.target = null;
|
|
155
|
+
this.ready = false;
|
|
156
|
+
this.readyDeferred = null;
|
|
122
157
|
}
|
|
123
158
|
async awaitReady() {
|
|
124
159
|
const timeoutMs = this.opts.openTimeoutMs ?? 18e4;
|
|
@@ -134,7 +169,10 @@ var ChipiPopupTransport = class {
|
|
|
134
169
|
}
|
|
135
170
|
/** Reject every in-flight request (popup closed / disconnected). */
|
|
136
171
|
rejectAllPending(message) {
|
|
137
|
-
for (const [, p] of this.pending)
|
|
172
|
+
for (const [, p] of this.pending) {
|
|
173
|
+
if (p.timer) clearTimeout(p.timer);
|
|
174
|
+
p.reject(Object.assign(new Error(message), { code: 4001 }));
|
|
175
|
+
}
|
|
138
176
|
this.pending.clear();
|
|
139
177
|
}
|
|
140
178
|
/** While requests are in flight, watch for the user closing the popup and
|
|
@@ -158,8 +196,22 @@ var ChipiPopupTransport = class {
|
|
|
158
196
|
this.closeWatch = null;
|
|
159
197
|
}
|
|
160
198
|
}
|
|
161
|
-
/**
|
|
199
|
+
/**
|
|
200
|
+
* Forward a get-starknet RPC call to the wallet, awaiting its response.
|
|
201
|
+
*
|
|
202
|
+
* The first request may open the popup. Once a popup has been opened, a
|
|
203
|
+
* request made after it was closed rejects with `code: "POPUP_CLOSED"`
|
|
204
|
+
* instead of calling `window.open` again: requests usually run outside a
|
|
205
|
+
* click, where browsers block popups. Reopen via `connect()` / `open()`
|
|
206
|
+
* from a click.
|
|
207
|
+
*/
|
|
162
208
|
async request(call) {
|
|
209
|
+
if (this.hadPopup && this.resolveMode() === "popup" && (!this.target || this.target.closed)) {
|
|
210
|
+
throw transportError(
|
|
211
|
+
"POPUP_CLOSED",
|
|
212
|
+
"The Chipi wallet window was closed. Call connect() again from a click."
|
|
213
|
+
);
|
|
214
|
+
}
|
|
163
215
|
await this.open();
|
|
164
216
|
if (this.ownsTarget) this.target?.focus();
|
|
165
217
|
const id = randomId();
|
|
@@ -168,10 +220,24 @@ var ChipiPopupTransport = class {
|
|
|
168
220
|
type: "rpc",
|
|
169
221
|
id,
|
|
170
222
|
origin: window.location.origin,
|
|
171
|
-
call
|
|
223
|
+
call: stripUndefined(call)
|
|
172
224
|
};
|
|
225
|
+
const timeoutMs = this.opts.requestTimeoutMs ?? 12e4;
|
|
173
226
|
return new Promise((resolve, reject) => {
|
|
174
|
-
|
|
227
|
+
const entry = { resolve, reject, message };
|
|
228
|
+
if (timeoutMs > 0 && Number.isFinite(timeoutMs)) {
|
|
229
|
+
entry.timer = setTimeout(() => {
|
|
230
|
+
if (this.pending.get(id) !== entry) return;
|
|
231
|
+
this.pending.delete(id);
|
|
232
|
+
reject(
|
|
233
|
+
transportError(
|
|
234
|
+
"REQUEST_TIMEOUT",
|
|
235
|
+
`The Chipi wallet did not answer "${call.type}" within ${timeoutMs} ms.`
|
|
236
|
+
)
|
|
237
|
+
);
|
|
238
|
+
}, timeoutMs);
|
|
239
|
+
}
|
|
240
|
+
this.pending.set(id, entry);
|
|
175
241
|
this.target.postMessage(message, this.walletOrigin);
|
|
176
242
|
this.startCloseWatch();
|
|
177
243
|
});
|
|
@@ -179,12 +245,8 @@ var ChipiPopupTransport = class {
|
|
|
179
245
|
/** Close the popup (if we own one) + reject in-flight requests. */
|
|
180
246
|
close() {
|
|
181
247
|
this.stopCloseWatch();
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
} catch {
|
|
185
|
-
}
|
|
186
|
-
this.target = null;
|
|
187
|
-
this.ready = false;
|
|
248
|
+
this.readyDeferred?.reject(Object.assign(new Error("disconnected"), { code: 4001 }));
|
|
249
|
+
this.resetTarget();
|
|
188
250
|
this.rejectAllPending("disconnected");
|
|
189
251
|
if (this.listening && typeof window !== "undefined") {
|
|
190
252
|
window.removeEventListener("message", this.onMessage);
|
|
@@ -215,13 +277,46 @@ function registerChipiWallet(wallet, target = typeof window !== "undefined" ? wi
|
|
|
215
277
|
var CHIPI_ICON = "data:image/png;base64,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";
|
|
216
278
|
|
|
217
279
|
// src/connector.ts
|
|
218
|
-
var SN_MAIN = BigInt(
|
|
280
|
+
var SN_MAIN = BigInt(starknet.constants.StarknetChainId.SN_MAIN);
|
|
281
|
+
function toChainId(value) {
|
|
282
|
+
if (typeof value === "bigint") return value;
|
|
283
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
284
|
+
try {
|
|
285
|
+
return BigInt(value);
|
|
286
|
+
} catch {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
219
292
|
var ChipiConnector = class extends core.Connector {
|
|
220
293
|
constructor(options = {}) {
|
|
221
294
|
super();
|
|
222
295
|
this._account = null;
|
|
223
296
|
this._swo = null;
|
|
224
297
|
this._registration = null;
|
|
298
|
+
this.onAccountsChanged = (data) => {
|
|
299
|
+
const accounts = Array.isArray(data) ? data : [];
|
|
300
|
+
const account = accounts[0];
|
|
301
|
+
if (typeof account === "string" && account) {
|
|
302
|
+
this._account = account;
|
|
303
|
+
this.emitEvent("change", { account, chainId: SN_MAIN });
|
|
304
|
+
} else {
|
|
305
|
+
this._account = null;
|
|
306
|
+
this.emitEvent("disconnect");
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
this.onNetworkChanged = (data) => {
|
|
310
|
+
const payload = typeof data === "object" && data !== null && !Array.isArray(data) ? data : { chainId: data };
|
|
311
|
+
const chainId = toChainId(payload.chainId);
|
|
312
|
+
const accounts = Array.isArray(payload.accounts) ? payload.accounts : [];
|
|
313
|
+
const next = typeof accounts[0] === "string" && accounts[0] ? accounts[0] : this._account;
|
|
314
|
+
if (next) this._account = next;
|
|
315
|
+
const change = {};
|
|
316
|
+
if (chainId !== void 0) change.chainId = chainId;
|
|
317
|
+
if (next) change.account = next;
|
|
318
|
+
this.emitEvent("change", change);
|
|
319
|
+
};
|
|
225
320
|
const walletUrl = options.walletUrl ?? options.transport?.walletUrl ?? "https://wallet.chipipay.com";
|
|
226
321
|
this.transport = new ChipiPopupTransport({
|
|
227
322
|
...options.transport,
|
|
@@ -232,7 +327,8 @@ var ChipiConnector = class extends core.Connector {
|
|
|
232
327
|
this._id = options.id ?? "chipi";
|
|
233
328
|
this._name = options.name ?? "Connect with Chipi";
|
|
234
329
|
this._icon = options.icon ?? CHIPI_ICON;
|
|
235
|
-
|
|
330
|
+
this._autoRegister = options.register !== false;
|
|
331
|
+
if (this._autoRegister) this.register();
|
|
236
332
|
}
|
|
237
333
|
/**
|
|
238
334
|
* Announce this wallet to scanning dApps (`window.starknet_chipi` +
|
|
@@ -286,7 +382,22 @@ var ChipiConnector = class extends core.Connector {
|
|
|
286
382
|
};
|
|
287
383
|
return this._swo;
|
|
288
384
|
}
|
|
289
|
-
|
|
385
|
+
/**
|
|
386
|
+
* Open the hosted wallet (call from a click: it opens a popup) and request
|
|
387
|
+
* the account. Chipi is mainnet-only: a `chainIdHint` other than SN_MAIN
|
|
388
|
+
* rejects before any popup opens.
|
|
389
|
+
*/
|
|
390
|
+
async connect(args = {}) {
|
|
391
|
+
if (args.chainIdHint !== void 0 && BigInt(args.chainIdHint) !== SN_MAIN) {
|
|
392
|
+
throw Object.assign(
|
|
393
|
+
new Error(
|
|
394
|
+
`Chipi is mainnet-only: chainIdHint 0x${BigInt(args.chainIdHint).toString(16)} is not SN_MAIN.`
|
|
395
|
+
),
|
|
396
|
+
{ code: "UNSUPPORTED_CHAIN" }
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (this._autoRegister) this.register();
|
|
400
|
+
this.subscribe();
|
|
290
401
|
await this.transport.open();
|
|
291
402
|
const accounts = await this.transport.request({ type: "wallet_requestAccounts" });
|
|
292
403
|
const account = accounts?.[0];
|
|
@@ -297,16 +408,27 @@ var ChipiConnector = class extends core.Connector {
|
|
|
297
408
|
return data;
|
|
298
409
|
}
|
|
299
410
|
async disconnect() {
|
|
411
|
+
this.unsubscribe();
|
|
300
412
|
this.transport.close();
|
|
301
413
|
this._account = null;
|
|
414
|
+
this.unregister();
|
|
302
415
|
this._swo = null;
|
|
303
416
|
this.emitEvent("disconnect");
|
|
304
417
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
418
|
+
/** Forward the wallet's account/network events as starknet-react events. */
|
|
419
|
+
subscribe() {
|
|
420
|
+
this.unsubscribe();
|
|
421
|
+
this.transport.on("accountsChanged", this.onAccountsChanged);
|
|
422
|
+
this.transport.on("networkChanged", this.onNetworkChanged);
|
|
423
|
+
}
|
|
424
|
+
unsubscribe() {
|
|
425
|
+
this.transport.off("accountsChanged", this.onAccountsChanged);
|
|
426
|
+
this.transport.off("networkChanged", this.onNetworkChanged);
|
|
427
|
+
}
|
|
308
428
|
emitEvent(event, data) {
|
|
309
|
-
this
|
|
429
|
+
const emitter = this;
|
|
430
|
+
if (data === void 0) emitter.emit(event);
|
|
431
|
+
else emitter.emit(event, data);
|
|
310
432
|
}
|
|
311
433
|
async account(provider) {
|
|
312
434
|
if (!this._account) throw new Error("chipi_not_connected");
|
|
@@ -325,13 +447,154 @@ function chipi(options) {
|
|
|
325
447
|
return new ChipiConnector(options);
|
|
326
448
|
}
|
|
327
449
|
|
|
450
|
+
// src/standard.ts
|
|
451
|
+
var CHIPI_STARKNET_MAINNET_CHAIN = "starknet:0x534e5f4d41494e";
|
|
452
|
+
function toStarknetChain(value) {
|
|
453
|
+
if (typeof value !== "string" && typeof value !== "bigint" && typeof value !== "number") {
|
|
454
|
+
return void 0;
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
return `starknet:0x${BigInt(value).toString(16)}`;
|
|
458
|
+
} catch {
|
|
459
|
+
return void 0;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function createChipiStandardWallet(options = {}) {
|
|
463
|
+
const transport = new ChipiPopupTransport({
|
|
464
|
+
...options.transport,
|
|
465
|
+
walletUrl: options.walletUrl ?? "https://wallet.chipipay.com",
|
|
466
|
+
mode: "popup"
|
|
467
|
+
});
|
|
468
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
469
|
+
let current = null;
|
|
470
|
+
const accounts = () => current ? [
|
|
471
|
+
{
|
|
472
|
+
address: current.address,
|
|
473
|
+
publicKey: new Uint8Array(),
|
|
474
|
+
chains: [current.chain],
|
|
475
|
+
features: []
|
|
476
|
+
}
|
|
477
|
+
] : [];
|
|
478
|
+
const emitChange = () => {
|
|
479
|
+
const properties = { accounts: accounts() };
|
|
480
|
+
for (const listener of [...listeners]) listener(properties);
|
|
481
|
+
};
|
|
482
|
+
const setDisconnected = () => {
|
|
483
|
+
if (!current) return;
|
|
484
|
+
current = null;
|
|
485
|
+
emitChange();
|
|
486
|
+
};
|
|
487
|
+
const onAccountsChanged = (data) => {
|
|
488
|
+
const list = Array.isArray(data) ? data : [];
|
|
489
|
+
const address = list[0];
|
|
490
|
+
if (typeof address !== "string" || !address) return setDisconnected();
|
|
491
|
+
if (!current) return;
|
|
492
|
+
current = { ...current, address };
|
|
493
|
+
emitChange();
|
|
494
|
+
};
|
|
495
|
+
const onNetworkChanged = (data) => {
|
|
496
|
+
const payload = typeof data === "object" && data !== null && !Array.isArray(data) ? data : { chainId: data };
|
|
497
|
+
const chain = toStarknetChain(payload.chainId);
|
|
498
|
+
if (!chain) return setDisconnected();
|
|
499
|
+
if (!current) return;
|
|
500
|
+
const list = Array.isArray(payload.accounts) ? payload.accounts : [];
|
|
501
|
+
const address = typeof list[0] === "string" && list[0] ? list[0] : current.address;
|
|
502
|
+
current = { address, chain };
|
|
503
|
+
emitChange();
|
|
504
|
+
};
|
|
505
|
+
transport.on("accountsChanged", onAccountsChanged);
|
|
506
|
+
transport.on("networkChanged", onNetworkChanged);
|
|
507
|
+
const request = ((call) => transport.request(call));
|
|
508
|
+
const features = {
|
|
509
|
+
"starknet:walletApi": {
|
|
510
|
+
version: "1.0.0",
|
|
511
|
+
request,
|
|
512
|
+
walletVersion: "1.0.0",
|
|
513
|
+
id: "chipi"
|
|
514
|
+
},
|
|
515
|
+
"standard:connect": {
|
|
516
|
+
version: "1.0.0",
|
|
517
|
+
connect: async (input) => {
|
|
518
|
+
if (current || input?.silent) return { accounts: accounts() };
|
|
519
|
+
await transport.open();
|
|
520
|
+
const result = await transport.request({ type: "wallet_requestAccounts" });
|
|
521
|
+
const list = Array.isArray(result) ? result : [];
|
|
522
|
+
const address = list[0];
|
|
523
|
+
if (typeof address !== "string" || !address) return { accounts: [] };
|
|
524
|
+
current = { address, chain: CHIPI_STARKNET_MAINNET_CHAIN };
|
|
525
|
+
emitChange();
|
|
526
|
+
return { accounts: accounts() };
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
"standard:disconnect": {
|
|
530
|
+
version: "1.0.0",
|
|
531
|
+
disconnect: async () => {
|
|
532
|
+
transport.close();
|
|
533
|
+
setDisconnected();
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
"standard:events": {
|
|
537
|
+
version: "1.0.0",
|
|
538
|
+
on: (_event, listener) => {
|
|
539
|
+
listeners.add(listener);
|
|
540
|
+
return () => {
|
|
541
|
+
listeners.delete(listener);
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
return {
|
|
547
|
+
version: "1.0.0",
|
|
548
|
+
name: options.name ?? "Chipi",
|
|
549
|
+
icon: options.icon ?? CHIPI_ICON,
|
|
550
|
+
chains: [CHIPI_STARKNET_MAINNET_CHAIN],
|
|
551
|
+
get accounts() {
|
|
552
|
+
return accounts();
|
|
553
|
+
},
|
|
554
|
+
features
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function registerChipiStandardWallet(options = {}, target = typeof window !== "undefined" ? window : void 0) {
|
|
558
|
+
if (!target) return () => {
|
|
559
|
+
};
|
|
560
|
+
const wallet = createChipiStandardWallet(options);
|
|
561
|
+
const unregisters = [];
|
|
562
|
+
const callback = ({ register }) => {
|
|
563
|
+
unregisters.push(register(wallet));
|
|
564
|
+
};
|
|
565
|
+
const onAppReady = (event) => {
|
|
566
|
+
const api = event.detail;
|
|
567
|
+
if (api && typeof api.register === "function") callback(api);
|
|
568
|
+
};
|
|
569
|
+
try {
|
|
570
|
+
target.dispatchEvent(
|
|
571
|
+
new CustomEvent("wallet-standard:register-wallet", {
|
|
572
|
+
detail: callback,
|
|
573
|
+
bubbles: false,
|
|
574
|
+
cancelable: false,
|
|
575
|
+
composed: false
|
|
576
|
+
})
|
|
577
|
+
);
|
|
578
|
+
} catch (error) {
|
|
579
|
+
console.error("wallet-standard:register-wallet event could not be dispatched\n", error);
|
|
580
|
+
}
|
|
581
|
+
target.addEventListener("wallet-standard:app-ready", onAppReady);
|
|
582
|
+
return () => {
|
|
583
|
+
target.removeEventListener("wallet-standard:app-ready", onAppReady);
|
|
584
|
+
for (const unregister of unregisters.splice(0)) unregister();
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
exports.CHIPI_STARKNET_MAINNET_CHAIN = CHIPI_STARKNET_MAINNET_CHAIN;
|
|
328
589
|
exports.CHIPI_WC = CHIPI_WC;
|
|
329
590
|
exports.CHIPI_WINDOW_KEY = CHIPI_WINDOW_KEY;
|
|
330
591
|
exports.ChipiConnector = ChipiConnector;
|
|
331
592
|
exports.ChipiPopupTransport = ChipiPopupTransport;
|
|
332
593
|
exports.chipi = chipi;
|
|
594
|
+
exports.createChipiStandardWallet = createChipiStandardWallet;
|
|
333
595
|
exports.isChipiDappMessage = isChipiDappMessage;
|
|
334
596
|
exports.isChipiWalletMessage = isChipiWalletMessage;
|
|
597
|
+
exports.registerChipiStandardWallet = registerChipiStandardWallet;
|
|
335
598
|
exports.registerChipiWallet = registerChipiWallet;
|
|
336
599
|
//# sourceMappingURL=index.cjs.map
|
|
337
600
|
//# sourceMappingURL=index.cjs.map
|