@dynamic-labs/solana 1.1.0-alpha.21 → 1.1.0-alpha.23

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/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
1
 
2
+ ## [1.1.0-alpha.23](https://github.com/dynamic-labs/DynamicAuth/compare/v1.1.0-alpha.22...v1.1.0-alpha.23) (2024-02-01)
3
+
4
+
5
+ ### Features
6
+
7
+ * bitcoin signPsbt ([3c964de](https://github.com/dynamic-labs/DynamicAuth/commit/3c964dea8a55debaf184c5a94f0f5fabdda3c877))
8
+ * embedded wallet email auth flow ([#4353](https://github.com/dynamic-labs/DynamicAuth/issues/4353)) ([4875da3](https://github.com/dynamic-labs/DynamicAuth/commit/4875da32c47c27facef1b1cdbdc214566bbfd171))
9
+
10
+ ## [1.1.0-alpha.22](https://github.com/dynamic-labs/DynamicAuth/compare/v1.1.0-alpha.21...v1.1.0-alpha.22) (2024-02-01)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * onAuthFlowClose not being called ([#4563](https://github.com/dynamic-labs/DynamicAuth/issues/4563)) ([c4b2648](https://github.com/dynamic-labs/DynamicAuth/commit/c4b264885b7dba6e204ef49bf642d25c7d287b04))
16
+
2
17
  ## [1.1.0-alpha.21](https://github.com/dynamic-labs/DynamicAuth/compare/v1.1.0-alpha.20...v1.1.0-alpha.21) (2024-02-01)
3
18
 
4
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/solana",
3
- "version": "1.1.0-alpha.21",
3
+ "version": "1.1.0-alpha.23",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/dynamic-labs/DynamicAuth.git",
@@ -30,12 +30,12 @@
30
30
  "@dynamic-labs/sdk-api": "0.0.356",
31
31
  "bs58": "^5.0.0",
32
32
  "tweetnacl": "^1.0.3",
33
- "@dynamic-labs/rpc-providers": "1.1.0-alpha.21",
34
- "@dynamic-labs/turnkey": "1.1.0-alpha.21",
35
- "@dynamic-labs/types": "1.1.0-alpha.21",
36
- "@dynamic-labs/utils": "1.1.0-alpha.21",
37
- "@dynamic-labs/wallet-book": "1.1.0-alpha.21",
38
- "@dynamic-labs/wallet-connector-core": "1.1.0-alpha.21",
33
+ "@dynamic-labs/rpc-providers": "1.1.0-alpha.23",
34
+ "@dynamic-labs/turnkey": "1.1.0-alpha.23",
35
+ "@dynamic-labs/types": "1.1.0-alpha.23",
36
+ "@dynamic-labs/utils": "1.1.0-alpha.23",
37
+ "@dynamic-labs/wallet-book": "1.1.0-alpha.23",
38
+ "@dynamic-labs/wallet-connector-core": "1.1.0-alpha.23",
39
39
  "eventemitter3": "5.0.1"
40
40
  },
41
41
  "peerDependencies": {}
@@ -7,10 +7,12 @@ var utils = require('@dynamic-labs/utils');
7
7
  var walletBook = require('@dynamic-labs/wallet-book');
8
8
  require('@dynamic-labs/turnkey');
9
9
  require('@dynamic-labs/sdk-api');
10
- var InjectedWalletBase = require('./injected/InjectedWalletBase.cjs');
10
+ require('./solWalletConnector.cjs');
11
+ require('tweetnacl');
12
+ require('bs58');
11
13
  require('@solana/web3.js');
14
+ var InjectedWalletBase = require('./injected/InjectedWalletBase.cjs');
12
15
  require('@dynamic-labs/wallet-connector-core');
13
- require('./solWalletConnector.cjs');
14
16
  var isSignedMessage = require('./utils/isSignedMessage.cjs');
15
17
 
16
18
  class CoinbaseSolana extends InjectedWalletBase.InjectedWalletBase {
@@ -3,10 +3,12 @@ import { bufferToBase64 } from '@dynamic-labs/utils';
3
3
  import { findWalletBookWallet } from '@dynamic-labs/wallet-book';
4
4
  import '@dynamic-labs/turnkey';
5
5
  import '@dynamic-labs/sdk-api';
6
- import { InjectedWalletBase } from './injected/InjectedWalletBase.js';
6
+ import './solWalletConnector.js';
7
+ import 'tweetnacl';
8
+ import 'bs58';
7
9
  import '@solana/web3.js';
10
+ import { InjectedWalletBase } from './injected/InjectedWalletBase.js';
8
11
  import '@dynamic-labs/wallet-connector-core';
9
- import './solWalletConnector.js';
10
12
  import { isSignedMessage } from './utils/isSignedMessage.js';
11
13
 
12
14
  class CoinbaseSolana extends InjectedWalletBase {
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _tslib = require('../_virtual/_tslib.cjs');
6
+ var walletBook = require('@dynamic-labs/wallet-book');
7
+ var utils = require('@dynamic-labs/utils');
8
+ var solWalletConnector = require('./solWalletConnector.cjs');
9
+ var PhantomRedirect = require('./phantomRedirect/PhantomRedirect.cjs');
10
+ var PhantomInjected = require('./injected/PhantomInjected.cjs');
11
+
12
+ class Phantom extends solWalletConnector.SolWalletConnector {
13
+ constructor(opts) {
14
+ super(opts);
15
+ this.name = 'Phantom';
16
+ this.wallet = walletBook.findWalletBookWallet(this.walletBook, this.key);
17
+ }
18
+ connect() {
19
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
20
+ yield this.getMobileOrInstalledWallet().connect();
21
+ });
22
+ }
23
+ getSigner() {
24
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
25
+ return this.getMobileOrInstalledWallet().getSigner();
26
+ });
27
+ }
28
+ getMobileOrInstalledWallet() {
29
+ if (!utils.isMobile()) {
30
+ return new PhantomInjected.PhantomInjected(this.constructorProps);
31
+ }
32
+ if (this.constructorProps.mobileExperience === 'redirect') {
33
+ return new PhantomRedirect.PhantomRedirect(this.constructorProps);
34
+ }
35
+ else {
36
+ return new PhantomInjected.PhantomInjected(this.constructorProps);
37
+ }
38
+ }
39
+ }
40
+
41
+ exports.Phantom = Phantom;
@@ -0,0 +1,12 @@
1
+ import { WalletSchema } from '@dynamic-labs/wallet-book';
2
+ import { WalletConnectorCore } from '@dynamic-labs/wallet-connector-core';
3
+ import { ISolana } from '..';
4
+ import { SolWalletConnector, SolWalletConnectorOpts } from './solWalletConnector';
5
+ export declare class Phantom extends SolWalletConnector {
6
+ name: string;
7
+ wallet: WalletSchema | undefined;
8
+ constructor(opts: SolWalletConnectorOpts);
9
+ connect(): Promise<void>;
10
+ getSigner(): Promise<ISolana | undefined>;
11
+ getMobileOrInstalledWallet(): WalletConnectorCore.WalletConnector;
12
+ }
package/src/Phantom.js ADDED
@@ -0,0 +1,37 @@
1
+ import { __awaiter } from '../_virtual/_tslib.js';
2
+ import { findWalletBookWallet } from '@dynamic-labs/wallet-book';
3
+ import { isMobile } from '@dynamic-labs/utils';
4
+ import { SolWalletConnector } from './solWalletConnector.js';
5
+ import { PhantomRedirect } from './phantomRedirect/PhantomRedirect.js';
6
+ import { PhantomInjected } from './injected/PhantomInjected.js';
7
+
8
+ class Phantom extends SolWalletConnector {
9
+ constructor(opts) {
10
+ super(opts);
11
+ this.name = 'Phantom';
12
+ this.wallet = findWalletBookWallet(this.walletBook, this.key);
13
+ }
14
+ connect() {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ yield this.getMobileOrInstalledWallet().connect();
17
+ });
18
+ }
19
+ getSigner() {
20
+ return __awaiter(this, void 0, void 0, function* () {
21
+ return this.getMobileOrInstalledWallet().getSigner();
22
+ });
23
+ }
24
+ getMobileOrInstalledWallet() {
25
+ if (!isMobile()) {
26
+ return new PhantomInjected(this.constructorProps);
27
+ }
28
+ if (this.constructorProps.mobileExperience === 'redirect') {
29
+ return new PhantomRedirect(this.constructorProps);
30
+ }
31
+ else {
32
+ return new PhantomInjected(this.constructorProps);
33
+ }
34
+ }
35
+ }
36
+
37
+ export { Phantom };
package/src/index.cjs CHANGED
@@ -4,6 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var turnkey = require('@dynamic-labs/turnkey');
6
6
  var sdkApi = require('@dynamic-labs/sdk-api');
