1- import { isAddress , PublicClient } from 'viem' ;
2- import { normalize } from 'viem/ens' ;
3- import { z , ZodError } from 'zod' ;
1+ import { isAddress } from 'viem' ;
2+ import { z , ZodError , ZodSchema } from 'zod' ;
43import {
54 appendErrors ,
65 FieldError ,
@@ -9,16 +8,24 @@ import {
98} from 'react-hook-form' ;
109import { VaultFactoryArgs } from 'types' ;
1110import {
11+ MainSettingsKeys ,
1212 PermissionKeys ,
13+ VaultMainSettingsType ,
1314 VaultPermissionsType ,
1415} from 'features/create-vault/types' ;
16+ import { isValidAnyAddress } from 'utils/address-validation' ;
17+ import { isValidEns } from '../../../../utils/ens' ;
1518
1619const INVALID_ADDRESS_MESSAGE = 'Invalid ethereum address' ;
1720const INVALID_NUMBER_MIN_MESSAGE = 'Must be 0.001 or above' ;
1821const INVALID_NUMBER_MAX_MESSAGE = 'Must be 99 or less' ;
19- const INVALID_NUMBER_DATA_MESSAGE = { message : 'Only number is valid' } ;
22+ const INVALID_NUMBER_SUM_MESSAGE =
23+ "Sum of Curator's and Node Operator's fees can't be more than 100" ;
24+ const INVALID_NUMBER_EXPIRY_MAX_MESSAGE = 'Must be 800 or less' ;
25+ const INVALID_NUMBER_DATA_MESSAGE = 'Only number is valid' ;
26+ const INVALID_NUMBER_DATA_OBJECT_MESSAGE = { message : 'Only number is valid' } ;
2027
21- const validateAddress = ( value : string ) => isAddress ( value ) ;
28+ const validateAddress = ( value : string ) => isValidAnyAddress ( value ) ;
2229
2330const addressSchema = z
2431 . string ( )
@@ -29,19 +36,18 @@ export const createVaultSchema = z.object({
2936 nodeOperatorManager : addressSchema ,
3037 assetRecoverer : addressSchema ,
3138 nodeOperatorFeeBP : z
32- . number ( INVALID_NUMBER_DATA_MESSAGE )
39+ . number ( INVALID_NUMBER_DATA_OBJECT_MESSAGE )
3340 . min ( 0.001 , INVALID_NUMBER_MIN_MESSAGE )
3441 . max ( 99 , INVALID_NUMBER_MAX_MESSAGE ) ,
3542 curatorFeeBP : z . coerce
36- . number ( INVALID_NUMBER_DATA_MESSAGE )
43+ . number ( INVALID_NUMBER_DATA_OBJECT_MESSAGE )
3744 . min ( 0.001 , INVALID_NUMBER_MIN_MESSAGE )
3845 . max ( 99 , INVALID_NUMBER_MAX_MESSAGE ) ,
3946 confirmExpiry : z . coerce
40- . number ( INVALID_NUMBER_DATA_MESSAGE )
47+ . number ( INVALID_NUMBER_DATA_OBJECT_MESSAGE )
4148 . min ( 1 , INVALID_NUMBER_MIN_MESSAGE )
42- . max ( 800 , 'Must be 800 or less' ) ,
49+ . max ( 800 , INVALID_NUMBER_EXPIRY_MAX_MESSAGE ) ,
4350 defaultAdmin : addressSchema ,
44- confirmMainSettings : z . boolean ( ) ,
4551 funders : z . array ( addressSchema ) . optional ( ) ,
4652 withdrawers : z . array ( addressSchema ) . optional ( ) ,
4753 minters : z . array ( addressSchema ) . optional ( ) ,
@@ -114,49 +120,37 @@ export const parseZodErrorSchema = (
114120 return errors ;
115121} ;
116122
117- export const createVaultFormValidator = async ( values : CreateVaultSchema ) => {
118- try {
119- const output = await createVaultSchema . parseAsync ( values ) ;
120- return {
121- values : output ,
122- errors : { } ,
123- } ;
124- } catch ( err : unknown ) {
125- if ( isZodError ( err ) ) {
126- const errors = err . errors ;
123+ export const createVaultFormValidator = < T extends ZodSchema > (
124+ schema : T ,
125+ ) : Resolver < z . infer < T > > => {
126+ return async ( values : z . infer < T > ) => {
127+ try {
128+ const output = schema . parse ( values ) ;
127129 return {
128- values,
129- errors : parseZodErrorSchema ( errors , true ) ,
130+ values : output ,
131+ errors : { } ,
130132 } ;
131- }
132-
133- return {
134- values : values ,
135- errors : { } ,
136- } ;
137- }
138- } ;
133+ } catch ( err : unknown ) {
134+ if ( isZodError ( err ) ) {
135+ const errors = err . errors ;
136+ return {
137+ values ,
138+ errors : parseZodErrorSchema ( errors , true ) ,
139+ } ;
140+ }
139141
140- // TODO: move to shared validators
141- export const validateEnsDomain = async (
142- value : string ,
143- publicClient : PublicClient ,
144- ) => {
145- try {
146- const ensAddress = await publicClient . getEnsAddress ( {
147- name : normalize ( value ) ,
148- } ) ;
149-
150- return ! ! ensAddress ;
151- } catch ( e ) {
152- return false ;
153- }
142+ return {
143+ values : values ,
144+ errors : { } ,
145+ } ;
146+ }
147+ } ;
154148} ;
155149
156150export const formatCreateVaultData = (
157151 values : CreateVaultSchema ,
158152) : VaultFactoryArgs => {
159- const { confirmMainSettings , nodeOperator, ...payload } = values ;
153+ const { nodeOperator, ...payload } = values ;
160154 ( payload as unknown as VaultFactoryArgs ) . confirmExpiry = BigInt (
161155 values . confirmExpiry ,
162156 ) ;
@@ -165,9 +159,8 @@ export const formatCreateVaultData = (
165159} ;
166160
167161export const validatePermissions = (
168- publicClient : PublicClient ,
169162 getValues : UseFormGetValues < Record < string , any > > ,
170- ) : Resolver < VaultPermissionsType , any > => {
163+ ) : Resolver < VaultPermissionsType > => {
171164 return async ( values : VaultPermissionsType ) => {
172165 const errors = { } as Record <
173166 PermissionKeys ,
@@ -185,10 +178,7 @@ export const validatePermissions = (
185178 const { value : currentValue } = field ;
186179
187180 if ( ! isAddress ( currentValue ) ) {
188- const isValid = await validateEnsDomain (
189- currentValue ,
190- publicClient ,
191- ) ;
181+ const isValid = isValidEns ( currentValue ) ;
192182
193183 if ( ! isValid ) {
194184 errors [ key ] [ `${ index } ` ] = {
@@ -218,3 +208,88 @@ export const validatePermissions = (
218208 } ;
219209 } ;
220210} ;
211+
212+ export const validateMainSettings : Resolver < VaultMainSettingsType > = (
213+ values : VaultMainSettingsType ,
214+ ) => {
215+ const errors = { } as Record < MainSettingsKeys , { message : string } > ;
216+ const keysList = Object . keys ( values ) as MainSettingsKeys [ ] ;
217+
218+ keysList . map ( ( key : MainSettingsKeys ) => {
219+ const payload = values [ key ] ;
220+ if ( typeof payload === 'string' ) {
221+ const isValid = validateAddress ( payload ) ;
222+ if ( ! isValid ) {
223+ errors [ key ] = {
224+ message : INVALID_ADDRESS_MESSAGE ,
225+ } ;
226+ }
227+ }
228+
229+ if (
230+ [ 'nodeOperatorFeeBP' , 'confirmExpiry' , 'curatorFeeBP' ] . includes ( key ) &&
231+ typeof payload !== 'number'
232+ ) {
233+ errors [ key ] = {
234+ message : INVALID_NUMBER_DATA_MESSAGE ,
235+ } ;
236+ }
237+
238+ if ( typeof payload === 'number' ) {
239+ if ( key === 'nodeOperatorFeeBP' ) {
240+ if ( payload < 0.001 ) {
241+ errors [ key ] = {
242+ message : INVALID_NUMBER_DATA_MESSAGE ,
243+ } ;
244+ } else if ( payload > 99 ) {
245+ errors [ key ] = {
246+ message : INVALID_NUMBER_MAX_MESSAGE ,
247+ } ;
248+ } else if ( values . curatorFeeBP + payload > 100 ) {
249+ errors [ key ] = {
250+ message : INVALID_NUMBER_SUM_MESSAGE ,
251+ } ;
252+ }
253+ }
254+
255+ if ( key === 'confirmExpiry' ) {
256+ if ( payload < 1 ) {
257+ errors [ key ] = {
258+ message : INVALID_NUMBER_DATA_MESSAGE ,
259+ } ;
260+ }
261+
262+ if ( payload > 800 ) {
263+ errors [ key ] = {
264+ message : INVALID_NUMBER_EXPIRY_MAX_MESSAGE ,
265+ } ;
266+ }
267+ }
268+
269+ if ( key === 'curatorFeeBP' ) {
270+ if ( payload < 0.001 ) {
271+ errors [ key ] = {
272+ message : INVALID_NUMBER_DATA_MESSAGE ,
273+ } ;
274+ }
275+
276+ if ( payload > 99 ) {
277+ errors [ key ] = {
278+ message : INVALID_NUMBER_MAX_MESSAGE ,
279+ } ;
280+ }
281+
282+ if ( values . nodeOperatorFeeBP + payload > 100 ) {
283+ errors [ key ] = {
284+ message : INVALID_NUMBER_SUM_MESSAGE ,
285+ } ;
286+ }
287+ }
288+ }
289+ } ) ;
290+
291+ return {
292+ values,
293+ errors,
294+ } ;
295+ } ;
0 commit comments