@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.
Files changed (105) hide show
  1. package/README.md +33 -18
  2. package/dist/index.cjs +4651 -4448
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +12 -226
  5. package/dist/index.d.ts +12 -226
  6. package/dist/index.js +4737 -4535
  7. package/dist/index.js.map +1 -1
  8. package/package.json +7 -6
  9. package/src/__tests__/adapter-parsing.test.ts +4 -3
  10. package/src/__tests__/getDefaultServiceConfig.test.ts +185 -0
  11. package/src/__tests__/mocks/mock-network-configs.ts +1 -1
  12. package/src/__tests__/provenanceLinks.test.ts +6 -4
  13. package/src/__tests__/providerSelection.test.ts +5 -4
  14. package/src/__tests__/timeouts.test.ts +5 -3
  15. package/src/__tests__/wallet-connect.test.ts +2 -2
  16. package/src/adapter.ts +61 -107
  17. package/src/configuration/execution.ts +1 -52
  18. package/src/configuration/index.ts +2 -3
  19. package/src/configuration/network-services.ts +47 -60
  20. package/src/index.ts +22 -13
  21. package/src/networks/index.ts +2 -1
  22. package/src/networks/mainnet.ts +1 -1
  23. package/src/networks/testnet.ts +1 -1
  24. package/src/query/adapter-query.ts +72 -0
  25. package/src/query/index.ts +2 -2
  26. package/src/transaction/components/useEvmRelayerOptions.ts +5 -3
  27. package/src/transaction/index.ts +1 -5
  28. package/src/types/artifacts.ts +5 -30
  29. package/src/types/providers.ts +7 -18
  30. package/src/wallet/components/EvmWalletUiRoot.tsx +1 -1
  31. package/src/wallet/evmUiKitManager.ts +26 -129
  32. package/src/wallet/hooks/index.ts +0 -1
  33. package/src/wallet/implementation/wagmi-implementation.ts +45 -577
  34. package/src/wallet/index.ts +2 -3
  35. package/src/wallet/rainbowkit/__tests__/export-service.test.ts +1 -2
  36. package/src/wallet/rainbowkit/componentFactory.ts +10 -8
  37. package/src/wallet/rainbowkit/components.tsx +16 -133
  38. package/src/wallet/rainbowkit/index.ts +27 -5
  39. package/src/wallet/utils/__tests__/uiKitService.test.ts +5 -1
  40. package/src/wallet/utils/connection.ts +8 -52
  41. package/src/wallet/utils/index.ts +0 -2
  42. package/src/wallet/utils/uiKitService.ts +7 -3
  43. package/src/wallet/utils/walletImplementationManager.ts +5 -4
  44. package/src/wallet/utils.ts +1 -65
  45. package/src/abi/__tests__/etherscan-v2.test.ts +0 -117
  46. package/src/abi/__tests__/transformer.test.ts +0 -342
  47. package/src/abi/comparison.ts +0 -389
  48. package/src/abi/etherscan-v2.ts +0 -243
  49. package/src/abi/etherscan.ts +0 -158
  50. package/src/abi/index.ts +0 -7
  51. package/src/abi/loader.ts +0 -415
  52. package/src/abi/sourcify.ts +0 -75
  53. package/src/abi/transformer.ts +0 -163
  54. package/src/abi/types.ts +0 -101
  55. package/src/configuration/__tests__/explorer.test.ts +0 -174
  56. package/src/configuration/__tests__/rpc.test.ts +0 -176
  57. package/src/configuration/explorer.ts +0 -243
  58. package/src/configuration/rpc.ts +0 -257
  59. package/src/mapping/__tests__/field-generator.test.ts +0 -137
  60. package/src/mapping/__tests__/type-mapper.test.ts +0 -139
  61. package/src/mapping/constants.ts +0 -57
  62. package/src/mapping/field-generator.ts +0 -115
  63. package/src/mapping/index.ts +0 -4
  64. package/src/mapping/type-mapper.ts +0 -80
  65. package/src/proxy/detection.ts +0 -465
  66. package/src/query/handler.ts +0 -227
  67. package/src/query/view-checker.ts +0 -10
  68. package/src/transaction/eoa.ts +0 -98
  69. package/src/transaction/execution-strategy.ts +0 -33
  70. package/src/transaction/formatter.ts +0 -101
  71. package/src/transaction/relayer.ts +0 -380
  72. package/src/transaction/sender.ts +0 -185
  73. package/src/transform/index.ts +0 -3
  74. package/src/transform/input-parser.ts +0 -177
  75. package/src/transform/output-formatter.ts +0 -64
  76. package/src/types/__tests__/artifacts.test.ts +0 -105
  77. package/src/types.ts +0 -92
  78. package/src/utils/__tests__/artifacts.test.ts +0 -81
  79. package/src/utils/artifacts.ts +0 -30
  80. package/src/utils/formatting.ts +0 -25
  81. package/src/utils/gas.ts +0 -17
  82. package/src/utils/index.ts +0 -6
  83. package/src/utils/json.ts +0 -19
  84. package/src/utils/validation.ts +0 -10
  85. package/src/validation/eoa.ts +0 -33
  86. package/src/validation/index.ts +0 -2
  87. package/src/validation/relayer.ts +0 -13
  88. package/src/wallet/__tests__/utils.test.ts +0 -149
  89. package/src/wallet/components/account/AccountDisplay.tsx +0 -52
  90. package/src/wallet/components/connect/ConnectButton.tsx +0 -125
  91. package/src/wallet/components/connect/ConnectorDialog.tsx +0 -140
  92. package/src/wallet/components/index.ts +0 -4
  93. package/src/wallet/components/network/NetworkSwitcher.tsx +0 -90
  94. package/src/wallet/context/index.ts +0 -1
  95. package/src/wallet/context/wagmi-context.tsx +0 -7
  96. package/src/wallet/hooks/useIsWagmiProviderInitialized.ts +0 -11
  97. package/src/wallet/rainbowkit/config-generator.ts +0 -56
  98. package/src/wallet/rainbowkit/config-service.ts +0 -169
  99. package/src/wallet/rainbowkit/export-service.ts +0 -18
  100. package/src/wallet/rainbowkit/rainbowkitAssetManager.ts +0 -74
  101. package/src/wallet/rainbowkit/types.ts +0 -74
  102. package/src/wallet/rainbowkit/utils.ts +0 -96
  103. package/src/wallet/services/configResolutionService.ts +0 -65
  104. package/src/wallet/utils/SafeWagmiComponent.tsx +0 -72
  105. package/src/wallet/utils/filterWalletComponents.ts +0 -89