7
+ var Phantom = require('./Phantom.cjs');
7
8
  var fetchInjectedWalletConnectors = require('./injected/fetchInjectedWalletConnectors.cjs');
8
9
  var isSignedMessage = require('./utils/isSignedMessage.cjs');
9
10
  var isBackpackSolanaSigner = require('./utils/isBackpackSolanaSigner.cjs');
@@ -13,6 +14,7 @@ const SolanaWalletConnectors = (props) => [
13
14
  ...fetchInjectedWalletConnectors.injectedWalletOverrides,
14
15
  ...fetchInjectedWalletConnectors.fetchInjectedWalletConnectors(props),
15
16
  ...turnkey.TurnkeyWalletConnectors(props, sdkApi.ChainEnum.Sol),
17
+ Phantom.Phantom,
16
18
  ];
17
19
 
18
20
  exports.isSignedMessage = isSignedMessage.isSignedMessage;
package/src/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export declare const SolanaWalletConnectors: (props: any) => import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor[];
1
+ import { Phantom } from './Phantom';
2
+ export declare const SolanaWalletConnectors: (props: any) => (import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor | typeof Phantom)[];
2
3
  export { isSignedMessage } from './utils/isSignedMessage';
3
4
  export { isBackpackSolanaSigner } from './utils/isBackpackSolanaSigner';
