@openzeppelin/ui-builder-adapter-evm 0.15.0 → 0.16.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/dist/index.cjs +57 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +61 -4
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/mapping/__tests__/field-generator.test.ts +37 -0
- package/src/mapping/field-generator.ts +32 -3
- package/src/wallet/implementation/wagmi-implementation.ts +48 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openzeppelin/ui-builder-adapter-evm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "EVM Adapter for UI Builder",
|
|
6
6
|
"keywords": [
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"lodash": "^4.17.21",
|
|
44
44
|
"lucide-react": "^0.510.0",
|
|
45
45
|
"react-hook-form": "^7.62.0",
|
|
46
|
-
"@openzeppelin/ui-builder-react-core": "^0.
|
|
47
|
-
"@openzeppelin/ui-builder-types": "^0.
|
|
48
|
-
"@openzeppelin/ui-builder-ui": "^0.
|
|
49
|
-
"@openzeppelin/ui-builder-utils": "^0.
|
|
46
|
+
"@openzeppelin/ui-builder-react-core": "^0.16.0",
|
|
47
|
+
"@openzeppelin/ui-builder-types": "^0.16.0",
|
|
48
|
+
"@openzeppelin/ui-builder-ui": "^0.16.0",
|
|
49
|
+
"@openzeppelin/ui-builder-utils": "^0.16.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@rainbow-me/rainbowkit": "^2.2.8",
|
|
@@ -20,9 +20,35 @@ describe('EVM Field Generator', () => {
|
|
|
20
20
|
|
|
21
21
|
expect(field.type).toBe('number');
|
|
22
22
|
expect(field.validation.required).toBe(true);
|
|
23
|
+
expect(field.validation.min).toBe(0);
|
|
24
|
+
expect(field.validation.max).toBe(4_294_967_295);
|
|
23
25
|
expect(field.validation.pattern).toBeUndefined();
|
|
24
26
|
});
|
|
25
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
|
+
|
|
26
52
|
it('should generate a bigint field for uint128', () => {
|
|
27
53
|
const param = createParam('uint128', 'amount');
|
|
28
54
|
const field = generateEvmDefaultField(param);
|
|
@@ -86,6 +112,17 @@ describe('EVM Field Generator', () => {
|
|
|
86
112
|
// Integer validation is handled by BigIntField component internally
|
|
87
113
|
});
|
|
88
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
|
+
|
|
89
126
|
it('should include proper field metadata', () => {
|
|
90
127
|
const param = createParam('uint256', 'value');
|
|
91
128
|
const field = generateEvmDefaultField(param);
|
|
@@ -7,7 +7,11 @@ import type {
|
|
|
7
7
|
FormFieldType,
|
|
8
8
|
FunctionParameter,
|
|
9
9
|
} from '@openzeppelin/ui-builder-types';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
enhanceNumericValidation,
|
|
12
|
+
getDefaultValueForType,
|
|
13
|
+
type NumericBoundsMap,
|
|
14
|
+
} from '@openzeppelin/ui-builder-utils';
|
|
11
15
|
|
|
12
16
|
import { mapEvmParamTypeToFieldType } from './type-mapper';
|
|
13
17
|
|
|
@@ -33,6 +37,23 @@ function getDefaultValidation(): FieldValidation {
|
|
|
33
37
|
return { required: true };
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
/**
|
|
41
|
+
* EVM numeric type bounds.
|
|
42
|
+
* Maps EVM type names to their min/max value constraints.
|
|
43
|
+
* Note: uint64, uint128, uint256, int64, int128, int256 exceed JavaScript's Number.MAX_SAFE_INTEGER
|
|
44
|
+
* and are handled via BigInt fields, so bounds are not applied here.
|
|
45
|
+
*/
|
|
46
|
+
const EVM_NUMERIC_BOUNDS: NumericBoundsMap = {
|
|
47
|
+
uint: { min: 0 },
|
|
48
|
+
uint8: { min: 0, max: 255 },
|
|
49
|
+
uint16: { min: 0, max: 65_535 },
|
|
50
|
+
uint32: { min: 0, max: 4_294_967_295 },
|
|
51
|
+
int: {},
|
|
52
|
+
int8: { min: -128, max: 127 },
|
|
53
|
+
int16: { min: -32_768, max: 32_767 },
|
|
54
|
+
int32: { min: -2_147_483_648, max: 2_147_483_647 },
|
|
55
|
+
};
|
|
56
|
+
|
|
36
57
|
/**
|
|
37
58
|
* Generate default field configuration for an EVM function parameter.
|
|
38
59
|
*/
|
|
@@ -49,7 +70,11 @@ export function generateEvmDefaultField<T extends FieldType = FieldType>(
|
|
|
49
70
|
placeholder: `Enter ${parameter.displayName || parameter.name || parameter.type}`,
|
|
50
71
|
helperText: parameter.description || '',
|
|
51
72
|
defaultValue: getDefaultValueForType(fieldType) as FieldValue<T>,
|
|
52
|
-
validation:
|
|
73
|
+
validation: enhanceNumericValidation(
|
|
74
|
+
getDefaultValidation(),
|
|
75
|
+
parameter.type,
|
|
76
|
+
EVM_NUMERIC_BOUNDS
|
|
77
|
+
),
|
|
53
78
|
width: 'full',
|
|
54
79
|
};
|
|
55
80
|
|
|
@@ -65,7 +90,11 @@ export function generateEvmDefaultField<T extends FieldType = FieldType>(
|
|
|
65
90
|
elementType: elementFieldType,
|
|
66
91
|
elementFieldConfig: {
|
|
67
92
|
type: elementFieldType,
|
|
68
|
-
validation:
|
|
93
|
+
validation: enhanceNumericValidation(
|
|
94
|
+
getDefaultValidation(),
|
|
95
|
+
elementType,
|
|
96
|
+
EVM_NUMERIC_BOUNDS
|
|
97
|
+
),
|
|
69
98
|
placeholder: `Enter ${elementType}`,
|
|
70
99
|
},
|
|
71
100
|
};
|
|
@@ -99,6 +99,7 @@ export class WagmiWalletImplementation {
|
|
|
99
99
|
private unsubscribe?: ReturnType<typeof watchAccount>;
|
|
100
100
|
private initialized: boolean = false;
|
|
101
101
|
private walletConnectProjectId?: string;
|
|
102
|
+
private rpcConfigUnsubscribe?: () => void;
|
|
102
103
|
|
|
103
104
|
/**
|
|
104
105
|
* Constructs the WagmiWalletImplementation.
|
|
@@ -121,9 +122,50 @@ export class WagmiWalletImplementation {
|
|
|
121
122
|
LOG_SYSTEM,
|
|
122
123
|
'WagmiWalletImplementation instance initialized (Wagmi config creation deferred).'
|
|
123
124
|
);
|
|
125
|
+
// Subscribe to RPC configuration changes to invalidate cached config
|
|
126
|
+
this.setupRpcConfigListener();
|
|
124
127
|
// No config created here by default anymore.
|
|
125
128
|
}
|
|
126
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Sets up a listener for RPC configuration changes to invalidate the cached Wagmi config
|
|
132
|
+
* when user changes RPC settings.
|
|
133
|
+
*/
|
|
134
|
+
private setupRpcConfigListener(): void {
|
|
135
|
+
// Import dynamically to avoid circular dependencies
|
|
136
|
+
import('@openzeppelin/ui-builder-utils')
|
|
137
|
+
.then(({ userRpcConfigService }) => {
|
|
138
|
+
// Subscribe to all RPC config changes
|
|
139
|
+
this.rpcConfigUnsubscribe = userRpcConfigService.subscribe('*', (event) => {
|
|
140
|
+
if (event.type === 'rpc-config-changed' || event.type === 'rpc-config-cleared') {
|
|
141
|
+
logger.info(
|
|
142
|
+
LOG_SYSTEM,
|
|
143
|
+
`RPC config changed for network ${event.networkId}. Invalidating cached Wagmi config.`
|
|
144
|
+
);
|
|
145
|
+
// Invalidate the cached config to force recreation with new RPC settings
|
|
146
|
+
this.defaultInstanceConfig = null;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
})
|
|
150
|
+
.catch((error) => {
|
|
151
|
+
logger.error(LOG_SYSTEM, 'Failed to setup RPC config listener:', error);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Cleanup method to unsubscribe from RPC config changes
|
|
157
|
+
*/
|
|
158
|
+
public cleanup(): void {
|
|
159
|
+
if (this.rpcConfigUnsubscribe) {
|
|
160
|
+
this.rpcConfigUnsubscribe();
|
|
161
|
+
this.rpcConfigUnsubscribe = undefined;
|
|
162
|
+
}
|
|
163
|
+
if (this.unsubscribe) {
|
|
164
|
+
this.unsubscribe();
|
|
165
|
+
this.unsubscribe = undefined;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
127
169
|
/**
|
|
128
170
|
* Sets the externally determined, currently active WagmiConfig instance.
|
|
129
171
|
* This is typically called by EvmUiKitManager after it has resolved the appropriate
|
|
@@ -333,8 +375,12 @@ export class WagmiWalletImplementation {
|
|
|
333
375
|
);
|
|
334
376
|
}
|
|
335
377
|
|
|
336
|
-
//
|
|
337
|
-
|
|
378
|
+
// Reuse existing default config if available, only create if needed
|
|
379
|
+
// This ensures wallet connection state is preserved across network switches
|
|
380
|
+
// Config is automatically invalidated when RPC settings change via setupRpcConfigListener()
|
|
381
|
+
if (!this.defaultInstanceConfig) {
|
|
382
|
+
this.defaultInstanceConfig = this.createDefaultConfig();
|
|
383
|
+
}
|
|
338
384
|
return this.defaultInstanceConfig;
|
|
339
385
|
}
|
|
340
386
|
|