@openzeppelin/adapter-stellar 1.0.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.
Files changed (165) hide show
  1. package/README.md +272 -0
  2. package/dist/config.cjs +21 -0
  3. package/dist/config.cjs.map +1 -0
  4. package/dist/config.d.cts +8 -0
  5. package/dist/config.d.cts.map +1 -0
  6. package/dist/config.d.mts +8 -0
  7. package/dist/config.d.mts.map +1 -0
  8. package/dist/config.mjs +20 -0
  9. package/dist/config.mjs.map +1 -0
  10. package/dist/index.cjs +7564 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +261 -0
  13. package/dist/index.d.cts.map +1 -0
  14. package/dist/index.d.mts +263 -0
  15. package/dist/index.d.mts.map +1 -0
  16. package/dist/index.mjs +7529 -0
  17. package/dist/index.mjs.map +1 -0
  18. package/dist/metadata.cjs +22 -0
  19. package/dist/metadata.cjs.map +1 -0
  20. package/dist/metadata.d.cts +7 -0
  21. package/dist/metadata.d.cts.map +1 -0
  22. package/dist/metadata.d.mts +7 -0
  23. package/dist/metadata.d.mts.map +1 -0
  24. package/dist/metadata.mjs +21 -0
  25. package/dist/metadata.mjs.map +1 -0
  26. package/dist/networks-BrV516-R.d.cts +15 -0
  27. package/dist/networks-BrV516-R.d.cts.map +1 -0
  28. package/dist/networks-C0MmhJcu.d.mts +15 -0
  29. package/dist/networks-C0MmhJcu.d.mts.map +1 -0
  30. package/dist/networks-DgUFSTiC.cjs +76 -0
  31. package/dist/networks-DgUFSTiC.cjs.map +1 -0
  32. package/dist/networks-QbEPbaGT.mjs +46 -0
  33. package/dist/networks-QbEPbaGT.mjs.map +1 -0
  34. package/dist/networks.cjs +8 -0
  35. package/dist/networks.d.cts +2 -0
  36. package/dist/networks.d.mts +2 -0
  37. package/dist/networks.mjs +3 -0
  38. package/dist/vite-config.cjs +43 -0
  39. package/dist/vite-config.cjs.map +1 -0
  40. package/dist/vite-config.d.cts +35 -0
  41. package/dist/vite-config.d.cts.map +1 -0
  42. package/dist/vite-config.d.mts +35 -0
  43. package/dist/vite-config.d.mts.map +1 -0
  44. package/dist/vite-config.mjs +42 -0
  45. package/dist/vite-config.mjs.map +1 -0
  46. package/package.json +114 -0
  47. package/src/__tests__/getDefaultServiceConfig.test.ts +105 -0
  48. package/src/access-control/actions.ts +214 -0
  49. package/src/access-control/feature-detection.ts +238 -0
  50. package/src/access-control/index.ts +54 -0
  51. package/src/access-control/indexer-client.ts +1474 -0
  52. package/src/access-control/onchain-reader.ts +446 -0
  53. package/src/access-control/service.ts +1431 -0
  54. package/src/access-control/validation.ts +256 -0
  55. package/src/adapter.ts +659 -0
  56. package/src/config.ts +43 -0
  57. package/src/configuration/__tests__/explorer.test.ts +80 -0
  58. package/src/configuration/__tests__/rpc.test.ts +355 -0
  59. package/src/configuration/execution.ts +83 -0
  60. package/src/configuration/explorer.ts +105 -0
  61. package/src/configuration/index.ts +5 -0
  62. package/src/configuration/network-services.ts +210 -0
  63. package/src/configuration/rpc.ts +270 -0
  64. package/src/configuration.ts +2 -0
  65. package/src/contract/__tests__/complete-type-coverage.test.ts +78 -0
  66. package/src/contract/index.ts +3 -0
  67. package/src/contract/loader.ts +498 -0
  68. package/src/contract/transformer.ts +1 -0
  69. package/src/contract/type.ts +65 -0
  70. package/src/index.ts +23 -0
  71. package/src/mapping/constants.ts +89 -0
  72. package/src/mapping/enum-metadata.ts +237 -0
  73. package/src/mapping/field-generator.ts +296 -0
  74. package/src/mapping/index.ts +5 -0
  75. package/src/mapping/struct-fields.ts +106 -0
  76. package/src/mapping/tuple-components.ts +43 -0
  77. package/src/mapping/type-coverage-validator.ts +151 -0
  78. package/src/mapping/type-mapper.ts +203 -0
  79. package/src/metadata.ts +16 -0
  80. package/src/networks/README.md +84 -0
  81. package/src/networks/index.ts +19 -0
  82. package/src/networks/mainnet.ts +20 -0
  83. package/src/networks/testnet.ts +20 -0
  84. package/src/networks.ts +2 -0
  85. package/src/query/handler.ts +411 -0
  86. package/src/query/index.ts +4 -0
  87. package/src/query/view-checker.ts +32 -0
  88. package/src/sac/spec-cache.ts +68 -0
  89. package/src/sac/spec-source.ts +35 -0
  90. package/src/sac/xdr.ts +101 -0
  91. package/src/transaction/components/AdvancedInfo.tsx +34 -0
  92. package/src/transaction/components/FeeConfiguration.tsx +41 -0
  93. package/src/transaction/components/StellarRelayerOptions.tsx +60 -0
  94. package/src/transaction/components/TransactionTiming.tsx +77 -0
  95. package/src/transaction/components/index.ts +5 -0
  96. package/src/transaction/components/useStellarRelayerOptions.ts +114 -0
  97. package/src/transaction/eoa.ts +229 -0
  98. package/src/transaction/execution-strategy.ts +33 -0
  99. package/src/transaction/formatter.ts +296 -0
  100. package/src/transaction/index.ts +4 -0
  101. package/src/transaction/relayer.ts +575 -0
  102. package/src/transaction/sender.ts +156 -0
  103. package/src/transform/index.ts +4 -0
  104. package/src/transform/input-parser.ts +9 -0
  105. package/src/transform/output-formatter.ts +133 -0
  106. package/src/transform/parsers/complex-parser.ts +157 -0
  107. package/src/transform/parsers/generic-parser.ts +171 -0
  108. package/src/transform/parsers/index.ts +86 -0
  109. package/src/transform/parsers/primitive-parser.ts +123 -0
  110. package/src/transform/parsers/scval-converter.ts +405 -0
  111. package/src/transform/parsers/struct-parser.ts +324 -0
  112. package/src/transform/parsers/types.ts +35 -0
  113. package/src/types/__tests__/artifacts.test.ts +89 -0
  114. package/src/types/artifacts.ts +19 -0
  115. package/src/utils/__tests__/artifacts.test.ts +77 -0
  116. package/src/utils/artifacts.ts +30 -0
  117. package/src/utils/formatting.ts +122 -0
  118. package/src/utils/index.ts +6 -0
  119. package/src/utils/input-parsing.ts +336 -0
  120. package/src/utils/safe-type-parser.ts +303 -0
  121. package/src/utils/stellar-types.ts +35 -0
  122. package/src/utils/type-detection.ts +163 -0
  123. package/src/utils/xdr-ordering.ts +36 -0
  124. package/src/validation/__tests__/address.test.ts +267 -0
  125. package/src/validation/address.ts +136 -0
  126. package/src/validation/eoa.ts +33 -0
  127. package/src/validation/index.ts +3 -0
  128. package/src/validation/relayer.ts +13 -0
  129. package/src/vite-config.ts +67 -0
  130. package/src/wallet/README.md +93 -0
  131. package/src/wallet/__tests__/connection.test.ts +72 -0
  132. package/src/wallet/components/StellarWalletUiRoot.tsx +161 -0
  133. package/src/wallet/components/account/AccountDisplay.tsx +50 -0
  134. package/src/wallet/components/connect/ConnectButton.tsx +100 -0
  135. package/src/wallet/components/connect/ConnectorDialog.tsx +125 -0
  136. package/src/wallet/components/index.ts +3 -0
  137. package/src/wallet/connection.ts +151 -0
  138. package/src/wallet/context/StellarWalletContext.ts +32 -0
  139. package/src/wallet/context/index.ts +4 -0
  140. package/src/wallet/context/useStellarWalletContext.ts +17 -0
  141. package/src/wallet/hooks/facade-hooks.ts +31 -0
  142. package/src/wallet/hooks/index.ts +7 -0
  143. package/src/wallet/hooks/useStellarAccount.ts +27 -0
  144. package/src/wallet/hooks/useStellarConnect.ts +60 -0
  145. package/src/wallet/hooks/useStellarDisconnect.ts +47 -0
  146. package/src/wallet/hooks/useUiKitConfig.ts +40 -0
  147. package/src/wallet/implementation/wallets-kit-implementation.ts +379 -0
  148. package/src/wallet/index.ts +11 -0
  149. package/src/wallet/services/__tests__/configResolutionService.test.ts +163 -0
  150. package/src/wallet/services/configResolutionService.ts +65 -0
  151. package/src/wallet/stellar-wallets-kit/StellarWalletsKitConnectButton.tsx +82 -0
  152. package/src/wallet/stellar-wallets-kit/__mocks__/@creit.tech/stellar-wallets-kit.ts +48 -0
  153. package/src/wallet/stellar-wallets-kit/__tests__/export-service.test.ts +93 -0
  154. package/src/wallet/stellar-wallets-kit/__tests__/stellarUiKitManager.test.ts +0 -0
  155. package/src/wallet/stellar-wallets-kit/config-generator.ts +75 -0
  156. package/src/wallet/stellar-wallets-kit/export-service.ts +19 -0
  157. package/src/wallet/stellar-wallets-kit/index.ts +3 -0
  158. package/src/wallet/stellar-wallets-kit/stellarUiKitManager.ts +235 -0
  159. package/src/wallet/types.ts +19 -0
  160. package/src/wallet/utils/__tests__/filterWalletComponents.test.ts +150 -0
  161. package/src/wallet/utils/__tests__/uiKitService.test.ts +189 -0
  162. package/src/wallet/utils/filterWalletComponents.ts +89 -0
  163. package/src/wallet/utils/index.ts +3 -0
  164. package/src/wallet/utils/stellarWalletImplementationManager.ts +118 -0
  165. package/src/wallet/utils/uiKitService.ts +74 -0