@@ -1,243 +0,0 @@
1
- import { NetworkConfig, UserExplorerConfig } from '@openzeppelin/ui-types';
2
- import { appConfigService, logger, userNetworkServiceConfigService } from '@openzeppelin/ui-utils';
3
-
4
- import { shouldUseV2Api, testEtherscanV2Connection } from '../abi/etherscan-v2';
5
- import { TypedEvmNetworkConfig } from '../types';
6
- import { isValidEvmAddress } from '../utils';
7
-
8
- /**
9
- * Resolves the explorer configuration for a given EVM network.
10
- * Priority order:
11
- * 1. User-configured explorer (from UserExplorerConfigService)
12
- * 2. For V2 API networks: Global Etherscan V2 API key (from AppConfigService global service configs)
13
- * 3. App-configured explorer API key (from AppConfigService network service configs)
14
- * 4. Default network explorer (from NetworkConfig)
15
- *
16
- * @param networkConfig - The EVM network configuration.
17
- * @returns The resolved explorer configuration.
18
- */
19
- export function resolveExplorerConfig(networkConfig: TypedEvmNetworkConfig): UserExplorerConfig {
20
- // Precompute app-level keys and defaults for merging
21
- const isV2 =
22
- networkConfig.supportsEtherscanV2 &&
23
- networkConfig.primaryExplorerApiIdentifier === 'etherscan-v2';
24
- const globalV2ApiKey = isV2
25
- ? (appConfigService.getGlobalServiceConfig('etherscanv2')?.apiKey as string | undefined)
26
- : undefined;
27
- const appApiKey = networkConfig.primaryExplorerApiIdentifier
28
- ? appConfigService.getExplorerApiKey(networkConfig.primaryExplorerApiIdentifier)
29
- : undefined;
30
-
31
- // 1. Check for user-configured explorer via new generic service
32
- const rawCfg = userNetworkServiceConfigService.get(networkConfig.id, 'explorer');
33
- if (rawCfg && typeof rawCfg === 'object') {
34
- const userCfg = rawCfg as Record<string, unknown>;
35
- logger.info('ExplorerConfig', `Using user-configured explorer for ${networkConfig.name}`);
36
- return {
37
- explorerUrl: (userCfg.explorerUrl as string | undefined) ?? networkConfig.explorerUrl,
38
- apiUrl: (userCfg.apiUrl as string | undefined) ?? networkConfig.apiUrl,
39
- apiKey: (userCfg.apiKey as string | undefined) ?? globalV2ApiKey ?? appApiKey,
40
- name: `${networkConfig.name} Explorer`,
41
- isCustom: true,
42
- };
43
- }
44
-
45
- // 2. For V2 API networks using 'etherscan-v2' identifier, check for global Etherscan V2 API key
46
- if (isV2 && globalV2ApiKey) {
47
- logger.info('ExplorerConfig', `Using global Etherscan V2 API key for ${networkConfig.name}`);
48
- return {
49
- explorerUrl: networkConfig.explorerUrl,
50
- apiUrl: networkConfig.apiUrl,
51
- apiKey: globalV2ApiKey,
52
- name: `${networkConfig.name} Explorer (V2 API)`,
53
- isCustom: false,
54
- };
55
- }
56
-
57
- // 3. Check for app-configured API key (V1 style or other identifiers)
58
- if (appApiKey) {
59
- logger.info('ExplorerConfig', `Using app-configured API key for ${networkConfig.name}`);
60
- return {
61
- explorerUrl: networkConfig.explorerUrl,
62
- apiUrl: networkConfig.apiUrl,
63
- apiKey: appApiKey,
64
- name: `${networkConfig.name} Explorer`,
65
- isCustom: false,
66
- };
67
- }
68
-
69
- // 4. Use default network explorer (no API key)
70
- logger.info(
71
- 'ExplorerConfig',
72
- `Using default explorer for ${networkConfig.name} (no API key configured)`
73
- );
74
- return {
75
- explorerUrl: networkConfig.explorerUrl,
76
- apiUrl: networkConfig.apiUrl,
77
- name: `${networkConfig.name} Explorer`,
78
- isCustom: false,
79
- };
80
- }
81
-
82
- /**
83
- * Gets a blockchain explorer URL for an EVM address.
84
- * Uses the resolved explorer configuration.
85
- */
86
- export function getEvmExplorerAddressUrl(
87
- address: string,
88
- networkConfig: NetworkConfig
89
- ): string | null {
90
- if (!isValidEvmAddress(address)) {
91
- return null;
92
- }
93
-
94
- const explorerConfig = resolveExplorerConfig(networkConfig as TypedEvmNetworkConfig);
95
- if (!explorerConfig.explorerUrl) {
96
- return null;
97
- }
98
-
99
- // Construct the URL using the explorerUrl from the config
100
- const baseUrl = explorerConfig.explorerUrl.replace(/\/+$/, '');
101
- return `${baseUrl}/address/${address}`;
102
- }
103
-
104
- /**
105
- * Gets a blockchain explorer URL for an EVM transaction.
106
- * Uses the resolved explorer configuration.
107
- */
108
- export function getEvmExplorerTxUrl(txHash: string, networkConfig: NetworkConfig): string | null {
109
- if (!txHash) {
110
- return null;
111
- }
112
-
113
- const explorerConfig = resolveExplorerConfig(networkConfig as TypedEvmNetworkConfig);
114
- if (!explorerConfig.explorerUrl) {
115
- return null;
116
- }
117
-
118
- // Construct the URL using the explorerUrl from the config
119
- const baseUrl = explorerConfig.explorerUrl.replace(/\/+$/, '');
120
- return `${baseUrl}/tx/${txHash}`;
121
- }
122
-
123
- /**
124
- * Validates an EVM explorer configuration.
125
- * Checks URL formats and API key format.
126
- */
127
- export function validateEvmExplorerConfig(explorerConfig: UserExplorerConfig): boolean {
128
- // Validate URLs if provided
129
- if (explorerConfig.explorerUrl) {
130
- try {
131
- new URL(explorerConfig.explorerUrl);
132
- } catch {
133
- return false;
134
- }
135
- }
136
-
137
- if (explorerConfig.apiUrl) {
138
- try {
139
- new URL(explorerConfig.apiUrl);
140
- } catch {
141
- return false;
142
- }
143
- }
144
-
145
- // Basic API key validation (not empty)
146
- if (explorerConfig.apiKey !== undefined && explorerConfig.apiKey.trim().length === 0) {
147
- return false;
148
- }
149
-
150
- return true;
151
- }
152
-
153
- /**
154
- * Tests the connection to an EVM explorer API.
155
- * Makes a test API call to verify the API key works.
156
- */
157
- export async function testEvmExplorerConnection(
158
- explorerConfig: UserExplorerConfig,
159
- networkConfig?: TypedEvmNetworkConfig
160
- ): Promise<{
161
- success: boolean;
162
- latency?: number;
163
- error?: string;
164
- }> {
165
- // Check if API key is required for this network
166
- const requiresApiKey =
167
- networkConfig && 'requiresExplorerApiKey' in networkConfig
168
- ? networkConfig.requiresExplorerApiKey !== false
169
- : true;
170
-
171
- if (requiresApiKey && !explorerConfig.apiKey) {
172
- return {
173
- success: false,
174
- error: 'API key is required for testing connection to this explorer',
175
- };
176
- }
177
-
178
- // Check if we should use V2 API
179
- if (networkConfig && shouldUseV2Api(networkConfig)) {
180
- return testEtherscanV2Connection(networkConfig, explorerConfig.apiKey);
181
- }
182
-
183
- // Use V1 API (legacy)
184
- // Use provided API URL or fall back to network config if available
185
- let apiUrl = explorerConfig.apiUrl;
186
- if (!apiUrl && networkConfig?.apiUrl) {
187
- apiUrl = networkConfig.apiUrl;
188
- }
189
-
190
- if (!apiUrl) {
191
- return {
192
- success: false,
193
- error:
194
- 'API URL is required for testing connection. Please provide an API URL or ensure the network has a default API URL configured.',
195
- };
196
- }
197
-
198
- const startTime = Date.now();
199
-
200
- try {
201
- // Test with a simple API call - get the latest block number
202
- const url = new URL(apiUrl);
203
- url.searchParams.append('module', 'proxy');
204
- url.searchParams.append('action', 'eth_blockNumber');
205
- if (explorerConfig.apiKey) {
206
- url.searchParams.append('apikey', explorerConfig.apiKey);
207
- }
208
-
209
- const response = await fetch(url.toString());
210
- const latency = Date.now() - startTime;
211
-
212
- if (!response.ok) {
213
- return {
214
- success: false,
215
- error: `HTTP ${response.status}: ${response.statusText}`,
216
- latency,
217
- };
218
- }
219
-
220
- const data = await response.json();
221
-
222
- // Check for API errors in the response
223
- if (data.status === '0' && data.message) {
224
- return {
225
- success: false,
226
- error: data.message,
227
- latency,
228
- };
229
- }
230
-
231
- // Success if we got a valid response
232
- return {
233
- success: true,
234
- latency,
235
- };
236
- } catch (error) {
237
- return {
238
- success: false,
239
- error: error instanceof Error ? error.message : 'Connection test failed',
240
- latency: Date.now() - startTime,
241
- };
242
- }
243
- }
@@ -1,257 +0,0 @@
1
- import type { EvmNetworkConfig, UserRpcProviderConfig } from '@openzeppelin/ui-types';
2
- import {
3
- appConfigService,
4
- isValidUrl,
5
- logger,
6
- userNetworkServiceConfigService,
7
- } from '@openzeppelin/ui-utils';
8
-
9
- /**
10
- * Builds a complete RPC URL from a user RPC provider configuration.
11
- * For simplified RPC configuration, this just returns the URL as-is since
12
- * users are now providing complete RPC URLs including any API keys.
13
- *
14
- * @param config The user RPC provider configuration
15
- * @returns The RPC URL
16
- */
17
- export function buildRpcUrl(config: UserRpcProviderConfig): string {
18
- return config.url;
19
- }
20
-
21
- /**
22
- * Extracts the user-configured RPC URL from UserNetworkServiceConfigService.
23
- *
24
- * @param networkId - The network ID to get the RPC URL for
25
- * @returns The RPC URL string if configured, undefined otherwise
26
- */
27
- export function getUserRpcUrl(networkId: string): string | undefined {
28
- const svcCfg = userNetworkServiceConfigService.get(networkId, 'rpc');
29
- if (svcCfg && typeof svcCfg === 'object' && 'rpcUrl' in svcCfg) {
30
- return (svcCfg as Record<string, unknown>).rpcUrl as string;
31
- }
32
- return undefined;
33
- }
34
-
35
- /**
36
- * Resolves the RPC URL for a given EVM network configuration.
37
- * Priority order:
38
- * 1. User-provided RPC configuration (from UserRpcConfigService)
39
- * 2. RPC URL override from AppConfigService
40
- * 3. Default rpcUrl from the network configuration
41
- *
42
- * @param networkConfig - The EVM network configuration.
43
- * @returns The resolved RPC URL string.
44
- * @throws If no RPC URL can be resolved (neither user config, override, nor default is present and valid).
45
- */
46
- export function resolveRpcUrl(networkConfig: EvmNetworkConfig): string {
47
- const logSystem = 'RpcResolver';
48
- const networkId = networkConfig.id;
49
-
50
- // First priority: Check adapter-led service config (generic)
51
- const userRpcUrl = getUserRpcUrl(networkId);
52
- if (userRpcUrl) {
53
- const userRpcUrlString = String(userRpcUrl);
54
- if (isValidUrl(userRpcUrlString)) {
55
- logger.info(logSystem, `Using user-configured RPC URL for network ${networkId}`);
56
- return userRpcUrlString;
57
- } else {
58
- logger.warn(
59
- logSystem,
60
- `User-configured RPC URL for ${networkId} is invalid: ${userRpcUrlString}. Falling back.`
61
- );
62
- }
63
- }
64
-
65
- // Second priority: Check AppConfigService for an override
66
- const rpcOverrideSetting = appConfigService.getRpcEndpointOverride(networkId);
67
- let rpcUrlFromOverride: string | undefined;
68
-
69
- if (typeof rpcOverrideSetting === 'string') {
70
- rpcUrlFromOverride = rpcOverrideSetting;
71
- } else if (typeof rpcOverrideSetting === 'object' && rpcOverrideSetting) {
72
- // Check if it's a UserRpcProviderConfig
73
- if ('url' in rpcOverrideSetting && 'isCustom' in rpcOverrideSetting) {
74
- const userConfig = rpcOverrideSetting as UserRpcProviderConfig;
75
- rpcUrlFromOverride = buildRpcUrl(userConfig);
76
- } else if ('http' in rpcOverrideSetting) {
77
- // It's an RpcEndpointConfig
78
- rpcUrlFromOverride = rpcOverrideSetting.http;
79
- }
80
- }
81
-
82
- if (rpcUrlFromOverride) {
83
- logger.info(
84
- logSystem,
85
- `Using overridden RPC URL for network ${networkId}: ${rpcUrlFromOverride}`
86
- );
87
- if (isValidUrl(rpcUrlFromOverride)) {
88
- return rpcUrlFromOverride;
89
- } else {
90
- logger.warn(
91
- logSystem,
92
- `Overridden RPC URL for ${networkId} is invalid: ${rpcUrlFromOverride}. Falling back.`
93
- );
94
- }
95
- }
96
-
97
- // Third priority: Fallback to the rpcUrl in the networkConfig
98
- if (networkConfig.rpcUrl && isValidUrl(networkConfig.rpcUrl)) {
99
- logger.debug(
100
- logSystem,
101
- `Using default RPC URL for network ${networkId}: ${networkConfig.rpcUrl}`
102
- );
103
- return networkConfig.rpcUrl;
104
- }
105
-
106
- logger.error(
107
- logSystem,
108
- `No valid RPC URL could be resolved for network ${networkId}. Checked user config, override, and networkConfig.rpcUrl.`
109
- );
110
- throw new Error(
111
- `No valid RPC URL configured for network ${networkConfig.name} (ID: ${networkId}).`
112
- );
113
- }
114
-
115
- /**
116
- * Validates an RPC endpoint configuration for EVM networks.
117
- * @param rpcConfig - The RPC provider configuration to validate
118
- * @returns True if the configuration is valid, false otherwise
119
- */
120
- export function validateEvmRpcEndpoint(rpcConfig: UserRpcProviderConfig): boolean {
121
- try {
122
- // Check if it's a valid URL (our validator already ensures HTTP/HTTPS)
123
- if (!isValidUrl(rpcConfig.url)) {
124
- logger.error('validateEvmRpcEndpoint', `Invalid RPC URL format: ${rpcConfig.url}`);
125
- return false;
126
- }
127
-
128
- // Additional EVM-specific validation could be added here
129
- // For example, checking if the URL follows known provider patterns
130
-
131
- return true;
132
- } catch (error) {
133
- logger.error('validateEvmRpcEndpoint', 'Error validating RPC endpoint:', error);
134
- return false;
135
- }
136
- }
137
-
138
- /**
139
- * Tests the connection to an EVM RPC endpoint with a timeout.
140
- * @param rpcConfig - The RPC provider configuration to test
141
- * @param timeoutMs - Timeout in milliseconds (default: 5000ms)
142
- * @returns Connection test results including success status, latency, and any errors
143
- */
144
- export async function testEvmRpcConnection(
145
- rpcConfig: UserRpcProviderConfig,
146
- timeoutMs: number = 5000
147
- ): Promise<{
148
- success: boolean;
149
- latency?: number;
150
- error?: string;
151
- }> {
152
- if (!rpcConfig.url) {
153
- return { success: false, error: 'RPC URL is required' };
154
- }
155
-
156
- // Create an AbortController for timeout
157
- const controller = new AbortController();
158
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
159
-
160
- try {
161
- const startTime = Date.now();
162
-
163
- // Use fetch to make a JSON-RPC call to test the connection
164
- const response = await fetch(rpcConfig.url, {
165
- method: 'POST',
166
- headers: {
167
- 'Content-Type': 'application/json',
168
- },
169
- body: JSON.stringify({
170
- jsonrpc: '2.0',
171
- method: 'eth_blockNumber',
172
- params: [],
173
- id: 1,
174
- }),
175
- signal: controller.signal,
176
- });
177
-
178
- if (!response.ok) {
179
- return { success: false, error: `HTTP error: ${response.status}` };
180
- }
181
-
182
- const data = await response.json();
183
- const latency = Date.now() - startTime;
184
-
185
- if (data.error) {
186
- return { success: false, error: data.error.message || 'RPC error' };
187
- }
188
-
189
- return { success: true, latency };
190
- } catch (error) {
191
- logger.error('testEvmRpcConnection', 'Connection test failed:', error);
192
-
193
- // Check if the error was due to timeout
194
- if (error instanceof Error && error.name === 'AbortError') {
195
- return {
196
- success: false,
197
- error: `Connection timeout after ${timeoutMs}ms`,
198
- };
199
- }
200
-
201
- return {
202
- success: false,
203
- error: error instanceof Error ? error.message : 'Connection failed',
204
- };
205
- } finally {
206
- // Clear the timeout
207
- clearTimeout(timeoutId);
208
- }
209
- }
210
-
211
- /**
212
- * Gets the current block number from an EVM network.
213
- *
214
- * @param networkConfig - The EVM network configuration
215
- * @returns Promise resolving to the current block number
216
- * @throws Error if the RPC call fails
217
- */
218
- export async function getEvmCurrentBlock(networkConfig: EvmNetworkConfig): Promise<number> {
219
- const rpcUrl = resolveRpcUrl(networkConfig);
220
-
221
- try {
222
- const response = await fetch(rpcUrl, {
223
- method: 'POST',
224
- headers: { 'Content-Type': 'application/json' },
225
- body: JSON.stringify({
226
- jsonrpc: '2.0',
227
- method: 'eth_blockNumber',
228
- params: [],
229
- id: 1,
230
- }),
231
- });
232
-
233
- if (!response.ok) {
234
- throw new Error(`RPC request failed with status ${response.status}`);
235
- }
236
-
237
- const data = await response.json();
238
- if (data.error) {
239
- throw new Error(data.error.message || 'RPC error');
240
- }
241
-
242
- // eth_blockNumber returns a hex string
243
- if (data.result === undefined || data.result === null) {
244
- throw new Error('RPC response missing result field');
245
- }
246
- const blockNumber = parseInt(data.result, 16);
247
- if (isNaN(blockNumber)) {
248
- throw new Error(`Invalid block number returned: ${data.result}`);
249
- }
250
- return blockNumber;
251
- } catch (error) {
252
- logger.error('getEvmCurrentBlock', 'Failed to get current block:', error);
253
- throw new Error(
254
- `Failed to get current block: ${error instanceof Error ? error.message : String(error)}`
255
- );
256
- }
257
- }
@@ -1,137 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
-
3
- import type { FunctionParameter } from '@openzeppelin/ui-types';
4
-
5
- import { generateEvmDefaultField } from '../field-generator';
6
-
7
- // Helper to create a mock function parameter
8
- const createParam = (type: string, name: string, description?: string): FunctionParameter => ({
9
- name,
10
- type,
11
- displayName: name,
12
- description,
13
- });
14
-
15
- describe('EVM Field Generator', () => {
16
- describe('generateEvmDefaultField', () => {
17
- it('should generate a number field for small integer types', () => {
18
- const param = createParam('uint32', 'count');
19
- const field = generateEvmDefaultField(param);
20
-
21
- expect(field.type).toBe('number');
22
- expect(field.validation.required).toBe(true);
23
- expect(field.validation.min).toBe(0);
24
- expect(field.validation.max).toBe(4_294_967_295);
25
- expect(field.validation.pattern).toBeUndefined();
26
- });
27
-
28
- it('should apply numeric bounds for uint8', () => {
29
- const param = createParam('uint8', 'byte');
30
- const field = generateEvmDefaultField(param);
31
-
32
- expect(field.validation.min).toBe(0);
33
- expect(field.validation.max).toBe(255);
34
- });
35
-
36
- it('should apply numeric bounds for int8', () => {
37
- const param = createParam('int8', 'signedByte');
38
- const field = generateEvmDefaultField(param);
39
-
40
- expect(field.validation.min).toBe(-128);
41
- expect(field.validation.max).toBe(127);
42
- });
43
-
44
- it('should apply numeric bounds for int32', () => {
45
- const param = createParam('int32', 'signedInt');
46
- const field = generateEvmDefaultField(param);
47
-
48
- expect(field.validation.min).toBe(-2_147_483_648);
49
- expect(field.validation.max).toBe(2_147_483_647);
50
- });
51
-
52
- it('should generate a bigint field for uint128', () => {
53
- const param = createParam('uint128', 'amount');
54
- const field = generateEvmDefaultField(param);
55
-
56
- expect(field.type).toBe('bigint');
57
- expect(field.validation.required).toBe(true);
58
- // BigIntField component handles its own validation and UI guidance
59
- });
60
-
61
- it('should generate a bigint field for uint256', () => {
62
- const param = createParam('uint256', 'value');
63
- const field = generateEvmDefaultField(param);
64
-
65
- expect(field.type).toBe('bigint');
66
- expect(field.validation.required).toBe(true);
67
- // BigIntField component handles its own validation and UI guidance
68
- });
69
-
70
- it('should generate a bigint field for int128', () => {
71
- const param = createParam('int128', 'delta');
72
- const field = generateEvmDefaultField(param);
73
-
74
- expect(field.type).toBe('bigint');
75
- expect(field.validation.required).toBe(true);
76
- // BigIntField component handles its own validation and UI guidance
77
- });
78
-
79
- it('should generate a bigint field for int256', () => {
80
- const param = createParam('int256', 'offset');
81
- const field = generateEvmDefaultField(param);
82
-
83
- expect(field.type).toBe('bigint');
84
- expect(field.validation.required).toBe(true);
85
- // BigIntField component handles its own validation and UI guidance
86
- });
87
-
88
- it('should preserve parameter description in helper text', () => {
89
- const param = createParam('uint256', 'tokenId', 'The unique identifier of the NFT');
90
- const field = generateEvmDefaultField(param);
91
-
92
- expect(field.type).toBe('bigint');
93
- expect(field.helperText).toBe('The unique identifier of the NFT');
94
- });
95
-
96
- it('should generate a blockchain-address field for address type', () => {
97
- const param = createParam('address', 'recipient');
98
- const field = generateEvmDefaultField(param);
99
-
100
- expect(field.type).toBe('blockchain-address');
101
- expect(field.validation.required).toBe(true);
102
- expect(field.validation.pattern).toBeUndefined();
103
- });
104
-
105
- it('should generate array field with proper element config for uint256[]', () => {
106
- const param = createParam('uint256[]', 'amounts');
107
- const field = generateEvmDefaultField(param);
108
-
109
- expect(field.type).toBe('array');
110
- expect(field.elementFieldConfig).toBeDefined();
111
- expect(field.elementFieldConfig?.type).toBe('bigint');
112
- // Integer validation is handled by BigIntField component internally
113
- });
114
-
115
- it('should apply numeric bounds to array element fields', () => {
116
- const param = createParam('uint32[]', 'counts');
117
- const field = generateEvmDefaultField(param);
118
-
119
- expect(field.type).toBe('array');
120
- expect(field.elementFieldConfig).toBeDefined();
121
- expect(field.elementFieldConfig!.validation).toBeDefined();
122
- expect(field.elementFieldConfig!.validation!.min).toBe(0);
123
- expect(field.elementFieldConfig!.validation!.max).toBe(4_294_967_295);
124
- });
125
-
126
- it('should include proper field metadata', () => {
127
- const param = createParam('uint256', 'value');
128
- const field = generateEvmDefaultField(param);
129
-
130
- expect(field.id).toBeDefined();
131
- expect(field.name).toBe('value');
132
- expect(field.label).toBe('Value');
133
- expect(field.placeholder).toContain('value');
134
- expect(field.width).toBe('full');
135
- });
136
- });
137
- });