@phantom/browser-injected-sdk 1.0.0-beta.9 → 1.0.2

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.
@@ -33,10 +33,134 @@ var __privateMethod = (obj, member, method) => {
33
33
  // src/ethereum/index.ts
34
34
  var ethereum_exports = {};
35
35
  __export(ethereum_exports, {
36
- createEthereumPlugin: () => createEthereumPlugin
36
+ createEthereumPlugin: () => createEthereumPlugin,
37
+ createSiweMessage: () => createSiweMessage
37
38
  });
38
39
  module.exports = __toCommonJS(ethereum_exports);
39
40
 
41
+ // src/ethereum/siwe.ts
42
+ var ADDRESS_REGEX = /^0x[a-fA-F0-9]{40}$/;
43
+ var DOMAIN_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:[0-9]{1,5})?$/;
44
+ var IP_REGEX = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(:[0-9]{1,5})?$/;
45
+ var LOCALHOST_REGEX = /^localhost(:[0-9]{1,5})?$/;
46
+ var NONCE_REGEX = /^[a-zA-Z0-9]{8,}$/;
47
+ var SCHEME_REGEX = /^([a-zA-Z][a-zA-Z0-9+-.]*)$/;
48
+ function createSiweMessage({
49
+ address,
50
+ chainId,
51
+ domain,
52
+ nonce,
53
+ uri,
54
+ version,
55
+ scheme,
56
+ statement: _statement,
57
+ requestId,
58
+ resources,
59
+ issuedAt = /* @__PURE__ */ new Date(),
60
+ expirationTime,
61
+ notBefore
62
+ }) {
63
+ if (!ADDRESS_REGEX.test(address)) {
64
+ throw new Error("address must be a hex value of 20 bytes (40 hex characters).");
65
+ }
66
+ if (chainId !== Math.floor(chainId)) {
67
+ throw new Error("chainId must be a EIP-155 chain ID.");
68
+ }
69
+ if (!(DOMAIN_REGEX.test(domain) || IP_REGEX.test(domain) || LOCALHOST_REGEX.test(domain))) {
70
+ throw new Error("domain must be an RFC 3986 authority.");
71
+ }
72
+ if (!NONCE_REGEX.test(nonce)) {
73
+ throw new Error("nonce must be at least 8 characters.");
74
+ }
75
+ if (!_isUri(uri)) {
76
+ throw new Error("uri must be a RFC 3986 URI referring to the resource that is the subject of the signing.");
77
+ }
78
+ if (version !== "1") {
79
+ throw new Error("version must be '1'.");
80
+ }
81
+ if (scheme && !SCHEME_REGEX.test(scheme)) {
82
+ throw new Error("scheme must be an RFC 3986 URI scheme.");
83
+ }
84
+ if (_statement?.includes("\n")) {
85
+ throw new Error("statement must not include '\\n'.");
86
+ }
87
+ const origin = scheme ? `${scheme}://${domain}` : domain;
88
+ const statement = _statement ? `${_statement}
89
+ ` : "";
90
+ const prefix = `${origin} wants you to sign in with your Ethereum account:
91
+ ${address}
92
+
93
+ ${statement}`;
94
+ let suffix = `URI: ${uri}
95
+ Version: ${version}
96
+ Chain ID: ${chainId}
97
+ Nonce: ${nonce}
98
+ Issued At: ${issuedAt.toISOString()}`;
99
+ if (expirationTime) {
100
+ suffix += `
101
+ Expiration Time: ${expirationTime.toISOString()}`;
102
+ }
103
+ if (notBefore) {
104
+ suffix += `
105
+ Not Before: ${notBefore.toISOString()}`;
106
+ }
107
+ if (requestId) {
108
+ suffix += `
109
+ Request ID: ${requestId}`;
110
+ }
111
+ if (resources) {
112
+ let content = "\nResources:";
113
+ for (const resource of resources) {
114
+ if (!_isUri(resource)) {
115
+ throw new Error("resources must be RFC 3986 URIs.");
116
+ }
117
+ content += `
118
+ - ${resource}`;
119
+ }
120
+ suffix += content;
121
+ }
122
+ return `${prefix}
123
+ ${suffix}`;
124
+ }
125
+ function _isUri(value) {
126
+ if (/[^a-z0-9:/?#[\]@!$&'()*+,;=.\-_~%]/i.test(value))
127
+ return false;
128
+ if (/%[^0-9a-f]/i.test(value))
129
+ return false;
130
+ if (/%[0-9a-f](:?[^0-9a-f]|$)/i.test(value))
131
+ return false;
132
+ const splitted = splitUri(value);
133
+ const scheme = splitted[1];
134
+ const authority = splitted[2];
135
+ const path = splitted[3];
136
+ const query = splitted[4];
137
+ const fragment = splitted[5];
138
+ if (!(scheme?.length && path.length >= 0))
139
+ return false;
140
+ if (authority?.length) {
141
+ if (!(path.length === 0 || /^\//.test(path)))
142
+ return false;
143
+ } else {
144
+ if (/^\/\//.test(path))
145
+ return false;
146
+ }
147
+ if (!/^[a-z][a-z0-9+\-.]*$/.test(scheme.toLowerCase()))
148
+ return false;
149
+ let out = "";
150
+ out += `${scheme}:`;
151
+ if (authority?.length)
152
+ out += `//${authority}`;
153
+ out += path;
154
+ if (query?.length)
155
+ out += `?${query}`;
156
+ if (fragment?.length)
157
+ out += `#${fragment}`;
158
+ return out;
159
+ }
160
+ function splitUri(value) {
161
+ return value.match(/(?:([^:/?#]+):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/);
162
+ }
163
+
40
164
  // src/ethereum/strategies/injected.ts
41
165
  var MAX_RETRIES = 4;
42
166
  var BASE_DELAY = 100;
@@ -153,7 +277,7 @@ var InjectedEthereumStrategy = class {
153
277
  if (!provider) {
154
278
  throw new Error("Provider not found.");
155
279
  }
156
- const message = `Sign in to ${signInData.domain || "this application"}`;
280
+ const message = createSiweMessage(signInData);
157
281
  const address = provider.selectedAddress;
158
282
  if (!address) {
159
283
  throw new Error("No address available.");
@@ -249,7 +373,7 @@ function addEventListener(event, callback) {
249
373
  eventListeners.set(event, /* @__PURE__ */ new Set());
250
374
  }
251
375
  const listeners = eventListeners.get(event);
252
- listeners.add(callback);
376
+ listeners?.add(callback);
253
377
  return () => removeEventListener(event, callback);
254
378
  }
255
379
  function removeEventListener(event, callback) {
@@ -323,16 +447,6 @@ async function getAccounts() {
323
447
  }
324
448
 
325
449
  // src/ethereum/signMessage.ts
326
- async function signMessage(message, address) {
327
- const provider = await getProvider();
328
- if (!provider) {
329
- throw new Error("Provider not found.");
330
- }
331
- if (!provider.isConnected) {
332
- await provider.connect({ onlyIfTrusted: false });
333
- }
334
- return provider.signMessage(message, address);
335
- }
336
450
  async function signPersonalMessage(message, address) {
337
451
  const provider = await getProvider();
338
452
  if (!provider) {
@@ -354,18 +468,6 @@ async function signTypedData(typedData, address) {
354
468
  return provider.signTypedData(typedData, address);
355
469
  }
356
470
 
357
- // src/ethereum/signIn.ts
358
- async function signIn(signInData) {
359
- const provider = await getProvider();
360
- if (!provider) {
361
- throw new Error("Provider not found.");
362
- }
363
- if (!provider.isConnected) {
364
- await provider.connect({ onlyIfTrusted: false });
365
- }
366
- return provider.signIn(signInData);
367
- }
368
-
369
471
  // src/ethereum/sendTransaction.ts
370
472
  async function sendTransaction(transaction) {
371
473
  const provider = await getProvider();
@@ -405,51 +507,127 @@ async function switchChain(chainId) {
405
507
  }
406
508
 
407
509
  // src/ethereum/plugin.ts
408
- var ethereum = {
409
- connect,
410
- disconnect,
411
- getAccounts,
412
- signMessage,
413
- signPersonalMessage,
414
- signTypedData,
415
- signIn,
416
- sendTransaction,
417
- signTransaction,
418
- getChainId,
419
- switchChain,
420
- getProvider,
421
- addEventListener,
422
- removeEventListener
423
- };
424
- async function bindProviderEvents() {
425
- try {
426
- const strategy = await getProvider();
427
- const provider = strategy.getProvider();
428
- if (provider) {
429
- provider.on("connect", () => {
430
- provider.request({ method: "eth_accounts" }).then((accounts) => {
431
- if (accounts?.length > 0)
510
+ var Ethereum = class {
511
+ constructor() {
512
+ this._chainId = "0x1";
513
+ this._accounts = [];
514
+ this.bindProviderEvents();
515
+ }
516
+ get connected() {
517
+ return this._accounts.length > 0;
518
+ }
519
+ get chainId() {
520
+ return this._chainId;
521
+ }
522
+ get accounts() {
523
+ return this._accounts;
524
+ }
525
+ async request(args) {
526
+ const provider = await getProvider();
527
+ if (!provider) {
528
+ throw new Error("Provider not found.");
529
+ }
530
+ const providerInstance = provider.getProvider();
531
+ if (!providerInstance) {
532
+ throw new Error("Provider instance not found.");
533
+ }
534
+ return providerInstance.request(args);
535
+ }
536
+ async connect() {
537
+ const accounts = await connect();
538
+ this._accounts = accounts;
539
+ return accounts;
540
+ }
541
+ async disconnect() {
542
+ await disconnect();
543
+ this._accounts = [];
544
+ }
545
+ signPersonalMessage(message, address) {
546
+ return signPersonalMessage(message, address);
547
+ }
548
+ signTypedData(data, address) {
549
+ return signTypedData(data, address);
550
+ }
551
+ signTransaction(transaction) {
552
+ return signTransaction(transaction);
553
+ }
554
+ sendTransaction(transaction) {
555
+ return sendTransaction(transaction);
556
+ }
557
+ async switchChain(chainId) {
558
+ const hexChainId = typeof chainId === "string" ? chainId.toLowerCase().startsWith("0x") ? chainId.toLowerCase() : `0x${parseInt(chainId, 10).toString(16)}` : `0x${chainId.toString(16)}`;
559
+ await switchChain(hexChainId);
560
+ this._chainId = hexChainId;
561
+ }
562
+ async getChainId() {
563
+ const chainId = await getChainId();
564
+ const parsed = parseInt(chainId, 16);
565
+ this._chainId = chainId;
566
+ return parsed;
567
+ }
568
+ async getAccounts() {
569
+ const accounts = await getAccounts();
570
+ this._accounts = accounts;
571
+ return accounts;
572
+ }
573
+ isConnected() {
574
+ return this._accounts.length > 0;
575
+ }
576
+ on(event, listener) {
577
+ addEventListener(event, listener);
578
+ }
579
+ off(event, listener) {
580
+ removeEventListener(event, listener);
581
+ }
582
+ async bindProviderEvents() {
583
+ try {
584
+ const strategy = await getProvider();
585
+ const provider = strategy.getProvider();
586
+ if (provider) {
587
+ provider.on("connect", async () => {
588
+ try {
589
+ const accounts = await provider.request({ method: "eth_accounts" });
590
+ if (accounts?.length > 0) {
591
+ this._accounts = accounts;
592
+ triggerEvent("connect", accounts);
593
+ }
594
+ } catch {
595
+ }
596
+ });
597
+ provider.on("disconnect", () => {
598
+ this._accounts = [];
599
+ const error = {
600
+ code: 4900,
601
+ message: "Provider disconnected"
602
+ };
603
+ triggerEvent("disconnect", error);
604
+ });
605
+ provider.on("accountsChanged", (accounts) => {
606
+ this._accounts = accounts;
607
+ triggerEvent("accountsChanged", accounts);
608
+ if (accounts && accounts.length > 0) {
432
609
  triggerEvent("connect", accounts);
433
- }).catch(() => {
610
+ }
434
611
  });
435
- });
436
- provider.on("disconnect", () => triggerEvent("disconnect", []));
437
- provider.on("accountsChanged", (accounts) => triggerEvent("accountsChanged", accounts));
438
- provider.on("chainChanged", (chainId) => triggerEvent("chainChanged", chainId));
612
+ provider.on("chainChanged", (chainId) => {
613
+ this._chainId = chainId;
614
+ triggerEvent("chainChanged", chainId);
615
+ });
616
+ }
617
+ } catch (error) {
439
618
  }
440
- } catch (error) {
441
619
  }
442
- }
620
+ };
443
621
  function createEthereumPlugin() {
444
622
  return {
445
623
  name: "ethereum",
446
624
  create: () => {
447
- bindProviderEvents();
448
- return ethereum;
625
+ return new Ethereum();
449
626
  }
450
627
  };
451
628
  }
452
629
  // Annotate the CommonJS export names for ESM import in node:
453
630
  0 && (module.exports = {
454
- createEthereumPlugin
631
+ createEthereumPlugin,
632
+ createSiweMessage
455
633
  });
@@ -1,8 +1,10 @@
1
1
  import {
2
- createEthereumPlugin
3
- } from "../chunk-MDTCVDFZ.mjs";
2
+ createEthereumPlugin,
3
+ createSiweMessage
4
+ } from "../chunk-CS23VDDD.mjs";
4
5
  import "../chunk-WUKYLWAZ.mjs";
5
6
  import "../chunk-GV6AIHPN.mjs";
6
7
  export {
7
- createEthereumPlugin
8
+ createEthereumPlugin,
9
+ createSiweMessage
8
10
  };
@@ -0,0 +1,93 @@
1
+ import { IEthereumChain } from '@phantom/chain-interfaces';
2
+
3
+ declare function isInstalled(): boolean;
4
+
5
+ type Extension = {
6
+ isInstalled: typeof isInstalled;
7
+ };
8
+ declare function createExtensionPlugin(): Plugin<Extension>;
9
+
10
+ declare module "../index" {
11
+ interface Phantom {
12
+ extension: Extension;
13
+ }
14
+ }
15
+
16
+ type EthereumTransaction = {
17
+ to?: string;
18
+ from?: string;
19
+ value?: string;
20
+ gas?: string;
21
+ gasPrice?: string;
22
+ maxFeePerGas?: string;
23
+ maxPriorityFeePerGas?: string;
24
+ data?: string;
25
+ nonce?: string;
26
+ type?: string;
27
+ chainId?: string;
28
+ };
29
+ type EthereumSignInData = {
30
+ address: `0x${string}`;
31
+ chainId: number;
32
+ domain: string;
33
+ expirationTime?: Date | undefined;
34
+ issuedAt?: Date | undefined;
35
+ nonce: string;
36
+ notBefore?: Date | undefined;
37
+ requestId?: string | undefined;
38
+ resources?: Array<string> | undefined;
39
+ scheme?: string | undefined;
40
+ statement?: string | undefined;
41
+ uri: string;
42
+ version: "1";
43
+ };
44
+ type EthereumEventType = "connect" | "disconnect" | "accountsChanged" | "chainChanged";
45
+ interface PhantomEthereumProvider {
46
+ isPhantom: boolean;
47
+ selectedAddress: string | null;
48
+ chainId: string;
49
+ isConnected: boolean;
50
+ request: <T = any>(args: {
51
+ method: string;
52
+ params?: any[];
53
+ }) => Promise<T>;
54
+ on: (event: EthereumEventType, handler: (...args: any[]) => void) => void;
55
+ off: (event: EthereumEventType, handler: (...args: any[]) => void) => void;
56
+ removeAllListeners: (event?: EthereumEventType) => void;
57
+ }
58
+
59
+ declare function createEthereumPlugin(): Plugin<IEthereumChain>;
60
+
61
+ /**
62
+ * Creates an EIP-4361 Sign In With Ethereum message.
63
+ *
64
+ * Adapted from viem's createSiweMessage implementation:
65
+ * https://github.com/wevm/viem/blob/53d302049e166706fecde453ea984284dd180ca6/src/utils/siwe/createSiweMessage.ts
66
+ *
67
+ * Copyright (c) 2023-present weth, LLC
68
+ * Licensed under the MIT License.
69
+ */
70
+ declare function createSiweMessage({ address, chainId, domain, nonce, uri, version, scheme, statement: _statement, requestId, resources, issuedAt, expirationTime, notBefore, }: EthereumSignInData): string;
71
+
72
+ declare module "../index" {
73
+ interface Phantom {
74
+ ethereum: IEthereumChain;
75
+ }
76
+ }
77
+
78
+ type Plugin<T> = {
79
+ name: string;
80
+ create: () => T;
81
+ };
82
+ type CreatePhantomConfig = {
83
+ plugins?: Plugin<unknown>[];
84
+ };
85
+ interface Phantom {
86
+ }
87
+ /**
88
+ * Creates a Phantom instance with the provided plugins.
89
+ * Each plugin extends the Phantom interface via declaration merging.
90
+ */
91
+ declare function createPhantom({ plugins }: CreatePhantomConfig): Phantom;
92
+
93
+ export { CreatePhantomConfig as C, EthereumTransaction as E, Plugin as P, createSiweMessage as a, PhantomEthereumProvider as b, createEthereumPlugin as c, EthereumSignInData as d, EthereumEventType as e, Phantom as f, createPhantom as g, createExtensionPlugin as h, Extension as i, isInstalled as j };
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
- export { C as CreatePhantomConfig, i as Extension, f as Phantom, P as Plugin, c as createEthereumPlugin, h as createExtensionPlugin, g as createPhantom, j as isPhantomExtensionInstalled } from './index-3a750f13.js';
1
+ export { C as CreatePhantomConfig, i as Extension, f as Phantom, P as Plugin, c as createEthereumPlugin, h as createExtensionPlugin, g as createPhantom, a as createSiweMessage, j as isPhantomExtensionInstalled } from './index-673af1e4.js';
2
+ import '@phantom/chain-interfaces';