@@ -24,6 +24,17 @@ error ResolverNotFound();
2424
2525error ResolverWildcardNotSupported ();
2626
27+ error ResolverNotContract ();
28+
29+ error ResolverError (bytes returnData );
30+
31+ error HttpError (HttpErrorItem[] errors );
32+
33+ struct HttpErrorItem {
34+ uint16 status;
35+ string message;
36+ }
37+
2738struct MulticallData {
2839 bytes name;
2940 bytes [] data;
@@ -35,6 +46,11 @@ struct MulticallData {
3546 bool [] failures;
3647}
3748
49+ struct MulticallChecks {
50+ bool isCallback;
51+ bool hasExtendedResolver;
52+ }
53+
3854struct OffchainLookupCallData {
3955 address sender;
4056 string [] urls;
@@ -46,6 +62,11 @@ struct OffchainLookupExtraData {
4662 bytes data;
4763}
4864
65+ struct Result {
66+ bool success;
67+ bytes returnData;
68+ }
69+
4970interface BatchGateway {
5071 function query (
5172 OffchainLookupCallData[] memory data
@@ -97,7 +118,7 @@ contract UniversalResolver is ERC165, Ownable {
97118 function resolve (
98119 bytes calldata name ,
99120 bytes [] memory data
100- ) external view returns (bytes [] memory , address ) {
121+ ) external view returns (Result [] memory , address ) {
101122 return resolve (name, data, batchGatewayURLs);
102123 }
103124
@@ -120,7 +141,7 @@ contract UniversalResolver is ERC165, Ownable {
120141 bytes calldata name ,
121142 bytes [] memory data ,
122143 string [] memory gateways
123- ) public view returns (bytes [] memory , address ) {
144+ ) public view returns (Result [] memory , address ) {
124145 return
125146 _resolve (name, data, gateways, this .resolveCallback.selector , "" );
126147 }
@@ -134,14 +155,19 @@ contract UniversalResolver is ERC165, Ownable {
134155 ) public view returns (bytes memory , address ) {
135156 bytes [] memory dataArr = new bytes [](1 );
136157 dataArr[0 ] = data;
137- (bytes [] memory results , address resolver ) = _resolve (
158+ (Result [] memory results , address resolver ) = _resolve (
138159 name,
139160 dataArr,
140161 gateways,
141162 callbackFunction,
142163 metaData
143164 );
144- return (results[0 ], resolver);
165+
166+ Result memory result = results[0 ];
167+
168+ _checkResolveSingle (result);
169+
170+ return (result.returnData, resolver);
145171 }
146172
147173 function _resolve (
@@ -150,13 +176,17 @@ contract UniversalResolver is ERC165, Ownable {
150176 string [] memory gateways ,
151177 bytes4 callbackFunction ,
152178 bytes memory metaData
153- ) internal view returns (bytes [] memory results , address resolverAddress ) {
179+ ) internal view returns (Result [] memory results , address resolverAddress ) {
154180 (Resolver resolver , , uint256 finalOffset ) = findResolver (name);
155181 resolverAddress = address (resolver);
156182 if (resolverAddress == address (0 )) {
157183 revert ResolverNotFound ();
158184 }
159185
186+ if (! resolverAddress.isContract ()) {
187+ revert ResolverNotContract ();
188+ }
189+
160190 bool isWildcard = finalOffset != 0 ;
161191
162192 results = _multicall (
@@ -193,7 +223,7 @@ contract UniversalResolver is ERC165, Ownable {
193223 reverseName.namehash (0 )
194224 );
195225 (
196- bytes memory resolvedReverseData ,
226+ bytes memory reverseResolvedData ,
197227 address reverseResolverAddress
198228 ) = _resolveSingle (
199229 reverseName,
@@ -205,7 +235,7 @@ contract UniversalResolver is ERC165, Ownable {
205235
206236 return
207237 getForwardDataFromReverse (
208- resolvedReverseData ,
238+ reverseResolvedData ,
209239 reverseResolverAddress,
210240 gateways
211241 );
@@ -249,19 +279,23 @@ contract UniversalResolver is ERC165, Ownable {
249279 bytes calldata response ,
250280 bytes calldata extraData
251281 ) external view returns (bytes memory , address ) {
252- (bytes [] memory results , address resolver , , ) = _resolveCallback (
282+ (Result [] memory results , address resolver , , ) = _resolveCallback (
253283 response,
254284 extraData,
255285 this .resolveSingleCallback.selector
256286 );
257- return (results[0 ], resolver);
287+ Result memory result = results[0 ];
288+
289+ _checkResolveSingle (result);
290+
291+ return (result.returnData, resolver);
258292 }
259293
260294 function resolveCallback (
261295 bytes calldata response ,
262296 bytes calldata extraData
263- ) external view returns (bytes [] memory , address ) {
264- (bytes [] memory results , address resolver , , ) = _resolveCallback (
297+ ) external view returns (Result [] memory , address ) {
298+ (Result [] memory results , address resolver , , ) = _resolveCallback (
265299 response,
266300 extraData,
267301 this .resolveCallback.selector
@@ -274,7 +308,7 @@ contract UniversalResolver is ERC165, Ownable {
274308 bytes calldata extraData
275309 ) external view returns (string memory , address , address , address ) {
276310 (
277- bytes [] memory resolvedData ,
311+ Result [] memory results ,
278312 address resolverAddress ,
279313 string [] memory gateways ,
280314 bytes memory metaData
@@ -284,10 +318,16 @@ contract UniversalResolver is ERC165, Ownable {
284318 this .reverseCallback.selector
285319 );
286320
321+ Result memory result = results[0 ];
322+
323+ if (! result.success) {
324+ revert ResolverError (result.returnData);
325+ }
326+
287327 if (metaData.length > 0 ) {
288328 (string memory resolvedName , address reverseResolverAddress ) = abi
289329 .decode (metaData, (string , address ));
290- address resolvedAddress = abi.decode (resolvedData[ 0 ] , (address ));
330+ address resolvedAddress = abi.decode (result.returnData , (address ));
291331 return (
292332 resolvedName,
293333 resolvedAddress,
@@ -298,7 +338,7 @@ contract UniversalResolver is ERC165, Ownable {
298338
299339 return
300340 getForwardDataFromReverse (
301- resolvedData[ 0 ] ,
341+ result.returnData ,
302342 resolverAddress,
303343 gateways
304344 );
@@ -319,7 +359,7 @@ contract UniversalResolver is ERC165, Ownable {
319359 )
320360 internal
321361 view
322- returns (bytes [] memory , address , string [] memory , bytes memory )
362+ returns (Result [] memory , address , string [] memory , bytes memory )
323363 {
324364 MulticallData memory multicallData;
325365 multicallData.callbackFunction = callbackFunction;
@@ -381,7 +421,8 @@ contract UniversalResolver is ERC165, Ownable {
381421 */
382422 function callWithOffchainLookupPropagation (
383423 address target ,
384- bytes memory data
424+ bytes memory data ,
425+ bool isSafe
385426 )
386427 internal
387428 view
@@ -392,7 +433,11 @@ contract UniversalResolver is ERC165, Ownable {
392433 bool result
393434 )
394435 {
395- result = LowLevelCallUtils.functionStaticCall (address (target), data);
436+ if (isSafe) {
437+ result = LowLevelCallUtils.functionStaticCall (target, data);
438+ } else {
439+ result = LowLevelCallUtils.functionStaticCall (target, data, 50000 );
440+ }
396441 uint256 size = LowLevelCallUtils.returnDataSize ();
397442
398443 if (result) {
@@ -499,56 +544,105 @@ contract UniversalResolver is ERC165, Ownable {
499544 return (parentresolver, node, parentoffset);
500545 }
501546
502- function _hasExtendedResolver (
503- address resolver
547+ function _checkInterface (
548+ address resolver ,
549+ bytes4 interfaceId
504550 ) internal view returns (bool ) {
505551 try
506- Resolver (resolver).supportsInterface {gas: 50000 }(
507- type (IExtendedResolver).interfaceId
508- )
552+ Resolver (resolver).supportsInterface {gas: 50000 }(interfaceId)
509553 returns (bool supported ) {
510554 return supported;
511555 } catch {
512556 return false ;
513557 }
514558 }
515559
560+ function _checkSafetyAndItem (
561+ bytes memory name ,
562+ bytes memory item ,
563+ address resolver ,
564+ MulticallChecks memory multicallChecks
565+ ) internal view returns (bool , bytes memory ) {
566+ if (! multicallChecks.isCallback) {
567+ if (multicallChecks.hasExtendedResolver) {
568+ return (
569+ true ,
570+ abi.encodeCall (IExtendedResolver.resolve, (name, item))
571+ );
572+ }
573+ return (_checkInterface (resolver, bytes4 (item)), item);
574+ }
575+ return (true , item);
576+ }
577+
578+ function _checkMulticall (
579+ MulticallData memory multicallData
580+ ) internal view returns (MulticallChecks memory ) {
581+ bool isCallback = multicallData.name.length == 0 ;
582+ bool hasExtendedResolver = _checkInterface (
583+ multicallData.resolver,
584+ type (IExtendedResolver).interfaceId
585+ );
586+
587+ if (multicallData.isWildcard && ! hasExtendedResolver) {
588+ revert ResolverWildcardNotSupported ();
589+ }
590+
591+ return MulticallChecks (isCallback, hasExtendedResolver);
592+ }
593+
594+ function _checkResolveSingle (Result memory result ) internal pure {
595+ if (! result.success) {
596+ if (bytes4 (result.returnData) == HttpError.selector ) {
597+ (, HttpErrorItem[] memory errors ) = abi.decode (
598+ result.returnData,
599+ (bytes4 , HttpErrorItem[])
600+ );
601+ revert HttpError (errors);
602+ }
603+ revert ResolverError (result.returnData);
604+ }
605+ }
606+
516607 function _multicall (
517608 MulticallData memory multicallData
518- ) internal view returns (bytes [] memory results ) {
609+ ) internal view returns (Result [] memory results ) {
519610 uint256 length = multicallData.data.length ;
520611 uint256 offchainCount = 0 ;
521612 OffchainLookupCallData[]
522613 memory callDatas = new OffchainLookupCallData [](length);
523614 OffchainLookupExtraData[]
524615 memory extraDatas = new OffchainLookupExtraData [](length);
525- results = new bytes [](length);
526- bool isCallback = multicallData.name.length == 0 ;
527- bool hasExtendedResolver = _hasExtendedResolver (multicallData.resolver);
528-
529- if (multicallData.isWildcard && ! hasExtendedResolver) {
530- revert ResolverWildcardNotSupported ();
531- }
616+ results = new Result [](length);
617+ MulticallChecks memory multicallChecks = _checkMulticall (multicallData);
532618
533619 for (uint256 i = 0 ; i < length; i++ ) {
534620 bytes memory item = multicallData.data[i];
535621 bool failure = multicallData.failures[i];
622+
536623 if (failure) {
537- results[i] = item;
624+ results[i] = Result ( false , item) ;
538625 continue ;
539626 }
540- if (! isCallback && hasExtendedResolver) {
541- item = abi.encodeCall (
542- IExtendedResolver.resolve,
543- (multicallData.name, item)
544- );
545- }
627+
628+ bool isSafe = false ;
629+ (isSafe, item) = _checkSafetyAndItem (
630+ multicallData.name,
631+ item,
632+ multicallData.resolver,
633+ multicallChecks
634+ );
635+
546636 (
547637 bool offchain ,
548638 bytes memory returnData ,
549639 OffchainLookupExtraData memory extraData ,
550640 bool success
551- ) = callWithOffchainLookupPropagation (multicallData.resolver, item);
641+ ) = callWithOffchainLookupPropagation (
642+ multicallData.resolver,
643+ item,
644+ isSafe
645+ );
552646
553647 if (offchain) {
554648 callDatas[offchainCount] = abi.decode (
@@ -560,11 +654,11 @@ contract UniversalResolver is ERC165, Ownable {
560654 continue ;
561655 }
562656
563- if (success && hasExtendedResolver) {
657+ if (success && multicallChecks. hasExtendedResolver) {
564658 // if this is a successful resolve() call, unwrap the result
565659 returnData = abi.decode (returnData, (bytes ));
566660 }
567- results[i] = returnData;
661+ results[i] = Result (success, returnData) ;
568662 extraDatas[i].data = multicallData.data[i];
569663 }
570664
0 commit comments