4
5
  export type { ISolana, IBackpackSolanaSigner, ICoinbaseSolanaSigner, SignedMessage, ISolanaSigner, } from './types';
package/src/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { TurnkeyWalletConnectors } from '@dynamic-labs/turnkey';
2
2
  import { ChainEnum } from '@dynamic-labs/sdk-api';
3
+ import { Phantom } from './Phantom.js';
3
4
  import { injectedWalletOverrides, fetchInjectedWalletConnectors } from './injected/fetchInjectedWalletConnectors.js';
4
5
  export { isSignedMessage } from './utils/isSignedMessage.js';
5
6
  export { isBackpackSolanaSigner } from './utils/isBackpackSolanaSigner.js';
@@ -9,6 +10,7 @@ const SolanaWalletConnectors = (props) => [
9
10
  ...injectedWalletOverrides,
10
11
  ...fetchInjectedWalletConnectors(props),
11
12
  ...TurnkeyWalletConnectors(props, ChainEnum.Sol),
13
+ Phantom,
12
14
  ];
13
15
 
14
16
  export { SolanaWalletConnectors };
@@ -7,7 +7,7 @@ var utils = require('@dynamic-labs/utils');
7
7
  var walletBook = require('@dynamic-labs/wallet-book');
8
8
  var InjectedWalletBase = require('./InjectedWalletBase.cjs');
9
9
 