@@ -0,0 +1,48 @@
1
+ // Mock for @creit.tech/stellar-wallets-kit to avoid CommonJS issues in tests
2
+
3
+ export const WalletNetwork = {
4
+ TESTNET: 'TESTNET',
5
+ PUBLIC: 'PUBLIC',
6
+ };
7
+
8
+ export class StellarWalletsKit {
9
+ constructor(_options: Record<string, unknown>) {
10
+ // Mock constructor
11
+ }
12
+
13
+ async getAddress() {
14
+ return { address: 'GBTEST123456789' };
15
+ }
16
+
17
+ async setWallet(_walletId: string) {
18
+ // Mock implementation
19
+ }
20
+
21
+ async getSupportedWallets() {
22
+ return [
23
+ {
24
+ id: 'freighter',
25
+ name: 'Freighter',
26
+ icon: 'https://example.com/freighter.png',
27
+ isAvailable: true,
28
+ type: 'browser',
29
+ },
30
+ ];
31
+ }
32
+
33
+ async signTransaction(_xdr: string, _options: Record<string, unknown>) {
34
+ return { signedTxXdr: 'mock-signed-xdr' };
35
+ }
36
+ }
37
+
38
+ export function allowAllModules() {
39
+ return [];
40
+ }
41
+
42
+ export interface ISupportedWallet {
43
+ id: string;
44
+ name: string;
45
+ icon: string;
46
+ isAvailable: boolean;
47
+ type: string;
48
+ }
@@ -0,0 +1,93 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import type { UiKitConfiguration } from '@openzeppelin/ui-types';
4
+
5
+ import { generateStellarWalletsKitExportables } from '../export-service';
6
+
7
+ describe('generateStellarWalletsKitExportables', () => {
8
+ it('should generate default config when no customCode is provided', () => {
9
+ const uiKitConfig: UiKitConfiguration = {
10
+ kitName: 'stellar-wallets-kit',
11
+ kitConfig: {
12
+ appName: 'My Stellar DApp',
13
+ allowTestnet: true,
14
+ },
15
+ };
16
+
17
+ const result = generateStellarWalletsKitExportables(uiKitConfig);
18
+
19
+ expect(Object.keys(result)).toEqual(['src/config/wallet/stellar-wallets-kit.config.ts']);
20
+
21
+ const content = result['src/config/wallet/stellar-wallets-kit.config.ts'];
22
+ expect(content).toContain('// Stellar Wallets Kit configuration for your exported application');
23
+ expect(content).toContain("appName: 'My Stellar DApp'");
24
+ expect(content).toContain('network: WalletNetwork.TESTNET');
25
+ });
26
+
27
+ it('should use customCode when provided', () => {
28
+ const customCode = `// Custom Stellar Wallets Kit config
29
+ import { StellarWalletsKit } from '@creit.tech/stellar-wallets-kit';
30
+
31
+ const config = {
32
+ custom: true,
33
+ appName: 'Custom App',
34
+ };
35
+
36
+ export default config;`;
37
+
38
+ const uiKitConfig: UiKitConfiguration = {
39
+ kitName: 'stellar-wallets-kit',
40
+ kitConfig: {
41
+ appName: 'My Stellar DApp',
42
+ },
43
+ customCode,
44
+ };
45
+
46
+ const result = generateStellarWalletsKitExportables(uiKitConfig);
47
+
48
+ expect(Object.keys(result)).toEqual(['src/config/wallet/stellar-wallets-kit.config.ts']);
49
+ expect(result['src/config/wallet/stellar-wallets-kit.config.ts']).toBe(customCode);
50
+ });
51
+
52
+ it('should handle empty kitConfig', () => {
53
+ const uiKitConfig: UiKitConfiguration = {
54
+ kitName: 'stellar-wallets-kit',
55
+ kitConfig: {},
56
+ };
57
+
58
+ const result = generateStellarWalletsKitExportables(uiKitConfig);
59
+
60
+ const content = result['src/config/wallet/stellar-wallets-kit.config.ts'];
61
+ expect(content).toContain("appName: 'My Stellar App'"); // default value
62
+ expect(content).toContain('network: WalletNetwork.TESTNET'); // default value
63
+ });
64
+
65
+ it('should handle WalletConnect project ID when provided', () => {
66
+ const uiKitConfig: UiKitConfiguration = {
67
+ kitName: 'stellar-wallets-kit',
68
+ kitConfig: {
69
+ walletConnectProjectId: 'my-project-id-123',
70
+ },
71
+ };
72
+
73
+ const result = generateStellarWalletsKitExportables(uiKitConfig);
74
+
75
+ const content = result['src/config/wallet/stellar-wallets-kit.config.ts'];
76
+ expect(content).toContain("walletConnectProjectId: 'my-project-id-123'");
77
+ expect(content).not.toContain('// walletConnectProjectId:');
78
+ });
79
+
80
+ it('should respect network mainnet', () => {
81
+ const uiKitConfig: UiKitConfiguration = {
82
+ kitName: 'stellar-wallets-kit',
83
+ kitConfig: {
84
+ network: 'MAINNET',
85
+ },
86
+ };
87
+
88
+ const result = generateStellarWalletsKitExportables(uiKitConfig);
89
+
90
+ const content = result['src/config/wallet/stellar-wallets-kit.config.ts'];
91
+ expect(content).toContain('network: WalletNetwork.PUBLIC');
92
+ });
93
+ });
@@ -0,0 +1,75 @@
1
+ import type { UiKitConfiguration } from '@openzeppelin/ui-types';
2
+
3
+ /**
4
+ * Generates the content for a `stellar-wallets-kit.config.ts` file for an exported project.
5
+ * This creates a configuration wrapper that can be used to initialize the Stellar Wallets Kit.
6
+ *
7
+ * @param userConfig - The user-provided configuration from the builder app.
8
+ * @returns A string containing the formatted TypeScript code for the config file.
9
+ */
10
+ export function generateStellarWalletsKitConfigFile(
11
+ userConfig: UiKitConfiguration['kitConfig']
12
+ ): string {
13
+ const config = (userConfig || {}) as Record<string, unknown>;
14
+
15
+ // Extract user-provided configuration options
16
+ const appName = (config.appName as string) || 'My Stellar App';
17
+ const network = (config.network as string) || 'TESTNET';
18
+ const walletConnectProjectId = (config.walletConnectProjectId as string) || '';
19
+ const modalTitle = (config.modalTitle as string) || `Connect to ${appName}`;
20
+ const buttonText = (config.buttonText as string) || 'Connect Wallet';
21
+
22
+ const fileContent = `// Stellar Wallets Kit configuration for your exported application
23
+ // This file is used ONLY in the exported app, not in the builder app preview
24
+
25
+ import {
26
+ StellarWalletsKit,
27
+ WalletNetwork,
28
+ allowAllModules
29
+ } from '@creit.tech/stellar-wallets-kit';
30
+
31
+ /**
32
+ * Stellar Wallets Kit configuration wrapper
33
+ *
34
+ * The kit supports multiple wallets including:
35
+ * - Freighter
36
+ * - xBull
37
+ * - Ledger
38
+ * - Trezor
39
+ * - WalletConnect
40
+ * - And more...
41
+ */
42
+ export const stellarWalletsKitConfig = {
43
+ // App information
44
+ appName: '${appName}',
45
+
46
+ // Network configuration (TESTNET or PUBLIC/MAINNET)
47
+ network: WalletNetwork.${network === 'MAINNET' || network === 'PUBLIC' ? 'PUBLIC' : 'TESTNET'},
48
+
49
+ // UI customization
50
+ buttonText: '${buttonText}',
51
+ modalTitle: '${modalTitle}',
52
+
53
+ // WalletConnect configuration
54
+ ${walletConnectProjectId ? `walletConnectProjectId: '${walletConnectProjectId}',` : "// walletConnectProjectId: 'YOUR_PROJECT_ID', // Get yours at https://cloud.walletconnect.com"}
55
+ };
56
+
57
+ /**
58
+ * Creates and configures a StellarWalletsKit instance
59
+ * @returns Configured StellarWalletsKit instance
60
+ */
61
+ export function createStellarWalletsKit(): StellarWalletsKit {
62
+ const modules = [
63
+ ...allowAllModules()
64
+ ];
65
+
66
+ return new StellarWalletsKit({
67
+ network: stellarWalletsKitConfig.network,
68
+ modules,
69
+ });
70
+ }
71
+
72
+ export default stellarWalletsKitConfig;`;
73
+
74
+ return fileContent;
75
+ }
@@ -0,0 +1,19 @@
1
+ import type { UiKitConfiguration } from '@openzeppelin/ui-types';
2
+
3
+ import { generateStellarWalletsKitConfigFile } from './config-generator';
4
+
5
+ /**
6
+ * Generates the specific configuration file for Stellar Wallets Kit during project export.
7
+ *
8
+ * @param uiKitConfig The full UI kit configuration object from the builder.
9
+ * @returns A record containing the file path and its generated content.
10
+ */
11
+ export function generateStellarWalletsKitExportables(
12
+ uiKitConfig: UiKitConfiguration
13
+ ): Record<string, string> {
14
+ const filePath = 'src/config/wallet/stellar-wallets-kit.config.ts';
15
+ const content =
16
+ uiKitConfig.customCode || generateStellarWalletsKitConfigFile(uiKitConfig.kitConfig);
17
+
18
+ return { [filePath]: content };
19
+ }
@@ -0,0 +1,3 @@
1
+ export * from './stellarUiKitManager';
2
+ export * from './export-service';
3
+ export { StellarWalletsKitConnectButton } from './StellarWalletsKitConnectButton';
@@ -0,0 +1,235 @@
1
+ import { allowAllModules, StellarWalletsKit, WalletNetwork } from '@creit.tech/stellar-wallets-kit';
2
+
3
+ import type { StellarNetworkConfig, UiKitConfiguration } from '@openzeppelin/ui-types';
4
+ import { logger } from '@openzeppelin/ui-utils';
5
+
6
+ import { getStellarWalletImplementation } from '../utils/stellarWalletImplementationManager';
7
+
8
+ export interface StellarUiKitManagerState {
9
+ isConfigured: boolean;
10
+ isInitializing: boolean;
11
+ hasConfigError: boolean;
12
+ error: Error | null;
13
+ lastConfigError: Error | null;
14
+ currentFullUiKitConfig: UiKitConfiguration | null;
15
+ stellarKitProvider: StellarWalletsKit | null;
16
+ kitProviderComponent: React.ComponentType<{ children: React.ReactNode }> | null;
17
+ isKitAssetsLoaded: boolean;
18
+ networkConfig: StellarNetworkConfig | null;
19
+ }
20
+
21
+ const getInitialState = (): StellarUiKitManagerState => ({
22
+ isConfigured: false,
23
+ isInitializing: false,
24
+ hasConfigError: false,
25
+ error: null,
26
+ lastConfigError: null,
27
+ currentFullUiKitConfig: null,
28
+ stellarKitProvider: null,
29
+ kitProviderComponent: null,
30
+ isKitAssetsLoaded: false,
31
+ networkConfig: null,
32
+ });
33
+
34
+ let state: StellarUiKitManagerState = getInitialState();
35
+
36
+ interface StellarUiKitManagerListener {
37
+ (state: StellarUiKitManagerState): void;
38
+ }
39
+
40
+ const listeners: Set<StellarUiKitManagerListener> = new Set();
41
+
42
+ function notifyListeners() {
43
+ listeners.forEach((listener) => listener(state));
44
+ }
45
+
46
+ function subscribe(listener: StellarUiKitManagerListener): () => void {
47
+ listeners.add(listener);
48
+
49
+ // Call the listener immediately with the current state
50
+ listener(state);
51
+
52
+ // Return unsubscribe function
53
+ return () => {
54
+ listeners.delete(listener);
55
+ };
56
+ }
57
+
58
+ function getState(): StellarUiKitManagerState {
59
+ return state;
60
+ }
61
+
62
+ function setNetworkConfig(config: StellarNetworkConfig): void {
63
+ state = {
64
+ ...state,
65
+ networkConfig: config,
66
+ };
67
+ notifyListeners();
68
+ }
69
+
70
+ function getWalletNetwork(networkConfig: StellarNetworkConfig | null): WalletNetwork {
71
+ if (!networkConfig) {
72
+ logger.warn('StellarUiKitManager', 'No network config available, defaulting to TESTNET');
73
+ return WalletNetwork.TESTNET;
74
+ }
75
+
76
+ return networkConfig.type === 'mainnet' ? WalletNetwork.PUBLIC : WalletNetwork.TESTNET;
77
+ }
78
+
79
+ async function configure(newFullUiKitConfig: UiKitConfiguration): Promise<void> {
80
+ logger.info(
81
+ 'StellarUiKitManager:configure',
82
+ 'Configuring UI kit. New config:',
83
+ newFullUiKitConfig
84
+ );
85
+
86
+ const oldKitName = state.currentFullUiKitConfig?.kitName;
87
+ const newKitName = newFullUiKitConfig.kitName;
88
+ const kitChanged = oldKitName !== newKitName;
89
+
90
+ state = {
91
+ ...state,
92
+ isInitializing: true,
93
+ error: null,
94
+ currentFullUiKitConfig: newFullUiKitConfig,
95
+ kitProviderComponent: kitChanged ? null : state.kitProviderComponent,
96
+ isKitAssetsLoaded: kitChanged ? false : state.isKitAssetsLoaded,
97
+ };
98
+ notifyListeners();
99
+
100
+ try {
101
+ const walletNetwork = getWalletNetwork(state.networkConfig);
102
+
103
+ if (newKitName === 'stellar-wallets-kit') {
104
+ // Initialize the Stellar Wallets Kit with its built-in UI components
105
+ const kit = new StellarWalletsKit({
106
+ network: walletNetwork,
107
+ selectedWalletId: undefined,
108
+ modules: allowAllModules(), // Use all available wallet modules
109
+ });
110
+
111
+ state.stellarKitProvider = kit;
112
+ // Stellar Wallets Kit provides its own modal UI that can be opened with kit.openModal()
113
+ // We don't need to provide custom components when using the built-in UI
114
+ state.kitProviderComponent = null;
115
+ state.isKitAssetsLoaded = true;
116
+ state.error = null;
117
+
118
+ // Wire the active kit into the wallet implementation
119
+ // This ensures signing and other operations use the correct kit instance
120
+ if (state.networkConfig) {
121
+ try {
122
+ const impl = await getStellarWalletImplementation(state.networkConfig);
123
+ impl.setActiveStellarKit(kit);
124
+ logger.debug(
125
+ 'StellarUiKitManager:configure',
126
+ 'Active kit wired into wallet implementation for stellar-wallets-kit'
127
+ );
128
+ } catch (error) {
129
+ logger.warn(
130
+ 'StellarUiKitManager:configure',
131
+ 'Failed to attach active kit to wallet implementation:',
132
+ error
133
+ );
134
+ }
135
+ }
136
+
137
+ logger.info(
138
+ 'StellarUiKitManager:configure',
139
+ 'Stellar Wallets Kit configured with built-in UI and all wallet modules'
140
+ );
141
+ } else if (newKitName === 'custom' || !newKitName) {
142
+ // Initialize the Stellar Wallets Kit for custom UI mode
143
+ const kit = new StellarWalletsKit({
144
+ network: walletNetwork,
145
+ selectedWalletId: undefined,
146
+ modules: allowAllModules(),
147
+ });
148
+
149
+ state.stellarKitProvider = kit;
150
+ state.kitProviderComponent = null;
151
+ state.isKitAssetsLoaded = true;
152
+ state.error = null;
153
+
154
+ // Wire the active kit into the wallet implementation
155
+ // This ensures signing and other operations use the correct kit instance
156
+ if (state.networkConfig) {
157
+ try {
158
+ const impl = await getStellarWalletImplementation(state.networkConfig);
159
+ impl.setActiveStellarKit(kit);
160
+ logger.debug(
161
+ 'StellarUiKitManager:configure',
162
+ 'Active kit wired into wallet implementation for custom'
163
+ );
164
+ } catch (error) {
165
+ logger.warn(
166
+ 'StellarUiKitManager:configure',
167
+ 'Failed to attach active kit to wallet implementation:',
168
+ error
169
+ );
170
+ }
171
+ }
172
+
173
+ logger.info(
174
+ 'StellarUiKitManager:configure',
175
+ 'Stellar Wallets Kit configured for custom UI components'
176
+ );
177
+ } else if (newKitName === 'none') {
178
+ // No wallet UI kit
179
+ state.stellarKitProvider = null;
180
+ state.kitProviderComponent = null;
181
+ state.isKitAssetsLoaded = false;
182
+ state.error = null;
183
+
184
+ // Clear the active kit from the wallet implementation
185
+ if (state.networkConfig) {
186
+ try {
187
+ const impl = await getStellarWalletImplementation(state.networkConfig);
188
+ impl.setActiveStellarKit(null);
189
+ logger.debug(
190
+ 'StellarUiKitManager:configure',
191
+ 'Active kit cleared from wallet implementation for none'
192
+ );
193
+ } catch (error) {
194
+ logger.warn(
195
+ 'StellarUiKitManager:configure',
196
+ 'Failed to clear active kit from wallet implementation:',
197
+ error
198
+ );
199
+ }
200
+ }
201
+
202
+ logger.info('StellarUiKitManager:configure', 'UI kit set to "none", no wallet UI provided');
203
+ } else {
204
+ throw new Error(`Unknown UI kit name: ${newKitName}`);
205
+ }
206
+
207
+ state = {
208
+ ...state,
209
+ isConfigured: true,
210
+ isInitializing: false,
211
+ hasConfigError: false,
212
+ error: null,
213
+ };
214
+ notifyListeners();
215
+ } catch (error) {
216
+ logger.error('StellarUiKitManager:configure', 'Failed to configure UI kit:', error);
217
+ state = {
218
+ ...state,
219
+ isInitializing: false,
220
+ hasConfigError: true,
221
+ error: error instanceof Error ? error : new Error('Failed to configure UI kit'),
222
+ lastConfigError: error instanceof Error ? error : new Error('Failed to configure UI kit'),
223
+ isConfigured: false,
224
+ };
225
+ notifyListeners();
226
+ throw error;
227
+ }
228
+ }
229
+
230
+ export const stellarUiKitManager = {
231
+ configure,
232
+ getState,
233
+ subscribe,
234
+ setNetworkConfig,
235
+ };
@@ -0,0 +1,19 @@
1
+ import type { WalletConnectionStatus } from '@openzeppelin/ui-types';
2
+
3
+ /**
4
+ * Stellar-specific wallet connection status extending the base interface.
5
+ * Includes Stellar-specific fields like walletId.
6
+ * Note that stellar wallets don't work with multiple addresses, only a single active address.
7
+ */
8
+ export interface StellarWalletConnectionStatus extends WalletConnectionStatus {
9
+ /** Stellar-specific wallet identifier (e.g., 'freighter', 'albedo') */
10
+ walletId?: string;
11
+ }
12
+
13
+ /**
14
+ * Type for wallet connection status listener callback
15
+ */
16
+ export type StellarConnectionStatusListener = (
17
+ status: StellarWalletConnectionStatus,
18
+ prevStatus: StellarWalletConnectionStatus
19
+ ) => void;
@@ -0,0 +1,150 @@
1
+ import { describe, expect, it } from 'vitest';
2
+
3
+ import type { EcosystemWalletComponents } from '@openzeppelin/ui-types';
4
+
5
+ import {
6
+ filterWalletComponents,
7
+ getComponentExclusionsFromConfig,
8
+ } from '../filterWalletComponents';
9
+
10
+ // Mock components
11
+ const MockConnectButton = () => null;
12
+ const MockAccountDisplay = () => null;
13
+ const MockNetworkSwitcher = () => null;
14
+
15
+ describe('filterWalletComponents', () => {
16
+ const allComponents: EcosystemWalletComponents = {
17
+ ConnectButton: MockConnectButton as React.FC,
18
+ AccountDisplay: MockAccountDisplay as React.FC,
19
+ NetworkSwitcher: MockNetworkSwitcher as React.FC,
20
+ };
21
+
22
+ it('should return all components when no exclusions', () => {
23
+ const result = filterWalletComponents(allComponents, [], 'test-kit');
24
+
25
+ expect(result).toEqual(allComponents);
26
+ expect(result).toHaveProperty('ConnectButton');
27
+ expect(result).toHaveProperty('AccountDisplay');
28
+ expect(result).toHaveProperty('NetworkSwitcher');
29
+ });
30
+
31
+ it('should exclude specified components', () => {
32
+ const result = filterWalletComponents(allComponents, ['NetworkSwitcher'], 'test-kit');
33
+
34
+ expect(result).toHaveProperty('ConnectButton');
35
+ expect(result).toHaveProperty('AccountDisplay');
36
+ expect(result).not.toHaveProperty('NetworkSwitcher');
37
+ });
38
+
39
+ it('should exclude multiple components', () => {
40
+ const result = filterWalletComponents(
41
+ allComponents,
42
+ ['NetworkSwitcher', 'AccountDisplay'],
43
+ 'test-kit'
44
+ );
45
+
46
+ expect(result).toHaveProperty('ConnectButton');
47
+ expect(result).not.toHaveProperty('AccountDisplay');
48
+ expect(result).not.toHaveProperty('NetworkSwitcher');
49
+ });
50
+
51
+ it('should return undefined when all components are excluded', () => {
52
+ const result = filterWalletComponents(
53
+ allComponents,
54
+ ['ConnectButton', 'AccountDisplay', 'NetworkSwitcher'],
55
+ 'test-kit'
56
+ );
57
+
58
+ expect(result).toBeUndefined();
59
+ });
60
+
61
+ it('should return undefined when no components provided', () => {
62
+ const result = filterWalletComponents({}, [], 'test-kit');
63
+
64
+ expect(result).toBeUndefined();
65
+ });
66
+
67
+ it('should return undefined when null components provided', () => {
68
+ const result = filterWalletComponents(
69
+ null as unknown as EcosystemWalletComponents,
70
+ [],
71
+ 'test-kit'
72
+ );
73
+
74
+ expect(result).toBeUndefined();
75
+ });
76
+
77
+ it('should ignore invalid exclusion keys', () => {
78
+ const result = filterWalletComponents(
79
+ allComponents,
80
+ ['InvalidKey' as keyof EcosystemWalletComponents, 'NetworkSwitcher'],
81
+ 'test-kit'
82
+ );
83
+
84
+ expect(result).toHaveProperty('ConnectButton');
85
+ expect(result).toHaveProperty('AccountDisplay');
86
+ expect(result).not.toHaveProperty('NetworkSwitcher');
87
+ });
88
+ });
89
+
90
+ describe('getComponentExclusionsFromConfig', () => {
91
+ it('should return empty array when no config', () => {
92
+ const result = getComponentExclusionsFromConfig(undefined);
93
+ expect(result).toEqual([]);
94
+ });
95
+
96
+ it('should return empty array when no components config', () => {
97
+ const result = getComponentExclusionsFromConfig({
98
+ showInjectedConnector: true,
99
+ });
100
+ expect(result).toEqual([]);
101
+ });
102
+
103
+ it('should return empty array when no exclude array', () => {
104
+ const result = getComponentExclusionsFromConfig({
105
+ components: {},
106
+ });
107
+ expect(result).toEqual([]);
108
+ });
109
+
110
+ it('should return exclude array when present', () => {
111
+ const result = getComponentExclusionsFromConfig({
112
+ components: {
113
+ exclude: ['NetworkSwitcher', 'AccountDisplay'],
114
+ },
115
+ });
116
+ expect(result).toEqual(['NetworkSwitcher', 'AccountDisplay']);
117
+ });
118
+
119
+ it('should handle non-array exclude value', () => {
120
+ const result = getComponentExclusionsFromConfig({
121
+ components: {
122
+ exclude: 'NetworkSwitcher' as unknown as string[],
123
+ },
124
+ });
125
+ expect(result).toEqual([]);
126
+ });
127
+
128
+ it('should filter out non-string values', () => {
129
+ const result = getComponentExclusionsFromConfig({
130
+ components: {
131
+ exclude: ['NetworkSwitcher', 123, null, 'AccountDisplay'] as unknown as string[],
132
+ },
133
+ });
134
+ expect(result).toEqual(['NetworkSwitcher', 'AccountDisplay']);
135
+ });
136
+
137
+ it('should handle nested config structure', () => {
138
+ const config = {
139
+ components: {
140
+ exclude: ['ConnectButton'],
141
+ otherProp: 'value',
142
+ },
143
+ showInjectedConnector: false,
144
+ appName: 'Test App',
145
+ };
146
+
147
+ const result = getComponentExclusionsFromConfig(config);
148
+ expect(result).toEqual(['ConnectButton']);
149
+ });
150
+ });