@dynamic-labs/stellar 4.67.3-device-registration.0 → 4.69.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/CHANGELOG.md CHANGED
@@ -1,20 +1,25 @@
1
1
 
2
- ### [4.67.3-device-registration.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.67.2...v4.67.3-device-registration.0) (2026-03-19)
2
+ ## [4.69.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.68.0...v4.69.0) (2026-03-19)
3
3
 
4
4
 
5
5
  ### Features
6
6
 
7
- * add device registration icons ([#10637](https://github.com/dynamic-labs/dynamic-auth/issues/10637)) ([01bfe15](https://github.com/dynamic-labs/dynamic-auth/commit/01bfe155722111f321d289629bed95e8b9e4344d))
8
- * add DeviceRegistrationView ([#10638](https://github.com/dynamic-labs/dynamic-auth/issues/10638)) ([11ccbbc](https://github.com/dynamic-labs/dynamic-auth/commit/11ccbbcc5cfaeab9fbeb01c040225a731137b465))
9
- * add Prompt MFA and Prompt Reauthenticate to Step Up Auth methods ([#10645](https://github.com/dynamic-labs/dynamic-auth/issues/10645)) ([c97d8ee](https://github.com/dynamic-labs/dynamic-auth/commit/c97d8ee27f48d376259a921b01d151b4cf7fa27b))
10
- * add step-up auth for email and SMS credential updates ([#10676](https://github.com/dynamic-labs/dynamic-auth/issues/10676)) ([4c7f0a5](https://github.com/dynamic-labs/dynamic-auth/commit/4c7f0a5330e557aea4db85359f7ac10d3c7545a5))
11
- * add step-up auth for wallet link and unlink ([#10678](https://github.com/dynamic-labs/dynamic-auth/issues/10678)) ([8a015ca](https://github.com/dynamic-labs/dynamic-auth/commit/8a015ca0fd0bda71559c21b811b7e6acb43a7909))
12
- * add TrustedDevicesSection and ManageTrustedDevicesView ([#10639](https://github.com/dynamic-labs/dynamic-auth/issues/10639)) ([17df870](https://github.com/dynamic-labs/dynamic-auth/commit/17df870caa34a8428d65510e5b3c9e9c7b93cea2))
13
- * add useSyncDeviceRegistrationFlow ([#10640](https://github.com/dynamic-labs/dynamic-auth/issues/10640)) ([8c7752d](https://github.com/dynamic-labs/dynamic-auth/commit/8c7752d7a8afedaa3cc99fad83091586f7b6107e))
14
- * **sdk-react-core:** prompt step-up auth before export private key ([#10647](https://github.com/dynamic-labs/dynamic-auth/issues/10647)) ([a39d886](https://github.com/dynamic-labs/dynamic-auth/commit/a39d88643af83484aae09332adcd05df8c0f923c))
15
- * **step-up:** reauth flow with signInCredentialId and choose-method UI ([#10644](https://github.com/dynamic-labs/dynamic-auth/issues/10644)) ([086a97f](https://github.com/dynamic-labs/dynamic-auth/commit/086a97f27d908780b17f49f8a85ce88c34f61ed8))
7
+ * add MoonPay icon to iconic ([#10666](https://github.com/dynamic-labs/dynamic-auth/issues/10666)) ([19d437b](https://github.com/dynamic-labs/dynamic-auth/commit/19d437b1a55e2b7800d65f375217b735f29d10eb))
8
+ * add step-up auth for OAuth and email credential link and unlink ([#10679](https://github.com/dynamic-labs/dynamic-auth/issues/10679)) ([ba48be8](https://github.com/dynamic-labs/dynamic-auth/commit/ba48be874e44c033563ae107e46a1b90f3c307d6))
9
+ * replace React session chaining with pure SDK implementation ([#10423](https://github.com/dynamic-labs/dynamic-auth/issues/10423)) ([2279421](https://github.com/dynamic-labs/dynamic-auth/commit/227942153828192d316d19295a69d9e7a5baa85c))
16
10
 
17
11
 
12
+ ### Bug Fixes
13
+
14
+ * csp nonce global styles ([#10591](https://github.com/dynamic-labs/dynamic-auth/issues/10591)) ([6ea9c14](https://github.com/dynamic-labs/dynamic-auth/commit/6ea9c141055b3a337d8841dbebec00c7a3cb5d93))
15
+
16
+ ## [4.68.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.67.2...v4.68.0) (2026-03-19)
17
+
18
+
19
+ ### Features
20
+
21
+ * add freighter ledger support on stellar ([#10665](https://github.com/dynamic-labs/dynamic-auth/issues/10665)) ([dedbaa6](https://github.com/dynamic-labs/dynamic-auth/commit/dedbaa6038f282b9e41b9166cad3ad6d5032948d))
22
+
18
23
  ### Bug Fixes
19
24
 
20
25
  * close auth flow on re-login when user already has embedded wallets ([#10641](https://github.com/dynamic-labs/dynamic-auth/issues/10641)) ([1aab930](https://github.com/dynamic-labs/dynamic-auth/commit/1aab9307c904f79bc0534026547fc112c55f6dc9))
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.67.3-device-registration.0";
6
+ var version = "4.69.0";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "4.67.3-device-registration.0";
2
+ var version = "4.69.0";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/stellar",
3
- "version": "4.67.3-device-registration.0",
3
+ "version": "4.69.0",
4
4
  "description": "A React SDK for implementing Stellar wallet web3 authentication and authorization to your website.",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -20,15 +20,15 @@
20
20
  "dependencies": {
21
21
  "@dynamic-labs/sdk-api-core": "0.0.907",
22
22
  "@stellar/stellar-sdk": "14.4.3",
23
- "@dynamic-labs/wallet-connector-core": "4.67.3-device-registration.0",
24
- "@dynamic-labs/assert-package-version": "4.67.3-device-registration.0",
23
+ "@dynamic-labs/wallet-connector-core": "4.69.0",
24
+ "@dynamic-labs/assert-package-version": "4.69.0",
25
25
  "@lobstrco/signer-extension-api": "2.0.0",
26
26
  "@stellar/freighter-api": "6.0.1",
27
- "@dynamic-labs/logger": "4.67.3-device-registration.0",
28
- "@dynamic-labs/types": "4.67.3-device-registration.0",
29
- "@dynamic-labs/utils": "4.67.3-device-registration.0",
30
- "@dynamic-labs/waas": "4.67.3-device-registration.0",
31
- "@dynamic-labs/wallet-book": "4.67.3-device-registration.0",
27
+ "@dynamic-labs/logger": "4.69.0",
28
+ "@dynamic-labs/types": "4.69.0",
29
+ "@dynamic-labs/utils": "4.69.0",
30
+ "@dynamic-labs/waas": "4.69.0",
31
+ "@dynamic-labs/wallet-book": "4.69.0",
32
32
  "eventemitter3": "5.0.1"
33
33
  },
34
34
  "peerDependencies": {}
@@ -9,6 +9,7 @@ var utils = require('@dynamic-labs/utils');
9
9
  class StellarLocalStorageCache {
10
10
  constructor(key) {
11
11
  this.CONNECTED_ACCOUNTS_KEY = `stellar_${key}_connectedAccounts`;
12
+ this.NETWORK_KEY = `stellar_${key}_network`;
12
13
  }
13
14
  getActiveAccount() {
14
15
  return _tslib.__awaiter(this, void 0, void 0, function* () {
@@ -60,6 +61,22 @@ class StellarLocalStorageCache {
60
61
  return utils.removeItemAsync(this.CONNECTED_ACCOUNTS_KEY);
61
62
  });
62
63
  }
64
+ getStoredNetwork() {
65
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
66
+ const stored = yield utils.getItemAsync(this.NETWORK_KEY);
67
+ return stored !== null && stored !== void 0 ? stored : undefined;
68
+ });
69
+ }
70
+ setStoredNetwork(networkId) {
71
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
72
+ return utils.setItemAsync(this.NETWORK_KEY, networkId);
73
+ });
74
+ }
75
+ clearStoredNetwork() {
76
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
77
+ return utils.removeItemAsync(this.NETWORK_KEY);
78
+ });
79
+ }
63
80
  }
64
81
 
65
82
  exports.StellarLocalStorageCache = StellarLocalStorageCache;
@@ -12,18 +12,25 @@ type StellarActiveAccount = {
12
12
  };
13
13
  export declare class StellarLocalStorageCache implements IStellarSessionCache {
14
14
  private readonly CONNECTED_ACCOUNTS_KEY;
15
+ private readonly NETWORK_KEY;
15
16
  constructor(key: string);
16
17
  getActiveAccount(): Promise<StellarActiveAccount | undefined>;
17
18
  getConnectedAccounts(): Promise<StellarConnectedAccounts | undefined>;
18
19
  getConnectedAccount(address: string): Promise<StellarConnectedAccount | undefined>;
19
20
  setConnectedAccount(address: string, account: StellarConnectedAccount): Promise<void>;
20
21
  clearConnectedAcccounts(): Promise<void>;
22
+ getStoredNetwork(): Promise<string | undefined>;
23
+ setStoredNetwork(networkId: string): Promise<void>;
24
+ clearStoredNetwork(): Promise<void>;
21
25
  }
22
26
  export interface IStellarSessionCache {
23
27
  clearConnectedAcccounts(): Promise<void>;
28
+ clearStoredNetwork(): Promise<void>;
24
29
  getActiveAccount(): Promise<StellarActiveAccount | undefined>;
25
30
  getConnectedAccount(address: string): Promise<StellarConnectedAccount | undefined>;
26
31
  getConnectedAccounts(): Promise<StellarConnectedAccounts | undefined>;
32
+ getStoredNetwork(): Promise<string | undefined>;
27
33
  setConnectedAccount(address: string, account: StellarConnectedAccount): Promise<void>;
34
+ setStoredNetwork(networkId: string): Promise<void>;
28
35
  }
29
36
  export {};
@@ -5,6 +5,7 @@ import { getItemAsync, setItemAsync, removeItemAsync } from '@dynamic-labs/utils
5
5
  class StellarLocalStorageCache {
6
6
  constructor(key) {
7
7
  this.CONNECTED_ACCOUNTS_KEY = `stellar_${key}_connectedAccounts`;
8
+ this.NETWORK_KEY = `stellar_${key}_network`;
8
9
  }
9
10
  getActiveAccount() {
10
11
  return __awaiter(this, void 0, void 0, function* () {
@@ -56,6 +57,22 @@ class StellarLocalStorageCache {
56
57
  return removeItemAsync(this.CONNECTED_ACCOUNTS_KEY);
57
58
  });
58
59
  }
60
+ getStoredNetwork() {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ const stored = yield getItemAsync(this.NETWORK_KEY);
63
+ return stored !== null && stored !== void 0 ? stored : undefined;
64
+ });
65
+ }
66
+ setStoredNetwork(networkId) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ return setItemAsync(this.NETWORK_KEY, networkId);
69
+ });
70
+ }
71
+ clearStoredNetwork() {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ return removeItemAsync(this.NETWORK_KEY);
74
+ });
75
+ }
59
76
  }
60
77
 
61
78
  export { StellarLocalStorageCache };
@@ -9,9 +9,8 @@ var logger = require('@dynamic-labs/logger');
9
9
  var utils = require('@dynamic-labs/utils');
10
10
  var walletConnectorCore = require('@dynamic-labs/wallet-connector-core');
11
11
  var StellarWallet = require('../../wallet/StellarWallet.cjs');
12
- var getNetworkFromAddress = require('../../utils/getNetworkFromAddress.cjs');
13
- var StellarUiTransaction = require('../../utils/StellarUiTransaction/StellarUiTransaction.cjs');
14
12
  var StellarLocalStorageCache = require('../../StellarLocalStorageCache.cjs');
13
+ var StellarUiTransaction = require('../../utils/StellarUiTransaction/StellarUiTransaction.cjs');
15
14
 
16
15
  const HORIZON_MAINNET_URL = 'https://horizon.stellar.org';
17
16
  const HORIZON_TESTNET_URL = 'https://horizon-testnet.stellar.org';
@@ -37,12 +36,17 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
37
36
  this.isConnecting = false;
38
37
  /** Flag to track if connection was cancelled by disconnect */
39
38
  this.connectionCancelled = false;
39
+ this.isHardwareWalletEnabled = false;
40
40
  this.name = name;
41
41
  this.logger = new logger.Logger(this.name);
42
42
  this.stellarNetworks = (_a = opts.stellarNetworks) !== null && _a !== void 0 ? _a : [];
43
43
  this.overrideKey = this.key;
44
44
  this.cache = new StellarLocalStorageCache.StellarLocalStorageCache(this.overrideKey);
45
45
  }
46
+ canConnectWithHardwareWallet() {
47
+ var _a;
48
+ return Boolean((_a = this.metadata.supportedHardwareWallets) === null || _a === void 0 ? void 0 : _a.includes('ledger'));
49
+ }
46
50
  getEnabledNetworks() {
47
51
  return this.stellarNetworks;
48
52
  }
@@ -61,50 +65,35 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
61
65
  const network = this.stellarNetworks.find((n) => { var _a, _b; return ((_a = n.chainId) === null || _a === void 0 ? void 0 : _a.toString()) === idStr || ((_b = n.networkId) === null || _b === void 0 ? void 0 : _b.toString()) === idStr; });
62
66
  if (network) {
63
67
  this.selectedNetwork = network;
68
+ yield this.cache.setStoredNetwork(String(network.chainId));
64
69
  this.emit('chainChange', { chain: String(network.chainId) });
65
70
  }
66
71
  });
67
72
  }
68
73
  getNetwork() {
69
74
  return _tslib.__awaiter(this, void 0, void 0, function* () {
70
- var _a;
71
75
  if (!this.stellarNetworks.length) {
72
76
  return undefined;
73
77
  }
74
- // If selectedNetwork is already set, return its chainId
75
78
  if (this.selectedNetwork) {
76
79
  return String(this.selectedNetwork.chainId);
77
80
  }
78
- // Detect network from address (needed after page reload)
79
- const address = yield this.getAddress();
80
- if (!address) {
81
- return undefined;
82
- }
83
- const detectedChainId = yield getNetworkFromAddress.getNetworkFromAddress(address, this.stellarNetworks[0]);
84
- if (!detectedChainId) {
85
- return undefined;
86
- }
87
- // Find and set the selectedNetwork based on detected chainId
88
- this.selectedNetwork = this.stellarNetworks.find((n) => n.chainId.toString() === detectedChainId);
89
- // If no exact match found, determine if it's testnet or mainnet based on the chainId
90
- // and select the appropriate network from stellarNetworks
91
- if (!this.selectedNetwork) {
92
- // Testnet chainId starts with 'cee0302d', mainnet with '7ac33997'
93
- const isTestnet = detectedChainId.startsWith('cee0302d');
94
- this.selectedNetwork = this.stellarNetworks.find((n) => {
81
+ // Check localStorage cache for a previously stored network ID
82
+ const storedNetworkId = yield this.cache.getStoredNetwork();
83
+ if (storedNetworkId) {
84
+ const cachedNetwork = this.stellarNetworks.find((n) => {
95
85
  var _a, _b;
96
- return isTestnet
97
- ? (_a = n.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('testnet')
98
- : !((_b = n.name) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('testnet'));
86
+ return ((_a = n.chainId) === null || _a === void 0 ? void 0 : _a.toString()) === storedNetworkId ||
87
+ ((_b = n.networkId) === null || _b === void 0 ? void 0 : _b.toString()) === storedNetworkId;
99
88
  });
100
- // If still no match, use the first network
101
- if (!this.selectedNetwork) {
102
- [this.selectedNetwork] = this.stellarNetworks;
89
+ if (cachedNetwork) {
90
+ this.selectedNetwork = cachedNetwork;
91
+ return String(cachedNetwork.chainId);
103
92
  }
104
93
  }
105
- // Return chainId (the hash) for network validation
106
- // This matches the chainId/networkId in the enabled networks from the API
107
- return String((_a = this.selectedNetwork) === null || _a === void 0 ? void 0 : _a.chainId);
94
+ // Fall back to the first configured network
95
+ [this.selectedNetwork] = this.stellarNetworks;
96
+ return String(this.selectedNetwork.chainId);
108
97
  });
109
98
  }
110
99
  /**
@@ -195,8 +184,10 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
195
184
  if (!provider) {
196
185
  // Still clear state even if no provider
197
186
  this.connectedPublicKey = undefined;
187
+ this.selectedNetwork = undefined;
198
188
  this.getAddressPromise = undefined;
199
189
  yield this.cache.clearConnectedAcccounts();
190
+ yield this.cache.clearStoredNetwork();
200
191
  return;
201
192
  }
202
193
  try {
@@ -207,8 +198,10 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
207
198
  }
208
199
  // Clear all cached state
209
200
  this.connectedPublicKey = undefined;
201
+ this.selectedNetwork = undefined;
210
202
  this.getAddressPromise = undefined;
211
203
  yield this.cache.clearConnectedAcccounts();
204
+ yield this.cache.clearStoredNetwork();
212
205
  });
213
206
  }
214
207
  /**
@@ -228,8 +221,40 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
228
221
  });
229
222
  });
230
223
  }
224
+ /**
225
+ * Signs a message using a Stellar ManageData transaction.
226
+ * Used as a fallback for hardware wallets (e.g. Ledger via Freighter) that
227
+ * cannot sign arbitrary data directly. Returns the signed transaction XDR.
228
+ */
229
+ signMessageViaTransaction(message) {
230
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
231
+ const address = yield this.getAddress();
232
+ if (!address) {
233
+ throw new utils.DynamicError('No connected address for hardware wallet signing');
234
+ }
235
+ const horizonServer = yield this.getHorizonServer();
236
+ const networkPassphrase = yield this.getNetworkPassphrase();
237
+ const account = yield horizonServer.loadAccount(address);
238
+ const messageBytes = Buffer.from(message);
239
+ // ManageData value is limited to 64 bytes; hash longer messages with SHA-256
240
+ const value = messageBytes.length > 64 ? stellarSdk.hash(messageBytes) : messageBytes;
241
+ const transaction = new stellarSdk.TransactionBuilder(account, {
242
+ fee: '100',
243
+ networkPassphrase,
244
+ })
245
+ .addOperation(stellarSdk.Operation.manageData({
246
+ name: 'dynamic:auth',
247
+ value,
248
+ }))
249
+ .setTimeout(30)
250
+ .build();
251
+ return this.signTransaction(transaction.toXDR());
252
+ });
253
+ }
231
254
  /**
232
255
  * Signs a message.
256
+ * For hardware wallets (e.g. Ledger via Freighter), falls back to signing a
257
+ * ManageData transaction because hardware wallets cannot sign arbitrary data.
233
258
  */
234
259
  signMessage(messageToSign) {
235
260
  return _tslib.__awaiter(this, void 0, void 0, function* () {
@@ -237,7 +262,20 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
237
262
  if (!provider) {
238
263
  return undefined;
239
264
  }
240
- return provider.signMessage(messageToSign);
265
+ if (this.isHardwareWalletEnabled) {
266
+ return this.signMessageViaTransaction(messageToSign);
267
+ }
268
+ try {
269
+ return yield provider.signMessage(messageToSign);
270
+ }
271
+ catch (error) {
272
+ const errorMessage = error instanceof Error ? error.message : String(error);
273
+ if (errorMessage.toLowerCase().includes('hardware wallet')) {
274
+ this.isHardwareWalletEnabled = true;
275
+ return this.signMessageViaTransaction(messageToSign);
276
+ }
277
+ throw error;
278
+ }
241
279
  });
242
280
  }
243
281
  getHorizonServer() {
@@ -459,9 +497,11 @@ class StellarWalletConnector extends walletConnectorCore.WalletConnectorBase {
459
497
  endSession() {
460
498
  return _tslib.__awaiter(this, void 0, void 0, function* () {
461
499
  this.connectedPublicKey = undefined;
500
+ this.selectedNetwork = undefined;
462
501
  this.getAddressPromise = undefined;
463
502
  this.connectionCancelled = false;
464
503
  yield this.cache.clearConnectedAcccounts();
504
+ yield this.cache.clearStoredNetwork();
465
505
  });
466
506
  }
467
507
  /**
@@ -30,8 +30,10 @@ export declare abstract class StellarWalletConnector extends WalletConnectorBase
30
30
  /** Promise cache to prevent multiple simultaneous getAddress calls */
31
31
  private getAddressPromise;
32
32
  private selectedNetwork;
33
+ isHardwareWalletEnabled: boolean;
33
34
  stellarNetworks: GenericNetwork[];
34
35
  constructor(name: string, opts: StellarWalletConnectorProps);
36
+ canConnectWithHardwareWallet(): boolean;
35
37
  /**
36
38
  * Abstract method to get the wallet provider.
37
39
  * Must be implemented by concrete connector classes.
@@ -61,8 +63,16 @@ export declare abstract class StellarWalletConnector extends WalletConnectorBase
61
63
  * Signs a Stellar transaction XDR.
62
64
  */
63
65
  signTransaction(transactionXdr: string): Promise<string>;
66
+ /**
67
+ * Signs a message using a Stellar ManageData transaction.
68
+ * Used as a fallback for hardware wallets (e.g. Ledger via Freighter) that
69
+ * cannot sign arbitrary data directly. Returns the signed transaction XDR.
70
+ */
71
+ private signMessageViaTransaction;
64
72
  /**
65
73
  * Signs a message.
74
+ * For hardware wallets (e.g. Ledger via Freighter), falls back to signing a
75
+ * ManageData transaction because hardware wallets cannot sign arbitrary data.
66
76
  */
67
77
  signMessage(messageToSign: string): Promise<string | undefined>;
68
78
  getHorizonServer(): Promise<Horizon.Server>;
@@ -1,13 +1,12 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../_virtual/_tslib.js';
3
- import { Horizon, Networks, TransactionBuilder } from '@stellar/stellar-sdk';
3
+ import { hash, TransactionBuilder, Operation, Horizon, Networks } from '@stellar/stellar-sdk';
4
4
  import { Logger } from '@dynamic-labs/logger';
5
5
  import { DynamicError } from '@dynamic-labs/utils';
6
6
  import { WalletConnectorBase } from '@dynamic-labs/wallet-connector-core';
7
7
  import { StellarWallet } from '../../wallet/StellarWallet.js';
8
- import { getNetworkFromAddress } from '../../utils/getNetworkFromAddress.js';
9
- import { StellarUiTransaction } from '../../utils/StellarUiTransaction/StellarUiTransaction.js';
10
8
  import { StellarLocalStorageCache } from '../../StellarLocalStorageCache.js';
9
+ import { StellarUiTransaction } from '../../utils/StellarUiTransaction/StellarUiTransaction.js';
11
10
 
12
11
  const HORIZON_MAINNET_URL = 'https://horizon.stellar.org';
13
12
  const HORIZON_TESTNET_URL = 'https://horizon-testnet.stellar.org';
@@ -33,12 +32,17 @@ class StellarWalletConnector extends WalletConnectorBase {
33
32
  this.isConnecting = false;
34
33
  /** Flag to track if connection was cancelled by disconnect */
35
34
  this.connectionCancelled = false;
35
+ this.isHardwareWalletEnabled = false;
36
36
  this.name = name;
37
37
  this.logger = new Logger(this.name);
38
38
  this.stellarNetworks = (_a = opts.stellarNetworks) !== null && _a !== void 0 ? _a : [];
39
39
  this.overrideKey = this.key;
40
40
  this.cache = new StellarLocalStorageCache(this.overrideKey);
41
41
  }
42
+ canConnectWithHardwareWallet() {
43
+ var _a;
44
+ return Boolean((_a = this.metadata.supportedHardwareWallets) === null || _a === void 0 ? void 0 : _a.includes('ledger'));
45
+ }
42
46
  getEnabledNetworks() {
43
47
  return this.stellarNetworks;
44
48
  }
@@ -57,50 +61,35 @@ class StellarWalletConnector extends WalletConnectorBase {
57
61
  const network = this.stellarNetworks.find((n) => { var _a, _b; return ((_a = n.chainId) === null || _a === void 0 ? void 0 : _a.toString()) === idStr || ((_b = n.networkId) === null || _b === void 0 ? void 0 : _b.toString()) === idStr; });
58
62
  if (network) {
59
63
  this.selectedNetwork = network;
64
+ yield this.cache.setStoredNetwork(String(network.chainId));
60
65
  this.emit('chainChange', { chain: String(network.chainId) });
61
66
  }
62
67
  });
63
68
  }
64
69
  getNetwork() {
65
70
  return __awaiter(this, void 0, void 0, function* () {
66
- var _a;
67
71
  if (!this.stellarNetworks.length) {
68
72
  return undefined;
69
73
  }
70
- // If selectedNetwork is already set, return its chainId
71
74
  if (this.selectedNetwork) {
72
75
  return String(this.selectedNetwork.chainId);
73
76
  }
74
- // Detect network from address (needed after page reload)
75
- const address = yield this.getAddress();
76
- if (!address) {
77
- return undefined;
78
- }
79
- const detectedChainId = yield getNetworkFromAddress(address, this.stellarNetworks[0]);
80
- if (!detectedChainId) {
81
- return undefined;
82
- }
83
- // Find and set the selectedNetwork based on detected chainId
84
- this.selectedNetwork = this.stellarNetworks.find((n) => n.chainId.toString() === detectedChainId);
85
- // If no exact match found, determine if it's testnet or mainnet based on the chainId
86
- // and select the appropriate network from stellarNetworks
87
- if (!this.selectedNetwork) {
88
- // Testnet chainId starts with 'cee0302d', mainnet with '7ac33997'
89
- const isTestnet = detectedChainId.startsWith('cee0302d');
90
- this.selectedNetwork = this.stellarNetworks.find((n) => {
77
+ // Check localStorage cache for a previously stored network ID
78
+ const storedNetworkId = yield this.cache.getStoredNetwork();
79
+ if (storedNetworkId) {
80
+ const cachedNetwork = this.stellarNetworks.find((n) => {
91
81
  var _a, _b;
92
- return isTestnet
93
- ? (_a = n.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes('testnet')
94
- : !((_b = n.name) === null || _b === void 0 ? void 0 : _b.toLowerCase().includes('testnet'));
82
+ return ((_a = n.chainId) === null || _a === void 0 ? void 0 : _a.toString()) === storedNetworkId ||
83
+ ((_b = n.networkId) === null || _b === void 0 ? void 0 : _b.toString()) === storedNetworkId;
95
84
  });
96
- // If still no match, use the first network
97
- if (!this.selectedNetwork) {
98
- [this.selectedNetwork] = this.stellarNetworks;
85
+ if (cachedNetwork) {
86
+ this.selectedNetwork = cachedNetwork;
87
+ return String(cachedNetwork.chainId);
99
88
  }
100
89
  }
101
- // Return chainId (the hash) for network validation
102
- // This matches the chainId/networkId in the enabled networks from the API
103
- return String((_a = this.selectedNetwork) === null || _a === void 0 ? void 0 : _a.chainId);
90
+ // Fall back to the first configured network
91
+ [this.selectedNetwork] = this.stellarNetworks;
92
+ return String(this.selectedNetwork.chainId);
104
93
  });
105
94
  }
106
95
  /**
@@ -191,8 +180,10 @@ class StellarWalletConnector extends WalletConnectorBase {
191
180
  if (!provider) {
192
181
  // Still clear state even if no provider
193
182
  this.connectedPublicKey = undefined;
183
+ this.selectedNetwork = undefined;
194
184
  this.getAddressPromise = undefined;
195
185
  yield this.cache.clearConnectedAcccounts();
186
+ yield this.cache.clearStoredNetwork();
196
187
  return;
197
188
  }
198
189
  try {
@@ -203,8 +194,10 @@ class StellarWalletConnector extends WalletConnectorBase {
203
194
  }
204
195
  // Clear all cached state
205
196
  this.connectedPublicKey = undefined;
197
+ this.selectedNetwork = undefined;
206
198
  this.getAddressPromise = undefined;
207
199
  yield this.cache.clearConnectedAcccounts();
200
+ yield this.cache.clearStoredNetwork();
208
201
  });
209
202
  }
210
203
  /**
@@ -224,8 +217,40 @@ class StellarWalletConnector extends WalletConnectorBase {
224
217
  });
225
218
  });
226
219
  }
220
+ /**
221
+ * Signs a message using a Stellar ManageData transaction.
222
+ * Used as a fallback for hardware wallets (e.g. Ledger via Freighter) that
223
+ * cannot sign arbitrary data directly. Returns the signed transaction XDR.
224
+ */
225
+ signMessageViaTransaction(message) {
226
+ return __awaiter(this, void 0, void 0, function* () {
227
+ const address = yield this.getAddress();
228
+ if (!address) {
229
+ throw new DynamicError('No connected address for hardware wallet signing');
230
+ }
231
+ const horizonServer = yield this.getHorizonServer();
232
+ const networkPassphrase = yield this.getNetworkPassphrase();
233
+ const account = yield horizonServer.loadAccount(address);
234
+ const messageBytes = Buffer.from(message);
235
+ // ManageData value is limited to 64 bytes; hash longer messages with SHA-256
236
+ const value = messageBytes.length > 64 ? hash(messageBytes) : messageBytes;
237
+ const transaction = new TransactionBuilder(account, {
238
+ fee: '100',
239
+ networkPassphrase,
240
+ })
241
+ .addOperation(Operation.manageData({
242
+ name: 'dynamic:auth',
243
+ value,
244
+ }))
245
+ .setTimeout(30)
246
+ .build();
247
+ return this.signTransaction(transaction.toXDR());
248
+ });
249
+ }
227
250
  /**
228
251
  * Signs a message.
252
+ * For hardware wallets (e.g. Ledger via Freighter), falls back to signing a
253
+ * ManageData transaction because hardware wallets cannot sign arbitrary data.
229
254
  */
230
255
  signMessage(messageToSign) {
231
256
  return __awaiter(this, void 0, void 0, function* () {
@@ -233,7 +258,20 @@ class StellarWalletConnector extends WalletConnectorBase {
233
258
  if (!provider) {
234
259
  return undefined;
235
260
  }
236
- return provider.signMessage(messageToSign);
261
+ if (this.isHardwareWalletEnabled) {
262
+ return this.signMessageViaTransaction(messageToSign);
263
+ }
264
+ try {
265
+ return yield provider.signMessage(messageToSign);
266
+ }
267
+ catch (error) {
268
+ const errorMessage = error instanceof Error ? error.message : String(error);
269
+ if (errorMessage.toLowerCase().includes('hardware wallet')) {
270
+ this.isHardwareWalletEnabled = true;
271
+ return this.signMessageViaTransaction(messageToSign);
272
+ }
273
+ throw error;
274
+ }
237
275
  });
238
276
  }
239
277
  getHorizonServer() {
@@ -455,9 +493,11 @@ class StellarWalletConnector extends WalletConnectorBase {
455
493
  endSession() {
456
494
  return __awaiter(this, void 0, void 0, function* () {
457
495
  this.connectedPublicKey = undefined;
496
+ this.selectedNetwork = undefined;
458
497
  this.getAddressPromise = undefined;
459
498
  this.connectionCancelled = false;
460
499
  yield this.cache.clearConnectedAcccounts();
500
+ yield this.cache.clearStoredNetwork();
461
501
  });
462
502
  }
463
503
  /**