@openzeppelin/ui-builder-adapter-evm 1.2.0 → 1.4.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 +33 -18
- package/dist/index.cjs +4651 -4448
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -226
- package/dist/index.d.ts +12 -226
- package/dist/index.js +4737 -4535
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
- package/src/__tests__/adapter-parsing.test.ts +4 -3
- package/src/__tests__/getDefaultServiceConfig.test.ts +185 -0
- package/src/__tests__/mocks/mock-network-configs.ts +1 -1
- package/src/__tests__/provenanceLinks.test.ts +6 -4
- package/src/__tests__/providerSelection.test.ts +5 -4
- package/src/__tests__/timeouts.test.ts +5 -3
- package/src/__tests__/wallet-connect.test.ts +2 -2
- package/src/adapter.ts +61 -107
- package/src/configuration/execution.ts +1 -52
- package/src/configuration/index.ts +2 -3
- package/src/configuration/network-services.ts +47 -60
- package/src/index.ts +22 -13
- package/src/networks/index.ts +2 -1
- package/src/networks/mainnet.ts +1 -1
- package/src/networks/testnet.ts +1 -1
- package/src/query/adapter-query.ts +72 -0
- package/src/query/index.ts +2 -2
- package/src/transaction/components/useEvmRelayerOptions.ts +5 -3
- package/src/transaction/index.ts +1 -5
- package/src/types/artifacts.ts +5 -30
- package/src/types/providers.ts +7 -18
- package/src/wallet/components/EvmWalletUiRoot.tsx +1 -1
- package/src/wallet/evmUiKitManager.ts +26 -129
- package/src/wallet/hooks/index.ts +0 -1
- package/src/wallet/implementation/wagmi-implementation.ts +45 -577
- package/src/wallet/index.ts +2 -3
- package/src/wallet/rainbowkit/__tests__/export-service.test.ts +1 -2
- package/src/wallet/rainbowkit/componentFactory.ts +10 -8
- package/src/wallet/rainbowkit/components.tsx +16 -133
- package/src/wallet/rainbowkit/index.ts +27 -5
- package/src/wallet/utils/__tests__/uiKitService.test.ts +5 -1
- package/src/wallet/utils/connection.ts +8 -52
- package/src/wallet/utils/index.ts +0 -2
- package/src/wallet/utils/uiKitService.ts +7 -3
- package/src/wallet/utils/walletImplementationManager.ts +5 -4
- package/src/wallet/utils.ts +1 -65
- package/src/abi/__tests__/etherscan-v2.test.ts +0 -117
- package/src/abi/__tests__/transformer.test.ts +0 -342
- package/src/abi/comparison.ts +0 -389
- package/src/abi/etherscan-v2.ts +0 -243
- package/src/abi/etherscan.ts +0 -158
- package/src/abi/index.ts +0 -7
- package/src/abi/loader.ts +0 -415
- package/src/abi/sourcify.ts +0 -75
- package/src/abi/transformer.ts +0 -163
- package/src/abi/types.ts +0 -101
- package/src/configuration/__tests__/explorer.test.ts +0 -174
- package/src/configuration/__tests__/rpc.test.ts +0 -176
- package/src/configuration/explorer.ts +0 -243
- package/src/configuration/rpc.ts +0 -257
- package/src/mapping/__tests__/field-generator.test.ts +0 -137
- package/src/mapping/__tests__/type-mapper.test.ts +0 -139
- package/src/mapping/constants.ts +0 -57
- package/src/mapping/field-generator.ts +0 -115
- package/src/mapping/index.ts +0 -4
- package/src/mapping/type-mapper.ts +0 -80
- package/src/proxy/detection.ts +0 -465
- package/src/query/handler.ts +0 -227
- package/src/query/view-checker.ts +0 -10
- package/src/transaction/eoa.ts +0 -98
- package/src/transaction/execution-strategy.ts +0 -33
- package/src/transaction/formatter.ts +0 -101
- package/src/transaction/relayer.ts +0 -380
- package/src/transaction/sender.ts +0 -185
- package/src/transform/index.ts +0 -3
- package/src/transform/input-parser.ts +0 -177
- package/src/transform/output-formatter.ts +0 -64
- package/src/types/__tests__/artifacts.test.ts +0 -105
- package/src/types.ts +0 -92
- package/src/utils/__tests__/artifacts.test.ts +0 -81
- package/src/utils/artifacts.ts +0 -30
- package/src/utils/formatting.ts +0 -25
- package/src/utils/gas.ts +0 -17
- package/src/utils/index.ts +0 -6
- package/src/utils/json.ts +0 -19
- package/src/utils/validation.ts +0 -10
- package/src/validation/eoa.ts +0 -33
- package/src/validation/index.ts +0 -2
- package/src/validation/relayer.ts +0 -13
- package/src/wallet/__tests__/utils.test.ts +0 -149
- package/src/wallet/components/account/AccountDisplay.tsx +0 -52
- package/src/wallet/components/connect/ConnectButton.tsx +0 -125
- package/src/wallet/components/connect/ConnectorDialog.tsx +0 -140
- package/src/wallet/components/index.ts +0 -4
- package/src/wallet/components/network/NetworkSwitcher.tsx +0 -90
- package/src/wallet/context/index.ts +0 -1
- package/src/wallet/context/wagmi-context.tsx +0 -7
- package/src/wallet/hooks/useIsWagmiProviderInitialized.ts +0 -11
- package/src/wallet/rainbowkit/config-generator.ts +0 -56
- package/src/wallet/rainbowkit/config-service.ts +0 -169
- package/src/wallet/rainbowkit/export-service.ts +0 -18
- package/src/wallet/rainbowkit/rainbowkitAssetManager.ts +0 -74
- package/src/wallet/rainbowkit/types.ts +0 -74
- package/src/wallet/rainbowkit/utils.ts +0 -96
- package/src/wallet/services/configResolutionService.ts +0 -65
- package/src/wallet/utils/SafeWagmiComponent.tsx +0 -72
- package/src/wallet/utils/filterWalletComponents.ts +0 -89
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* EVM Adapter RainbowKit Component Factory
|
|
3
|
+
*
|
|
4
|
+
* Factory function for creating RainbowKit components.
|
|
5
|
+
* Separated from components.tsx to support React Fast Refresh.
|
|
6
|
+
*/
|
|
7
|
+
import { createRainbowKitComponents as coreCreateRainbowKitComponents } from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
2
8
|
|
|
3
9
|
import { RainbowKitConnectButton } from './components';
|
|
4
10
|
|
|
5
11
|
/**
|
|
6
|
-
* Creates the complete set of RainbowKit wallet components.
|
|
12
|
+
* Creates the complete set of RainbowKit wallet components for the EVM adapter.
|
|
7
13
|
*
|
|
8
14
|
* @returns An object containing all RainbowKit wallet components
|
|
9
15
|
*/
|
|
10
|
-
export function createRainbowKitComponents()
|
|
11
|
-
return
|
|
12
|
-
ConnectButton: RainbowKitConnectButton,
|
|
13
|
-
// RainbowKit's ConnectButton is comprehensive and typically includes account display
|
|
14
|
-
// So we don't provide separate AccountDisplay or NetworkSwitcher components
|
|
15
|
-
};
|
|
16
|
+
export function createRainbowKitComponents() {
|
|
17
|
+
return coreCreateRainbowKitComponents(RainbowKitConnectButton);
|
|
16
18
|
}
|
|
@@ -1,140 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* EVM Adapter RainbowKit Components
|
|
3
|
+
*
|
|
4
|
+
* This file exports only React components to support Fast Refresh.
|
|
5
|
+
* Factory functions are in componentFactory.ts.
|
|
6
|
+
*/
|
|
7
|
+
import { createRainbowKitConnectButton } from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
5
8
|
import type { BaseComponentProps } from '@openzeppelin/ui-types';
|
|
6
|
-
import { cn, logger } from '@openzeppelin/ui-utils';
|
|
7
9
|
|
|
8
|
-
import { CustomConnectButton } from '../components';
|
|
9
|
-
import { WagmiProviderInitializedContext } from '../context/wagmi-context';
|
|
10
10
|
import { evmUiKitManager } from '../evmUiKitManager';
|
|
11
|
-
import { extractRainbowKitCustomizations } from './types';
|
|
12
|
-
|
|
13
|
-
const MIN_COMPONENT_LOADING_DISPLAY_MS = 1000; // 1 second artificial delay
|
|
14
11
|
|
|
15
12
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @returns A React component that dynamically imports the RainbowKit ConnectButton
|
|
13
|
+
* Props for the RainbowKitConnectButton component.
|
|
19
14
|
*/
|
|
20
|
-
export
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
-
const [Component, setComponent] = useState<React.ComponentType<any> | null>(null);
|
|
23
|
-
const [error, setError] = useState<Error | null>(null);
|
|
24
|
-
const [isLoadingComponent, setIsLoadingComponent] = useState(true);
|
|
25
|
-
const [showComponentLoadingOverride, setShowComponentLoadingOverride] = useState(false);
|
|
26
|
-
const componentLoadingTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
27
|
-
const [managerState, setManagerState] = useState(evmUiKitManager.getState());
|
|
28
|
-
|
|
29
|
-
const isWagmiProviderReady = useContext(WagmiProviderInitializedContext);
|
|
30
|
-
|
|
31
|
-
// Subscribe to UI kit manager state changes
|
|
32
|
-
useEffect(() => {
|
|
33
|
-
const unsubscribe = evmUiKitManager.subscribe(() => {
|
|
34
|
-
setManagerState(evmUiKitManager.getState());
|
|
35
|
-
});
|
|
36
|
-
return unsubscribe;
|
|
37
|
-
}, []);
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
let isMounted = true;
|
|
41
|
-
setIsLoadingComponent(true);
|
|
42
|
-
setShowComponentLoadingOverride(true); // Start showing override immediately
|
|
43
|
-
|
|
44
|
-
if (componentLoadingTimerRef.current) {
|
|
45
|
-
clearTimeout(componentLoadingTimerRef.current);
|
|
46
|
-
}
|
|
47
|
-
componentLoadingTimerRef.current = setTimeout(() => {
|
|
48
|
-
if (isMounted) {
|
|
49
|
-
setShowComponentLoadingOverride(false);
|
|
50
|
-
}
|
|
51
|
-
componentLoadingTimerRef.current = null;
|
|
52
|
-
}, MIN_COMPONENT_LOADING_DISPLAY_MS);
|
|
53
|
-
|
|
54
|
-
const loadComponent = async () => {
|
|
55
|
-
try {
|
|
56
|
-
const rainbowKit = await import('@rainbow-me/rainbowkit');
|
|
57
|
-
if (isMounted) {
|
|
58
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
-
setComponent(() => rainbowKit.ConnectButton as React.ComponentType<any>);
|
|
60
|
-
// Actual component loading is done, but override might still be active
|
|
61
|
-
setIsLoadingComponent(false);
|
|
62
|
-
}
|
|
63
|
-
} catch (err) {
|
|
64
|
-
if (isMounted) {
|
|
65
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
66
|
-
setIsLoadingComponent(false); // Finished loading (with an error)
|
|
67
|
-
logger.error('RainbowKitConnectButton', 'Failed to load RainbowKit ConnectButton:', err);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
loadComponent();
|
|
15
|
+
export type RainbowKitConnectButtonProps = BaseComponentProps;
|
|
73
16
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const renderLoadingPlaceholder = (message: string) => (
|
|
83
|
-
<Button
|
|
84
|
-
disabled={true}
|
|
85
|
-
variant="outline"
|
|
86
|
-
size="sm"
|
|
87
|
-
className={cn('h-8 px-2 text-xs', props.className)}
|
|
88
|
-
>
|
|
89
|
-
<Loader2 className="h-3.5 w-3.5 animate-spin mr-1.5" />
|
|
90
|
-
{message}
|
|
91
|
-
</Button>
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
if (error) {
|
|
95
|
-
logger.warn(
|
|
96
|
-
'RainbowKitConnectButton',
|
|
97
|
-
'Error loading RainbowKit ConnectButton. Displaying fallback CustomConnectButton.'
|
|
98
|
-
);
|
|
99
|
-
return <CustomConnectButton {...props} />;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Show "Loading Wallet..." if component is still factually loading OR if the override is active
|
|
103
|
-
if (isLoadingComponent || showComponentLoadingOverride) {
|
|
104
|
-
return renderLoadingPlaceholder('Loading Wallet...');
|
|
105
|
-
}
|
|
106
|
-
// At this point, component import has finished (successfully or not handled by error state)
|
|
107
|
-
// AND the minimum display time for "Loading Wallet..." has passed.
|
|
108
|
-
|
|
109
|
-
// Now check if the provider context is ready
|
|
110
|
-
if (!isWagmiProviderReady) {
|
|
111
|
-
// No separate delay for this message; it appears if context isn't ready after component load delay.
|
|
112
|
-
return renderLoadingPlaceholder('Initializing Provider...');
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Component should be non-null here if no error and not isLoadingComponent
|
|
116
|
-
if (!Component) {
|
|
117
|
-
// This case should ideally not be hit if logic is correct, but as a safeguard:
|
|
118
|
-
logger.warn('RainbowKitConnectButton', 'Component is null after loading phase, falling back.');
|
|
119
|
-
return <CustomConnectButton {...props} />;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Extract custom configuration from the manager state
|
|
123
|
-
const kitConfig = managerState.currentFullUiKitConfig?.kitConfig;
|
|
124
|
-
const customizations = extractRainbowKitCustomizations(kitConfig);
|
|
125
|
-
const connectButtonConfig = customizations?.connectButton;
|
|
126
|
-
|
|
127
|
-
// Merge props: base props + custom configuration + any overrides from props
|
|
128
|
-
// This allows the config to set defaults while still allowing prop overrides
|
|
129
|
-
const finalProps = {
|
|
130
|
-
...connectButtonConfig, // Apply custom configuration from config
|
|
131
|
-
...props, // Allow props to override configuration
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
logger.debug('RainbowKitConnectButton', 'Rendering with configuration:', {
|
|
135
|
-
configFromFile: connectButtonConfig,
|
|
136
|
-
finalProps: finalProps,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
return <Component {...finalProps} />;
|
|
140
|
-
};
|
|
17
|
+
/**
|
|
18
|
+
* RainbowKitConnectButton component configured with the EVM UI kit manager.
|
|
19
|
+
* This component lazily loads the RainbowKit ConnectButton and manages
|
|
20
|
+
* its state through the evmUiKitManager.
|
|
21
|
+
*/
|
|
22
|
+
export const RainbowKitConnectButton: React.FC<RainbowKitConnectButtonProps> =
|
|
23
|
+
createRainbowKitConnectButton(evmUiKitManager);
|
|
@@ -1,5 +1,27 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// Re-export types from core
|
|
2
|
+
export type {
|
|
3
|
+
AppInfo,
|
|
4
|
+
RainbowKitConnectButtonProps,
|
|
5
|
+
RainbowKitProviderProps,
|
|
6
|
+
RainbowKitKitConfig,
|
|
7
|
+
RainbowKitCustomizations,
|
|
8
|
+
} from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
isRainbowKitCustomizations,
|
|
12
|
+
extractRainbowKitCustomizations,
|
|
13
|
+
validateRainbowKitConfig,
|
|
14
|
+
getRawUserNativeConfig,
|
|
15
|
+
} from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
16
|
+
|
|
17
|
+
// EVM-specific components
|
|
18
|
+
export { RainbowKitConnectButton } from './components';
|
|
19
|
+
|
|
20
|
+
// EVM-specific factory functions
|
|
21
|
+
export { createRainbowKitComponents } from './componentFactory';
|
|
22
|
+
|
|
23
|
+
// Re-export config service from core for convenience
|
|
24
|
+
export {
|
|
25
|
+
createRainbowKitWagmiConfig,
|
|
26
|
+
getWagmiConfigForRainbowKit,
|
|
27
|
+
} from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
CustomAccountDisplay,
|
|
5
|
+
CustomConnectButton,
|
|
6
|
+
CustomNetworkSwitcher,
|
|
7
|
+
} from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
3
8
|
import type { ComponentExclusionConfig, UiKitConfiguration } from '@openzeppelin/ui-types';
|
|
4
9
|
import { logger } from '@openzeppelin/ui-utils';
|
|
5
10
|
|
|
6
|
-
import { CustomAccountDisplay, CustomConnectButton, CustomNetworkSwitcher } from '../../components';
|
|
7
11
|
import { getResolvedWalletComponents } from '../uiKitService';
|
|
8
12
|
|
|
9
13
|
// Mock the logger
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { GetAccountReturnType } from '@wagmi/core';
|
|
2
2
|
|
|
3
|
+
import {
|
|
4
|
+
connectAndEnsureCorrectNetworkCore,
|
|
5
|
+
DEFAULT_DISCONNECTED_STATUS,
|
|
6
|
+
type EvmWalletConnectionResult,
|
|
7
|
+
} from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
3
8
|
import type { Connector } from '@openzeppelin/ui-types';
|
|
4
9
|
import { logger } from '@openzeppelin/ui-utils';
|
|
5
10
|
|
|
@@ -41,52 +46,14 @@ export async function getEvmAvailableConnectors(): Promise<Connector[]> {
|
|
|
41
46
|
export async function connectAndEnsureCorrectNetwork(
|
|
42
47
|
connectorId: string,
|
|
43
48
|
targetChainId: number
|
|
44
|
-
): Promise<
|
|
49
|
+
): Promise<EvmWalletConnectionResult> {
|
|
45
50
|
const impl = await getEvmWalletImplementation();
|
|
46
51
|
if (!impl) {
|
|
47
52
|
logger.error(LOG_SYSTEM, 'connectAndEnsureCorrectNetwork: Wallet implementation not ready.');
|
|
48
53
|
return { connected: false, error: 'Wallet system not initialized.' };
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
if (!connectionResult.connected || !connectionResult.address || !connectionResult.chainId) {
|
|
53
|
-
return { connected: false, error: connectionResult.error || 'Connection failed' };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (connectionResult.chainId !== targetChainId) {
|
|
57
|
-
logger.info(
|
|
58
|
-
LOG_SYSTEM,
|
|
59
|
-
`Connected to chain ${connectionResult.chainId}, but target is ${targetChainId}. Attempting switch.`
|
|
60
|
-
);
|
|
61
|
-
try {
|
|
62
|
-
await impl.switchNetwork(targetChainId);
|
|
63
|
-
const postSwitchStatus = impl.getWalletConnectionStatus();
|
|
64
|
-
if (postSwitchStatus.chainId !== targetChainId) {
|
|
65
|
-
const switchError = `Failed to switch to target network ${targetChainId}. Current: ${postSwitchStatus.chainId}`;
|
|
66
|
-
logger.error(LOG_SYSTEM, switchError);
|
|
67
|
-
// Attempt to disconnect to leave a clean state if switch fails
|
|
68
|
-
try {
|
|
69
|
-
await impl.disconnect();
|
|
70
|
-
} catch (e) {
|
|
71
|
-
logger.warn(LOG_SYSTEM, 'Failed to disconnect after network switch failure.', e);
|
|
72
|
-
}
|
|
73
|
-
return { connected: false, error: switchError };
|
|
74
|
-
}
|
|
75
|
-
logger.info(LOG_SYSTEM, `Successfully switched to target chain ${targetChainId}.`);
|
|
76
|
-
return { ...connectionResult, chainId: postSwitchStatus.chainId }; // Return updated chainId
|
|
77
|
-
} catch (error) {
|
|
78
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
79
|
-
logger.error(LOG_SYSTEM, 'Network switch failed:', errorMessage);
|
|
80
|
-
// Attempt to disconnect to leave a clean state if switch fails
|
|
81
|
-
try {
|
|
82
|
-
await impl.disconnect();
|
|
83
|
-
} catch (e) {
|
|
84
|
-
logger.warn(LOG_SYSTEM, 'Failed to disconnect after network switch failure.', e);
|
|
85
|
-
}
|
|
86
|
-
return { connected: false, error: `Network switch failed: ${errorMessage}` };
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return connectionResult;
|
|
56
|
+
return connectAndEnsureCorrectNetworkCore(impl, connectorId, targetChainId, LOG_SYSTEM);
|
|
90
57
|
}
|
|
91
58
|
|
|
92
59
|
/**
|
|
@@ -117,18 +84,7 @@ export function getEvmWalletConnectionStatus(): GetAccountReturnType {
|
|
|
117
84
|
LOG_SYSTEM,
|
|
118
85
|
'getEvmWalletConnectionStatus: Wallet implementation not ready. Returning default disconnected state.'
|
|
119
86
|
);
|
|
120
|
-
return
|
|
121
|
-
isConnected: false,
|
|
122
|
-
isConnecting: false,
|
|
123
|
-
isDisconnected: true,
|
|
124
|
-
isReconnecting: false,
|
|
125
|
-
status: 'disconnected',
|
|
126
|
-
address: undefined,
|
|
127
|
-
addresses: undefined,
|
|
128
|
-
chainId: undefined,
|
|
129
|
-
chain: undefined,
|
|
130
|
-
connector: undefined,
|
|
131
|
-
};
|
|
87
|
+
return DEFAULT_DISCONNECTED_STATUS;
|
|
132
88
|
}
|
|
133
89
|
return impl.getWalletConnectionStatus();
|
|
134
90
|
}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CustomAccountDisplay,
|
|
3
|
+
CustomConnectButton,
|
|
4
|
+
CustomNetworkSwitcher,
|
|
5
|
+
filterWalletComponents,
|
|
6
|
+
getComponentExclusionsFromConfig,
|
|
7
|
+
} from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
1
8
|
import type { EcosystemWalletComponents, UiKitConfiguration } from '@openzeppelin/ui-types';
|
|
2
9
|
import { logger } from '@openzeppelin/ui-utils';
|
|
3
10
|
|
|
4
|
-
import { CustomAccountDisplay, CustomConnectButton, CustomNetworkSwitcher } from '../components';
|
|
5
11
|
import { createRainbowKitComponents, validateRainbowKitConfig } from '../rainbowkit';
|
|
6
|
-
// Assuming this is the default custom provider
|
|
7
|
-
import { filterWalletComponents, getComponentExclusionsFromConfig } from './filterWalletComponents';
|
|
8
12
|
|
|
9
13
|
/** Service for resolving UI kit specific components and providers for the EVM adapter. */
|
|
10
14
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { WagmiWalletImplementation } from '@openzeppelin/ui-builder-adapter-evm-core';
|
|
1
2
|
import type { UiKitConfiguration } from '@openzeppelin/ui-types';
|
|
2
3
|
import { appConfigService, logger } from '@openzeppelin/ui-utils';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { createEvmWalletImplementation } from '../implementation/wagmi-implementation';
|
|
5
6
|
|
|
6
7
|
let walletImplementationInstance: WagmiWalletImplementation | undefined;
|
|
7
8
|
let walletImplementationPromise: Promise<WagmiWalletImplementation> | undefined;
|
|
@@ -37,14 +38,14 @@ export async function getEvmWalletImplementation(): Promise<WagmiWalletImplement
|
|
|
37
38
|
| string
|
|
38
39
|
| undefined;
|
|
39
40
|
|
|
40
|
-
//
|
|
41
|
-
const instance =
|
|
41
|
+
// Use factory function for proper EVM configuration
|
|
42
|
+
const instance = createEvmWalletImplementation(wcProjectId, initialUiKitConfig);
|
|
42
43
|
logger.info(LOG_SYSTEM, 'WagmiWalletImplementation singleton created (async).');
|
|
43
44
|
walletImplementationInstance = instance;
|
|
44
45
|
return instance;
|
|
45
46
|
} catch (error) {
|
|
46
47
|
logger.error(LOG_SYSTEM, 'Failed to initialize WagmiWalletImplementation (async):', error);
|
|
47
|
-
const fallbackInstance =
|
|
48
|
+
const fallbackInstance = createEvmWalletImplementation();
|
|
48
49
|
walletImplementationInstance = fallbackInstance;
|
|
49
50
|
return fallbackInstance;
|
|
50
51
|
}
|
package/src/wallet/utils.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
EcosystemWalletComponents,
|
|
3
|
-
NativeConfigLoader,
|
|
4
|
-
UiKitConfiguration,
|
|
5
|
-
} from '@openzeppelin/ui-types';
|
|
6
|
-
import { logger } from '@openzeppelin/ui-utils';
|
|
1
|
+
import type { EcosystemWalletComponents, UiKitConfiguration } from '@openzeppelin/ui-types';
|
|
7
2
|
|
|
8
3
|
// Import the actual service functions instead of using placeholders
|
|
9
4
|
import { getResolvedWalletComponents as getWalletComponentsFromService } from './utils/uiKitService';
|
|
@@ -14,62 +9,3 @@ export function getResolvedWalletComponents(
|
|
|
14
9
|
): EcosystemWalletComponents | undefined {
|
|
15
10
|
return getWalletComponentsFromService(uiKitConfig);
|
|
16
11
|
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Resolves and initializes the kit-specific configuration.
|
|
20
|
-
* This function acts as a manager to call the appropriate kit's configuration initializer.
|
|
21
|
-
*
|
|
22
|
-
* @param kitName The name of the UI kit (e.g., 'rainbowkit').
|
|
23
|
-
* @param programmaticKitConfig Optional base/programmatic config passed to the kit initializer.
|
|
24
|
-
* @param loadConfigModule Optional generic callback to load configuration modules by path.
|
|
25
|
-
* @returns A Promise resolving to the final kitConfig (Record<string, unknown>) for the specified kit, or null.
|
|
26
|
-
*/
|
|
27
|
-
export async function resolveAndInitializeKitConfig(
|
|
28
|
-
kitName?: string, // kitName is used to construct the path to the conventional config file
|
|
29
|
-
programmaticKitConfig?: Record<string, unknown>,
|
|
30
|
-
loadConfigModule?: NativeConfigLoader
|
|
31
|
-
): Promise<Record<string, unknown> | null> {
|
|
32
|
-
logger.debug(
|
|
33
|
-
'resolveAndInitializeKitConfig',
|
|
34
|
-
`Resolving native config for kit: ${kitName || 'none'}`,
|
|
35
|
-
{
|
|
36
|
-
hasProgrammaticKitConfig: !!programmaticKitConfig,
|
|
37
|
-
hasLoadConfigModule: !!loadConfigModule,
|
|
38
|
-
}
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
let userNativeConfig: Record<string, unknown> | null = null;
|
|
42
|
-
|
|
43
|
-
// Only attempt to load a native config if a kitName is provided and a loader function exists.
|
|
44
|
-
// And the kitName is not 'custom' or 'none' as those typically don't have dedicated native config files.
|
|
45
|
-
if (kitName && kitName !== 'custom' && kitName !== 'none' && loadConfigModule) {
|
|
46
|
-
const conventionalConfigPath = `./config/wallet/${kitName}.config.ts`;
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
userNativeConfig = await loadConfigModule(conventionalConfigPath);
|
|
50
|
-
} catch (error) {
|
|
51
|
-
logger.warn(
|
|
52
|
-
'resolveAndInitializeKitConfig',
|
|
53
|
-
`Call to load native config for ${kitName} from ${conventionalConfigPath} failed. Error:`,
|
|
54
|
-
error
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Merge the loaded user native config with the programmatically passed kitConfig.
|
|
60
|
-
// Programmatic config can override or augment the native file's settings.
|
|
61
|
-
if (userNativeConfig && programmaticKitConfig) {
|
|
62
|
-
const mergedConfig = { ...userNativeConfig, ...programmaticKitConfig };
|
|
63
|
-
return mergedConfig;
|
|
64
|
-
} else if (userNativeConfig) {
|
|
65
|
-
return userNativeConfig;
|
|
66
|
-
} else if (programmaticKitConfig) {
|
|
67
|
-
return programmaticKitConfig;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
logger.debug(
|
|
71
|
-
'resolveAndInitializeKitConfig',
|
|
72
|
-
`No native or programmatic kitConfig provided for ${kitName || 'none'}. Returning null.`
|
|
73
|
-
);
|
|
74
|
-
return null;
|
|
75
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
|
|
3
|
-
import { TypedEvmNetworkConfig } from '../../types';
|
|
4
|
-
import { shouldUseV2Api, testEtherscanV2Connection } from '../etherscan-v2';
|
|
5
|
-
|
|
6
|
-
// Mock the dependencies
|
|
7
|
-
vi.mock('../../configuration/explorer', () => ({
|
|
8
|
-
resolveExplorerConfig: vi.fn(),
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
vi.mock('@openzeppelin/ui-utils', () => ({
|
|
12
|
-
logger: {
|
|
13
|
-
info: vi.fn(),
|
|
14
|
-
error: vi.fn(),
|
|
15
|
-
warn: vi.fn(),
|
|
16
|
-
},
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
// Mock global fetch
|
|
20
|
-
global.fetch = vi.fn();
|
|
21
|
-
|
|
22
|
-
describe('Etherscan V2 API', () => {
|
|
23
|
-
const mockNetworkConfig: TypedEvmNetworkConfig = {
|
|
24
|
-
id: 'ethereum-mainnet',
|
|
25
|
-
name: 'Ethereum Mainnet',
|
|
26
|
-
ecosystem: 'evm',
|
|
27
|
-
network: 'ethereum',
|
|
28
|
-
type: 'mainnet',
|
|
29
|
-
isTestnet: false,
|
|
30
|
-
chainId: 1,
|
|
31
|
-
rpcUrl: 'https://mainnet.infura.io/v3/test',
|
|
32
|
-
explorerUrl: 'https://etherscan.io',
|
|
33
|
-
supportsEtherscanV2: true,
|
|
34
|
-
exportConstName: 'ethereumMainnet',
|
|
35
|
-
nativeCurrency: {
|
|
36
|
-
name: 'Ether',
|
|
37
|
-
symbol: 'ETH',
|
|
38
|
-
decimals: 18,
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
beforeEach(() => {
|
|
43
|
-
vi.clearAllMocks();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
describe('shouldUseV2Api', () => {
|
|
47
|
-
it('should return true if network supports V2 and no user config', () => {
|
|
48
|
-
expect(shouldUseV2Api(mockNetworkConfig)).toBe(true);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should return true for networks that support V2 API', () => {
|
|
52
|
-
expect(shouldUseV2Api(mockNetworkConfig)).toBe(true);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should return false for networks without V2 support even with user preference', () => {
|
|
56
|
-
const networkWithoutV2 = { ...mockNetworkConfig, supportsEtherscanV2: false };
|
|
57
|
-
expect(shouldUseV2Api(networkWithoutV2)).toBe(false);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
describe('testEtherscanV2Connection', () => {
|
|
62
|
-
it('should allow testing connection without API key when network does not require it', async () => {
|
|
63
|
-
const networkWithoutKeyRequired: TypedEvmNetworkConfig = {
|
|
64
|
-
...mockNetworkConfig,
|
|
65
|
-
requiresExplorerApiKey: false,
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const mockResponse = {
|
|
69
|
-
status: '1',
|
|
70
|
-
result: '0x1234567',
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
vi.mocked(global.fetch).mockResolvedValueOnce({
|
|
74
|
-
ok: true,
|
|
75
|
-
json: vi.fn().mockResolvedValueOnce(mockResponse),
|
|
76
|
-
} as unknown as Response);
|
|
77
|
-
|
|
78
|
-
const result = await testEtherscanV2Connection(networkWithoutKeyRequired);
|
|
79
|
-
|
|
80
|
-
expect(result.success).toBe(true);
|
|
81
|
-
expect(result.latency).toBeDefined();
|
|
82
|
-
expect(result.error).toBeUndefined();
|
|
83
|
-
|
|
84
|
-
// Verify API call was made without API key
|
|
85
|
-
const fetchCall = vi.mocked(global.fetch).mock.calls[0][0] as string;
|
|
86
|
-
expect(fetchCall).not.toContain('apikey=');
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('should require API key for testing when network requires it', async () => {
|
|
90
|
-
const result = await testEtherscanV2Connection(mockNetworkConfig);
|
|
91
|
-
|
|
92
|
-
expect(result.success).toBe(false);
|
|
93
|
-
expect(result.error).toBe('API key is required for testing connection to this explorer');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should test with API key when provided', async () => {
|
|
97
|
-
const mockResponse = {
|
|
98
|
-
status: '1',
|
|
99
|
-
result: '0x1234567',
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
vi.mocked(global.fetch).mockResolvedValueOnce({
|
|
103
|
-
ok: true,
|
|
104
|
-
json: vi.fn().mockResolvedValueOnce(mockResponse),
|
|
105
|
-
} as unknown as Response);
|
|
106
|
-
|
|
107
|
-
const result = await testEtherscanV2Connection(mockNetworkConfig, 'test-api-key');
|
|
108
|
-
|
|
109
|
-
expect(result.success).toBe(true);
|
|
110
|
-
expect(result.latency).toBeDefined();
|
|
111
|
-
|
|
112
|
-
// Verify API call was made with API key
|
|
113
|
-
const fetchCall = vi.mocked(global.fetch).mock.calls[0][0] as string;
|
|
114
|
-
expect(fetchCall).toContain('apikey=test-api-key');
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
});
|