@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.
- package/README.md +272 -0
- package/dist/config.cjs +21 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +8 -0
- package/dist/config.d.cts.map +1 -0
- package/dist/config.d.mts +8 -0
- package/dist/config.d.mts.map +1 -0
- package/dist/config.mjs +20 -0
- package/dist/config.mjs.map +1 -0
- package/dist/index.cjs +7564 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +261 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +263 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +7529 -0
- package/dist/index.mjs.map +1 -0
- package/dist/metadata.cjs +22 -0
- package/dist/metadata.cjs.map +1 -0
- package/dist/metadata.d.cts +7 -0
- package/dist/metadata.d.cts.map +1 -0
- package/dist/metadata.d.mts +7 -0
- package/dist/metadata.d.mts.map +1 -0
- package/dist/metadata.mjs +21 -0
- package/dist/metadata.mjs.map +1 -0
- package/dist/networks-BrV516-R.d.cts +15 -0
- package/dist/networks-BrV516-R.d.cts.map +1 -0
- package/dist/networks-C0MmhJcu.d.mts +15 -0
- package/dist/networks-C0MmhJcu.d.mts.map +1 -0
- package/dist/networks-DgUFSTiC.cjs +76 -0
- package/dist/networks-DgUFSTiC.cjs.map +1 -0
- package/dist/networks-QbEPbaGT.mjs +46 -0
- package/dist/networks-QbEPbaGT.mjs.map +1 -0
- package/dist/networks.cjs +8 -0
- package/dist/networks.d.cts +2 -0
- package/dist/networks.d.mts +2 -0
- package/dist/networks.mjs +3 -0
- package/dist/vite-config.cjs +43 -0
- package/dist/vite-config.cjs.map +1 -0
- package/dist/vite-config.d.cts +35 -0
- package/dist/vite-config.d.cts.map +1 -0
- package/dist/vite-config.d.mts +35 -0
- package/dist/vite-config.d.mts.map +1 -0
- package/dist/vite-config.mjs +42 -0
- package/dist/vite-config.mjs.map +1 -0
- package/package.json +114 -0
- package/src/__tests__/getDefaultServiceConfig.test.ts +105 -0
- package/src/access-control/actions.ts +214 -0
- package/src/access-control/feature-detection.ts +238 -0
- package/src/access-control/index.ts +54 -0
- package/src/access-control/indexer-client.ts +1474 -0
- package/src/access-control/onchain-reader.ts +446 -0
- package/src/access-control/service.ts +1431 -0
- package/src/access-control/validation.ts +256 -0
- package/src/adapter.ts +659 -0
- package/src/config.ts +43 -0
- package/src/configuration/__tests__/explorer.test.ts +80 -0
- package/src/configuration/__tests__/rpc.test.ts +355 -0
- package/src/configuration/execution.ts +83 -0
- package/src/configuration/explorer.ts +105 -0
- package/src/configuration/index.ts +5 -0
- package/src/configuration/network-services.ts +210 -0
- package/src/configuration/rpc.ts +270 -0
- package/src/configuration.ts +2 -0
- package/src/contract/__tests__/complete-type-coverage.test.ts +78 -0
- package/src/contract/index.ts +3 -0
- package/src/contract/loader.ts +498 -0
- package/src/contract/transformer.ts +1 -0
- package/src/contract/type.ts +65 -0
- package/src/index.ts +23 -0
- package/src/mapping/constants.ts +89 -0
- package/src/mapping/enum-metadata.ts +237 -0
- package/src/mapping/field-generator.ts +296 -0
- package/src/mapping/index.ts +5 -0
- package/src/mapping/struct-fields.ts +106 -0
- package/src/mapping/tuple-components.ts +43 -0
- package/src/mapping/type-coverage-validator.ts +151 -0
- package/src/mapping/type-mapper.ts +203 -0
- package/src/metadata.ts +16 -0
- package/src/networks/README.md +84 -0
- package/src/networks/index.ts +19 -0
- package/src/networks/mainnet.ts +20 -0
- package/src/networks/testnet.ts +20 -0
- package/src/networks.ts +2 -0
- package/src/query/handler.ts +411 -0
- package/src/query/index.ts +4 -0
- package/src/query/view-checker.ts +32 -0
- package/src/sac/spec-cache.ts +68 -0
- package/src/sac/spec-source.ts +35 -0
- package/src/sac/xdr.ts +101 -0
- package/src/transaction/components/AdvancedInfo.tsx +34 -0
- package/src/transaction/components/FeeConfiguration.tsx +41 -0
- package/src/transaction/components/StellarRelayerOptions.tsx +60 -0
- package/src/transaction/components/TransactionTiming.tsx +77 -0
- package/src/transaction/components/index.ts +5 -0
- package/src/transaction/components/useStellarRelayerOptions.ts +114 -0
- package/src/transaction/eoa.ts +229 -0
- package/src/transaction/execution-strategy.ts +33 -0
- package/src/transaction/formatter.ts +296 -0
- package/src/transaction/index.ts +4 -0
- package/src/transaction/relayer.ts +575 -0
- package/src/transaction/sender.ts +156 -0
- package/src/transform/index.ts +4 -0
- package/src/transform/input-parser.ts +9 -0
- package/src/transform/output-formatter.ts +133 -0
- package/src/transform/parsers/complex-parser.ts +157 -0
- package/src/transform/parsers/generic-parser.ts +171 -0
- package/src/transform/parsers/index.ts +86 -0
- package/src/transform/parsers/primitive-parser.ts +123 -0
- package/src/transform/parsers/scval-converter.ts +405 -0
- package/src/transform/parsers/struct-parser.ts +324 -0
- package/src/transform/parsers/types.ts +35 -0
- package/src/types/__tests__/artifacts.test.ts +89 -0
- package/src/types/artifacts.ts +19 -0
- package/src/utils/__tests__/artifacts.test.ts +77 -0
- package/src/utils/artifacts.ts +30 -0
- package/src/utils/formatting.ts +122 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/input-parsing.ts +336 -0
- package/src/utils/safe-type-parser.ts +303 -0
- package/src/utils/stellar-types.ts +35 -0
- package/src/utils/type-detection.ts +163 -0
- package/src/utils/xdr-ordering.ts +36 -0
- package/src/validation/__tests__/address.test.ts +267 -0
- package/src/validation/address.ts +136 -0
- package/src/validation/eoa.ts +33 -0
- package/src/validation/index.ts +3 -0
- package/src/validation/relayer.ts +13 -0
- package/src/vite-config.ts +67 -0
- package/src/wallet/README.md +93 -0
- package/src/wallet/__tests__/connection.test.ts +72 -0
- package/src/wallet/components/StellarWalletUiRoot.tsx +161 -0
- package/src/wallet/components/account/AccountDisplay.tsx +50 -0
- package/src/wallet/components/connect/ConnectButton.tsx +100 -0
- package/src/wallet/components/connect/ConnectorDialog.tsx +125 -0
- package/src/wallet/components/index.ts +3 -0
- package/src/wallet/connection.ts +151 -0
- package/src/wallet/context/StellarWalletContext.ts +32 -0
- package/src/wallet/context/index.ts +4 -0
- package/src/wallet/context/useStellarWalletContext.ts +17 -0
- package/src/wallet/hooks/facade-hooks.ts +31 -0
- package/src/wallet/hooks/index.ts +7 -0
- package/src/wallet/hooks/useStellarAccount.ts +27 -0
- package/src/wallet/hooks/useStellarConnect.ts +60 -0
- package/src/wallet/hooks/useStellarDisconnect.ts +47 -0
- package/src/wallet/hooks/useUiKitConfig.ts +40 -0
- package/src/wallet/implementation/wallets-kit-implementation.ts +379 -0
- package/src/wallet/index.ts +11 -0
- package/src/wallet/services/__tests__/configResolutionService.test.ts +163 -0
- package/src/wallet/services/configResolutionService.ts +65 -0
- package/src/wallet/stellar-wallets-kit/StellarWalletsKitConnectButton.tsx +82 -0
- package/src/wallet/stellar-wallets-kit/__mocks__/@creit.tech/stellar-wallets-kit.ts +48 -0
- package/src/wallet/stellar-wallets-kit/__tests__/export-service.test.ts +93 -0
- package/src/wallet/stellar-wallets-kit/__tests__/stellarUiKitManager.test.ts +0 -0
- package/src/wallet/stellar-wallets-kit/config-generator.ts +75 -0
- package/src/wallet/stellar-wallets-kit/export-service.ts +19 -0
- package/src/wallet/stellar-wallets-kit/index.ts +3 -0
- package/src/wallet/stellar-wallets-kit/stellarUiKitManager.ts +235 -0
- package/src/wallet/types.ts +19 -0
- package/src/wallet/utils/__tests__/filterWalletComponents.test.ts +150 -0
- package/src/wallet/utils/__tests__/uiKitService.test.ts +189 -0
- package/src/wallet/utils/filterWalletComponents.ts +89 -0
- package/src/wallet/utils/index.ts +3 -0
- package/src/wallet/utils/stellarWalletImplementationManager.ts +118 -0
- 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
|
+
});
|
|
File without changes
|
|
@@ -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,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
|
+
});
|