10
- class Phantom extends InjectedWalletBase.InjectedWalletBase {
10
+ class PhantomInjected extends InjectedWalletBase.InjectedWalletBase {
11
11
  constructor(opts) {
12
12
  super(opts);
13
13
  this.name = 'Phantom';
@@ -32,4 +32,4 @@ class Phantom extends InjectedWalletBase.InjectedWalletBase {
32
32
  }
33
33
  }
34
34
 
35
- exports.Phantom = Phantom;
35
+ exports.PhantomInjected = PhantomInjected;
@@ -1,6 +1,6 @@
1
1
  import { SolWalletConnectorOpts } from '../solWalletConnector';
2
2
  import { InjectedWalletBase } from './InjectedWalletBase';
3
- export declare class Phantom extends InjectedWalletBase {
3
+ export declare class PhantomInjected extends InjectedWalletBase {
4
4
  name: string;
5
5
  constructor(opts: SolWalletConnectorOpts);
6
6
  fetchPublicAddress(): Promise<string | undefined>;
@@ -3,7 +3,7 @@ import { isMobile, handleMobileWalletRedirect } from '@dynamic-labs/utils';
3
3
  import { findWalletBookWallet } from '@dynamic-labs/wallet-book';
4
4
  import { InjectedWalletBase } from './InjectedWalletBase.js';
5
5
 
6
- class Phantom extends InjectedWalletBase {
6
+ class PhantomInjected extends InjectedWalletBase {
7
7
  constructor(opts) {
8
8
  super(opts);
9
9
  this.name = 'Phantom';
@@ -28,4 +28,4 @@ class Phantom extends InjectedWalletBase {
28
28
  }
29
29
  }
30
30
 
31
- export { Phantom };
31
+ export { PhantomInjected };
@@ -5,13 +5,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var CoinbaseSolana = require('../CoinbaseSolana.cjs');
6
6
  var Slope = require('../Slope.cjs');
7
7
  var InjectedWalletBase = require('./InjectedWalletBase.cjs');
8
- var Phantom = require('./Phantom.cjs');
9
8
  var BackpackSol = require('./BackpackSol.cjs');
10
9
 
11
10
  const injectedWalletOverrides = [
12
11
  CoinbaseSolana.CoinbaseSolana,
13
12
  Slope.Slope,
14
- Phantom.Phantom,
15
13
  BackpackSol.BackpackSol,
16
14
  ];
17
15
  const filteredInjectedWalletKeysOverrides = [
@@ -1,13 +1,11 @@
1
1
  import { CoinbaseSolana } from '../CoinbaseSolana.js';
2
2
  import { Slope } from '../Slope.js';
3
3
  import { InjectedWalletBase } from './InjectedWalletBase.js';
4
- import { Phantom } from './Phantom.js';
5
4
  import { BackpackSol } from './BackpackSol.js';
6
5
 
7
6
  const injectedWalletOverrides = [
8
7
  CoinbaseSolana,
9
8
  Slope,
10
- Phantom,
11
9
  BackpackSol,
12
10
  ];
13
11
  const filteredInjectedWalletKeysOverrides = [
@@ -0,0 +1,160 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _tslib = require('../../_virtual/_tslib.cjs');
6
+ var nacl = require('tweetnacl');
7
+ var bs58 = require('bs58');
8
+ var web3_js = require('@solana/web3.js');
9
+ var solWalletConnector = require('../solWalletConnector.cjs');
10
+ var utils = require('./utils.cjs');
11
+ var storage = require('./storage.cjs');
12
+
13
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
+
15
+ var nacl__default = /*#__PURE__*/_interopDefaultLegacy(nacl);
16
+ var bs58__default = /*#__PURE__*/_interopDefaultLegacy(bs58);
17
+
18
+ class PhantomRedirect extends solWalletConnector.SolWalletConnector {
19
+ constructor(props) {
20
+ super(Object.assign({}, props));
21
+ this.name = 'Phantom';
22
+ }
23
+ fetchPublicAddress() {
24
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
25
+ const address = storage.storage.address.get();
26
+ if (address) {
27
+ return address;
28
+ }
29
+ yield this.connect();
30
+ return undefined;
31
+ });
32
+ }
33
+ connect() {
34
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
35
+ // Generate a new key pair
36
+ const keyPair = nacl__default["default"].box.keyPair();
37
+ storage.storage.encryptionPublicKey.set(keyPair.publicKey);
38
+ storage.storage.encryptionSecretKey.set(keyPair.secretKey);
39
+ const isLocalHost = window.location.href.includes('localhost') ||
40
+ window.location.href.includes('0.0.0.0') ||
41
+ window.location.href.includes('127.0.0.1');
42
+ const params = new URLSearchParams({
43
+ app_url: isLocalHost ? 'https://demo.dynamic.xyz' : window.location.href,
44
+ cluster: 'mainnet-beta',
45
+ dapp_encryption_public_key: bs58__default["default"].encode(keyPair.publicKey),
46
+ redirect_link: window.location.href,
47
+ });
48
+ const url = utils.buildUrl('connect', params);
49
+ window.location.href = url;
50
+ });
51
+ }
52
+ getSession() {
53
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
54
+ const params = new URLSearchParams(window.location.search);
55
+ const { data, nonce, phantom_encryption_public_key: phantomEncryptionPublicKey, encryptionSecretKey, } = this.getInputsOrThrow('getSession', ['data', 'nonce', 'phantom_encryption_public_key'], ['encryptionSecretKey']);
56
+ const sharedSecret = nacl__default["default"].box.before(bs58__default["default"].decode(phantomEncryptionPublicKey), encryptionSecretKey);
57
+ storage.storage.sharedSecret.set(sharedSecret);
58
+ const connectData = utils.decryptPayload(data, nonce, sharedSecret);
59
+ storage.storage.session.set(connectData.session);
60
+ storage.storage.address.set(new web3_js.PublicKey(connectData.public_key));
61
+ params.delete('phantom_encryption_public_key');
62
+ params.delete('data');
63
+ params.delete('nonce');
64
+ history.replaceState(null, '', `${window.location.origin}${window.location.pathname}?${params.toString()}`);
65
+ return connectData.public_key;
66
+ });
67
+ }
68
+ signMessage(messageToSign) {
69
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
70
+ const { session, sharedSecret, encryptionPublicKey } = this.getInputsOrThrow('signMessage', [], ['session', 'sharedSecret', 'encryptionPublicKey']);
71
+ storage.storage.message.set(messageToSign);
72
+ const payload = {
73
+ message: bs58__default["default"].encode(Buffer.from(messageToSign)),
74
+ session,
75
+ };
76
+ const [nonce, encryptedPayload] = utils.encryptPayload(payload, sharedSecret);
77
+ const params = new URLSearchParams({
78
+ dapp_encryption_public_key: bs58__default["default"].encode(encryptionPublicKey),
79
+ nonce: bs58__default["default"].encode(nonce),
80
+ payload: bs58__default["default"].encode(encryptedPayload),
81
+ redirect_link: window.location.href,
82
+ });
83
+ const url = utils.buildUrl('signMessage', params);
84
+ window.location.href = url;
85
+ // throwing this to prevent local storage from being cleared.
86
+ // when verifying signature, the SDK calls endSession when no
87
+ // signature is returned. in the case of phantom mobile, a signature
88
+ // is not returned from signMessage, so an error will always be thrown.
89
+ // this is a workaround to prevent the SDK from clearing local storage
90
+ // ideally we would figure out how to:
91
+ // 1. kick off the sign message on one tab
92
+ // 2. resume the process on that tab after the user signs in phantom
93
+ throw new Error('ignore');
94
+ });
95
+ }
96
+ extractSignature() {
97
+ const params = new URLSearchParams(window.location.search);
98
+ const { data, nonce, sharedSecret, message } = this.getInputsOrThrow('extractSignature', ['data', 'nonce'], ['sharedSecret', 'message']);
99
+ const signMessageData = utils.decryptPayload(data, nonce, sharedSecret);
100
+ params.delete('data');
101
+ params.delete('nonce');
102
+ history.replaceState(null, '', `${window.location.origin}${window.location.pathname}?${params.toString()}`);
103
+ return {
104
+ message,
105
+ signature: signMessageData.signature,
106
+ };
107
+ }
108
+ getSigner() {
109
+ return Promise.resolve(undefined);
110
+ }
111
+ getConnectedAccounts() {
112
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
113
+ const address = storage.storage.address.get();
114
+ return address ? [address] : [];
115
+ });
116
+ }
117
+ endSession() {
118
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
119
+ // for establishing the shared secret. NOT the wallet address
120
+ storage.storage.address.remove();
121
+ storage.storage.encryptionPublicKey.remove();
122
+ storage.storage.encryptionSecretKey.remove();
123
+ storage.storage.message.remove();
124
+ storage.storage.session.remove();
125
+ storage.storage.sharedSecret.remove();
126
+ });
127
+ }
128
+ /**
129
+ * Helper method to get inputs from query params and localstorage
130
+ *
131
+ * The second argument is used to read values from the query string
132
+ * e.g. ['data', 'nonce'] -> params.get('data') and params.get('nonce')
133
+ *
134
+ * The third argument is used to read values from local storage
135
+ * e.g. ['address', 'message'] -> storage.address.get() and storage.message.get()
136
+ *
137
+ * Throws an error if any of the inputs are unable to be found in their respective locations
138
+ */
139
+ getInputsOrThrow(methodName, queryParams, storageParams) {
140
+ const inputs = {};
141
+ const queryString = new URLSearchParams(window.location.search);
142
+ queryParams.forEach((param) => {
143
+ const value = queryString.get(param);
144
+ if (!value) {
145
+ throw new Error(`[PhantomRedirect] ${methodName} called, but required input '${param}' not found in query params`);
146
+ }
147
+ inputs[param] = value;
148
+ });
149
+ storageParams.forEach((storageParam) => {
150
+ const value = storage.storage[storageParam].get();
151
+ if (!value) {
152
+ throw new Error(`[PhantomRedirect] ${methodName} called, but required input '${storageParam}' not found in local storage`);
153
+ }
154
+ inputs[storageParam] = value;
155
+ });
156
+ return inputs;
157
+ }
158
+ }
159
+
160
+ exports.PhantomRedirect = PhantomRedirect;
@@ -0,0 +1,151 @@
1
+ import { __awaiter } from '../../_virtual/_tslib.js';
2
+ import nacl from 'tweetnacl';
3
+ import bs58 from 'bs58';
4
+ import { PublicKey } from '@solana/web3.js';
5
+ import { SolWalletConnector } from '../solWalletConnector.js';
6
+ import { buildUrl, decryptPayload, encryptPayload } from './utils.js';
7
+ import { storage } from './storage.js';
8
+
9
+ class PhantomRedirect extends SolWalletConnector {
10
+ constructor(props) {
11
+ super(Object.assign({}, props));
12
+ this.name = 'Phantom';
13
+ }
14
+ fetchPublicAddress() {
15
+ return __awaiter(this, void 0, void 0, function* () {
16
+ const address = storage.address.get();
17
+ if (address) {
18
+ return address;
19
+ }
20
+ yield this.connect();
21
+ return undefined;
22
+ });
23
+ }
24
+ connect() {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ // Generate a new key pair
27
+ const keyPair = nacl.box.keyPair();
28
+ storage.encryptionPublicKey.set(keyPair.publicKey);
29
+ storage.encryptionSecretKey.set(keyPair.secretKey);
30
+ const isLocalHost = window.location.href.includes('localhost') ||
31
+ window.location.href.includes('0.0.0.0') ||
32
+ window.location.href.includes('127.0.0.1');
33
+ const params = new URLSearchParams({
34
+ app_url: isLocalHost ? 'https://demo.dynamic.xyz' : window.location.href,
35
+ cluster: 'mainnet-beta',
36
+ dapp_encryption_public_key: bs58.encode(keyPair.publicKey),
37
+ redirect_link: window.location.href,
38
+ });
39
+ const url = buildUrl('connect', params);
40
+ window.location.href = url;
41
+ });
42
+ }
43
+ getSession() {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ const params = new URLSearchParams(window.location.search);
46
+ const { data, nonce, phantom_encryption_public_key: phantomEncryptionPublicKey, encryptionSecretKey, } = this.getInputsOrThrow('getSession', ['data', 'nonce', 'phantom_encryption_public_key'], ['encryptionSecretKey']);
47
+ const sharedSecret = nacl.box.before(bs58.decode(phantomEncryptionPublicKey), encryptionSecretKey);
48
+ storage.sharedSecret.set(sharedSecret);
49
+ const connectData = decryptPayload(data, nonce, sharedSecret);
50
+ storage.session.set(connectData.session);
51
+ storage.address.set(new PublicKey(connectData.public_key));
52
+ params.delete('phantom_encryption_public_key');
53
+ params.delete('data');
54
+ params.delete('nonce');
55
+ history.replaceState(null, '', `${window.location.origin}${window.location.pathname}?${params.toString()}`);
56
+ return connectData.public_key;
57
+ });
58
+ }
59
+ signMessage(messageToSign) {
60
+ return __awaiter(this, void 0, void 0, function* () {
61
+ const { session, sharedSecret, encryptionPublicKey } = this.getInputsOrThrow('signMessage', [], ['session', 'sharedSecret', 'encryptionPublicKey']);
62
+ storage.message.set(messageToSign);
63
+ const payload = {
64
+ message: bs58.encode(Buffer.from(messageToSign)),
65
+ session,
66
+ };
67
+ const [nonce, encryptedPayload] = encryptPayload(payload, sharedSecret);
68
+ const params = new URLSearchParams({
69
+ dapp_encryption_public_key: bs58.encode(encryptionPublicKey),
70
+ nonce: bs58.encode(nonce),
71
+ payload: bs58.encode(encryptedPayload),
72
+ redirect_link: window.location.href,
73
+ });
74
+ const url = buildUrl('signMessage', params);
75
+ window.location.href = url;
76
+ // throwing this to prevent local storage from being cleared.
77
+ // when verifying signature, the SDK calls endSession when no
78
+ // signature is returned. in the case of phantom mobile, a signature
79
+ // is not returned from signMessage, so an error will always be thrown.
80
+ // this is a workaround to prevent the SDK from clearing local storage
81
+ // ideally we would figure out how to:
82
+ // 1. kick off the sign message on one tab
83
+ // 2. resume the process on that tab after the user signs in phantom
84
+ throw new Error('ignore');
85
+ });
86
+ }
87
+ extractSignature() {
88
+ const params = new URLSearchParams(window.location.search);
89
+ const { data, nonce, sharedSecret, message } = this.getInputsOrThrow('extractSignature', ['data', 'nonce'], ['sharedSecret', 'message']);
90
+ const signMessageData = decryptPayload(data, nonce, sharedSecret);
91
+ params.delete('data');
92
+ params.delete('nonce');
93
+ history.replaceState(null, '', `${window.location.origin}${window.location.pathname}?${params.toString()}`);
94
+ return {
95
+ message,
96
+ signature: signMessageData.signature,
97
+ };
98
+ }
99
+ getSigner() {
100
+ return Promise.resolve(undefined);
101
+ }
102
+ getConnectedAccounts() {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ const address = storage.address.get();
105
+ return address ? [address] : [];
106
+ });
107
+ }
108
+ endSession() {
109
+ return __awaiter(this, void 0, void 0, function* () {
110
+ // for establishing the shared secret. NOT the wallet address
111
+ storage.address.remove();
112
+ storage.encryptionPublicKey.remove();
113
+ storage.encryptionSecretKey.remove();
114
+ storage.message.remove();
115
+ storage.session.remove();
116
+ storage.sharedSecret.remove();
117
+ });
118
+ }
119
+ /**
120
+ * Helper method to get inputs from query params and localstorage
121
+ *
122
+ * The second argument is used to read values from the query string
123
+ * e.g. ['data', 'nonce'] -> params.get('data') and params.get('nonce')
124
+ *
125
+ * The third argument is used to read values from local storage
126
+ * e.g. ['address', 'message'] -> storage.address.get() and storage.message.get()
127
+ *
128
+ * Throws an error if any of the inputs are unable to be found in their respective locations
129
+ */
130
+ getInputsOrThrow(methodName, queryParams, storageParams) {
131
+ const inputs = {};
132
+ const queryString = new URLSearchParams(window.location.search);
133
+ queryParams.forEach((param) => {
134
+ const value = queryString.get(param);
135
+ if (!value) {
136
+ throw new Error(`[PhantomRedirect] ${methodName} called, but required input '${param}' not found in query params`);
137
+ }
138
+ inputs[param] = value;
139
+ });
140
+ storageParams.forEach((storageParam) => {
141
+ const value = storage[storageParam].get();
142
+ if (!value) {
143
+ throw new Error(`[PhantomRedirect] ${methodName} called, but required input '${storageParam}' not found in local storage`);
144
+ }
145
+ inputs[storageParam] = value;
146
+ });
147
+ return inputs;
148
+ }
149
+ }
150
+
151
+ export { PhantomRedirect };
@@ -0,0 +1,80 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const storage = {
6
+ address: {
7
+ get: () => { var _a; return (_a = localStorage.getItem('dynamic_phantom_wallet_address')) !== null && _a !== void 0 ? _a : undefined; },
8
+ remove: () => {
9
+ localStorage.removeItem('dynamic_phantom_wallet_address');
10
+ },
11
+ set: (address) => {
12
+ localStorage.setItem('dynamic_phantom_wallet_address', address.toString());
13
+ },
14
+ },
15
+ encryptionPublicKey: {
16
+ get: () => {
17
+ const rawPublicKey = localStorage.getItem('dynamic_phantom_public_key');
18
+ if (!rawPublicKey) {
19
+ return undefined;
20
+ }
21
+ return new Uint8Array(JSON.parse(rawPublicKey));
22
+ },
23
+ remove: () => {
24
+ localStorage.removeItem('dynamic_phantom_public_key');
25
+ },
26
+ set: (publicKey) => {
27
+ localStorage.setItem('dynamic_phantom_public_key', JSON.stringify([...publicKey]));
28
+ },
29
+ },
30
+ encryptionSecretKey: {
31
+ get: () => {
32
+ const rawSecretKey = localStorage.getItem('dynamic_phantom_secret_key');
33
+ if (!rawSecretKey) {
34
+ return undefined;
35
+ }
36
+ return new Uint8Array(JSON.parse(rawSecretKey));
37
+ },
38
+ remove: () => {
39
+ localStorage.removeItem('dynamic_phantom_secret_key');
40
+ },
41
+ set: (secretKey) => {
42
+ localStorage.setItem('dynamic_phantom_secret_key', JSON.stringify([...secretKey]));
43
+ },
44
+ },
45
+ message: {
46
+ get: () => { var _a; return (_a = localStorage.getItem('dynamic_phantom_message_to_sign')) !== null && _a !== void 0 ? _a : undefined; },
47
+ remove: () => {
48
+ localStorage.removeItem('dynamic_phantom_message_to_sign');
49
+ },
50
+ set: (message) => {
51
+ localStorage.setItem('dynamic_phantom_message_to_sign', message);
52
+ },
53
+ },
54
+ session: {
55
+ get: () => { var _a; return (_a = localStorage.getItem('dynamic_phantom_session')) !== null && _a !== void 0 ? _a : undefined; },
56
+ remove: () => {
57
+ localStorage.removeItem('dynamic_phantom_session');
58
+ },
59
+ set: (session) => {
60
+ localStorage.setItem('dynamic_phantom_session', session);
61
+ },
62
+ },
63
+ sharedSecret: {
64
+ get: () => {
65
+ const rawSharedSecret = localStorage.getItem('dynamic_phantom_shared_secret');
66
+ if (!rawSharedSecret) {
67
+ return undefined;
68
+ }
69
+ return new Uint8Array(JSON.parse(rawSharedSecret));
70
+ },
71
+ remove: () => {
72
+ localStorage.removeItem('dynamic_phantom_shared_secret');
73
+ },
74
+ set: (sharedSecret) => {
75
+ localStorage.setItem('dynamic_phantom_shared_secret', JSON.stringify([...sharedSecret]));
76
+ },
77
+ },
78
+ };
79
+
80
+ exports.storage = storage;
@@ -0,0 +1,76 @@
1
+ const storage = {
2
+ address: {
3
+ get: () => { var _a; return (_a = localStorage.getItem('dynamic_phantom_wallet_address')) !== null && _a !== void 0 ? _a : undefined; },
4
+ remove: () => {
5
+ localStorage.removeItem('dynamic_phantom_wallet_address');
6
+ },
7
+ set: (address) => {
8
+ localStorage.setItem('dynamic_phantom_wallet_address', address.toString());
9
+ },
10
+ },
11
+ encryptionPublicKey: {
12
+ get: () => {
13
+ const rawPublicKey = localStorage.getItem('dynamic_phantom_public_key');
14
+ if (!rawPublicKey) {
15
+ return undefined;
16
+ }
17
+ return new Uint8Array(JSON.parse(rawPublicKey));
18
+ },
19
+ remove: () => {
20
+ localStorage.removeItem('dynamic_phantom_public_key');
21
+ },
22
+ set: (publicKey) => {
23
+ localStorage.setItem('dynamic_phantom_public_key', JSON.stringify([...publicKey]));
24
+ },
25
+ },
26
+ encryptionSecretKey: {
27
+ get: () => {
28
+ const rawSecretKey = localStorage.getItem('dynamic_phantom_secret_key');
29
+ if (!rawSecretKey) {
30
+ return undefined;
31
+ }
32
+ return new Uint8Array(JSON.parse(rawSecretKey));
33
+ },
34
+ remove: () => {
35
+ localStorage.removeItem('dynamic_phantom_secret_key');
36
+ },
37
+ set: (secretKey) => {
38
+ localStorage.setItem('dynamic_phantom_secret_key', JSON.stringify([...secretKey]));
39
+ },
40
+ },
41
+ message: {
42
+ get: () => { var _a; return (_a = localStorage.getItem('dynamic_phantom_message_to_sign')) !== null && _a !== void 0 ? _a : undefined; },
43
+ remove: () => {
44
+ localStorage.removeItem('dynamic_phantom_message_to_sign');
45
+ },
46
+ set: (message) => {
47
+ localStorage.setItem('dynamic_phantom_message_to_sign', message);
48
+ },
49
+ },
50
+ session: {
51
+ get: () => { var _a; return (_a = localStorage.getItem('dynamic_phantom_session')) !== null && _a !== void 0 ? _a : undefined; },
52
+ remove: () => {
53
+ localStorage.removeItem('dynamic_phantom_session');
54
+ },
55
+ set: (session) => {
56
+ localStorage.setItem('dynamic_phantom_session', session);
57
+ },
58
+ },
59
+ sharedSecret: {
60
+ get: () => {
61
+ const rawSharedSecret = localStorage.getItem('dynamic_phantom_shared_secret');
62
+ if (!rawSharedSecret) {
63
+ return undefined;
64
+ }
65
+ return new Uint8Array(JSON.parse(rawSharedSecret));
66
+ },
67
+ remove: () => {
68
+ localStorage.removeItem('dynamic_phantom_shared_secret');
69
+ },
70
+ set: (sharedSecret) => {
71
+ localStorage.setItem('dynamic_phantom_shared_secret', JSON.stringify([...sharedSecret]));
72
+ },
73
+ },
74
+ };
75
+
76
+ export { storage };
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var nacl = require('tweetnacl');
6
+ var bs58 = require('bs58');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ var nacl__default = /*#__PURE__*/_interopDefaultLegacy(nacl);
11
+ var bs58__default = /*#__PURE__*/_interopDefaultLegacy(bs58);
12
+
13
+ const buildUrl = (path, params) => `https://phantom.app/ul/v1/${path}?${params.toString()}`;
14
+ const decryptPayload = (data, nonce, sharedSecret) => {
15
+ const decryptedData = nacl__default["default"].box.open.after(bs58__default["default"].decode(data), bs58__default["default"].decode(nonce), sharedSecret);
16
+ if (!decryptedData) {
17
+ throw new Error('Unable to decrypt data');
18
+ }
19
+ return JSON.parse(Buffer.from(decryptedData).toString('utf8'));
20
+ };
21
+ const encryptPayload = (payload, sharedSecret) => {
22
+ const nonce = nacl__default["default"].randomBytes(24);
23
+ const encryptedPayload = nacl__default["default"].box.after(Buffer.from(JSON.stringify(payload)), nonce, sharedSecret);
24
+ return [nonce, encryptedPayload];
25
+ };
26
+
27
+ exports.buildUrl = buildUrl;
28
+ exports.decryptPayload = decryptPayload;
29
+ exports.encryptPayload = encryptPayload;
@@ -0,0 +1,18 @@
1
+ import nacl from 'tweetnacl';
2
+ import bs58 from 'bs58';
3
+
4
+ const buildUrl = (path, params) => `https://phantom.app/ul/v1/${path}?${params.toString()}`;
5
+ const decryptPayload = (data, nonce, sharedSecret) => {
6
+ const decryptedData = nacl.box.open.after(bs58.decode(data), bs58.decode(nonce), sharedSecret);
7
+ if (!decryptedData) {
8
+ throw new Error('Unable to decrypt data');
9
+ }
10
+ return JSON.parse(Buffer.from(decryptedData).toString('utf8'));
11
+ };
12
+ const encryptPayload = (payload, sharedSecret) => {
13
+ const nonce = nacl.randomBytes(24);
14
+ const encryptedPayload = nacl.box.after(Buffer.from(JSON.stringify(payload)), nonce, sharedSecret);
15
+ return [nonce, encryptedPayload];
16
+ };
17
+
18
+ export { buildUrl, decryptPayload, encryptPayload };