2828import org .junit .jupiter .api .BeforeAll ;
2929import org .junit .jupiter .api .BeforeEach ;
3030import org .junit .jupiter .api .Test ;
31+ import org .mockito .ArgumentCaptor ;
3132
3233import org .web3j .abi .TypeEncoder ;
3334import org .web3j .abi .datatypes .Utf8String ;
@@ -281,13 +282,60 @@ void buildRequestWhenNotValidSenderTest() {
281282 }
282283
283284 @ Test
284- void buildRequestWhenNotValidUrl () {
285+ void buildRequestWithDataParameterOnly () throws Exception {
285286 String url = "https://example.com/gateway/{data}.json" ;
286287 sender = "0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8" ;
287288 data = "0xd5fa2b00" ;
288289
289- assertThrows (
290- EnsResolutionException .class , () -> ensResolver .buildRequest (url , sender , data ));
290+ okhttp3 .Request request = ensResolver .buildRequest (url , sender , data );
291+
292+ assertEquals ("https://example.com/gateway/0xd5fa2b00.json" , request .url ().toString ());
293+ assertEquals ("GET" , request .method ());
294+ assertNull (request .body ());
295+ }
296+
297+ @ Test
298+ void buildRequestWithSenderParameterOnly () throws Exception {
299+ String url = "https://example.com/gateway/{sender}/lookup" ;
300+ sender = "0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8" ;
301+ data = "0xd5fa2b00" ;
302+
303+ okhttp3 .Request request = ensResolver .buildRequest (url , sender , data );
304+
305+ assertEquals (
306+ "https://example.com/gateway/0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8/lookup" ,
307+ request .url ().toString ());
308+ assertEquals ("POST" , request .method ());
309+ assertNotNull (request .body ());
310+ assertEquals ("application/json" , request .header ("Content-Type" ));
311+ }
312+
313+ @ Test
314+ void verifyPostRequestBodyContainsSenderAndData () throws Exception {
315+ String url = "https://example.com/gateway/lookup" ;
316+ sender = "0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8" ;
317+ data = "0xd5fa2b00" ;
318+
319+ okhttp3 .Request request = ensResolver .buildRequest (url , sender , data );
320+ assertNotNull (request .body ());
321+ okhttp3 .MediaType contentType = request .body ().contentType ();
322+ assertNotNull (contentType );
323+ assertTrue (contentType .toString ().startsWith ("application/json" ));
324+ }
325+
326+ @ Test
327+ void buildRequestWithBothParameters () throws Exception {
328+ String url = "https://example.com/gateway/{sender}/{data}" ;
329+ sender = "0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8" ;
330+ data = "0xd5fa2b00" ;
331+
332+ okhttp3 .Request request = ensResolver .buildRequest (url , sender , data );
333+
334+ assertEquals (
335+ "https://example.com/gateway/0x226159d592E2b063810a10Ebf6dcbADA94Ed68b8/0xd5fa2b00" ,
336+ request .url ().toString ());
337+ assertEquals ("GET" , request .method ());
338+ assertNull (request .body ());
291339 }
292340
293341 @ Test
@@ -420,9 +468,7 @@ void resolveOffchainSuccess() throws Exception {
420468 when (httpClientMock .newCall (any ())).thenReturn (call );
421469 when (call .execute ()).thenReturn (responseObj );
422470
423- RemoteFunctionCall respWithProof = mock (RemoteFunctionCall .class );
424- when (resolver .resolveWithProof (any (), any ())).thenReturn (respWithProof );
425- when (respWithProof .send ()).thenReturn (RESOLVED_NAME_HEX );
471+ when (resolver .executeCallWithoutDecoding (any ())).thenReturn (RESOLVED_NAME_HEX );
426472
427473 String result = ensResolver .resolveOffchain (LOOKUP_HEX , resolver , 4 );
428474
@@ -447,17 +493,87 @@ void resolveOffchainWhenLookUpCallsOutOfLimit() throws Exception {
447493 buildResponse (200 , urls .get (0 ), sender , data ),
448494 buildResponse (200 , urls .get (0 ), sender , data ));
449495
450- RemoteFunctionCall respWithProof = mock (RemoteFunctionCall .class );
451- when (resolver .resolveWithProof (any (), any ()))
452- .thenReturn (respWithProof , respWithProof , respWithProof );
453496 String eip3668Data = EnsUtils .EIP_3668_CCIP_INTERFACE_ID + "data" ;
454- when (respWithProof .send ()).thenReturn (eip3668Data , eip3668Data , eip3668Data );
497+ when (resolver .executeCallWithoutDecoding (any ()))
498+ .thenReturn (eip3668Data , eip3668Data , eip3668Data );
455499
456500 assertThrows (
457501 EnsResolutionException .class ,
458502 () -> ensResolver .resolveOffchain (LOOKUP_HEX , resolver , 2 ));
459503 }
460504
505+ @ Test
506+ void resolveOffchainWithDynamicCallback () throws Exception {
507+ OffchainResolverContract resolver = mock (OffchainResolverContract .class );
508+ when (resolver .getContractAddress ())
509+ .thenReturn ("0xc1735677a60884abbcf72295e88d47764beda282" );
510+
511+ OkHttpClient httpClientMock = mock (OkHttpClient .class );
512+ Call call = mock (Call .class );
513+ okhttp3 .Response responseObj = buildResponse (200 , urls .get (0 ), sender , data );
514+ ensResolver .setHttpClient (httpClientMock );
515+ when (httpClientMock .newCall (any ())).thenReturn (call );
516+ when (call .execute ()).thenReturn (responseObj );
517+
518+ // Create a custom LOOKUP_HEX with a different callback function
519+ String customCallbackSelector = "aabbccdd" ;
520+ String customLookupHex =
521+ LOOKUP_HEX .substring (0 , 202 ) + customCallbackSelector + LOOKUP_HEX .substring (210 );
522+
523+ // Capture the function call to verify the correct callback selector is used
524+ ArgumentCaptor <String > functionCallCaptor = ArgumentCaptor .forClass (String .class );
525+ when (resolver .executeCallWithoutDecoding (functionCallCaptor .capture ()))
526+ .thenReturn (RESOLVED_NAME_HEX );
527+
528+ String result = ensResolver .resolveOffchain (customLookupHex , resolver , 4 );
529+ assertEquals ("0x41563129cdbbd0c5d3e1c86cf9563926b243834d" , result );
530+
531+ // Verify that the captured function call starts with our custom callback selector
532+ String capturedFunctionCall = functionCallCaptor .getValue ();
533+ assertTrue (
534+ capturedFunctionCall .startsWith ("0x" + customCallbackSelector ),
535+ "Function call should start with the custom callback selector" );
536+ }
537+
538+ @ Test
539+ void resolveOffchainParameterEncoding () throws Exception {
540+ OffchainResolverContract resolver = mock (OffchainResolverContract .class );
541+ when (resolver .getContractAddress ())
542+ .thenReturn ("0xc1735677a60884abbcf72295e88d47764beda282" );
543+
544+ OkHttpClient httpClientMock = mock (OkHttpClient .class );
545+ Call call = mock (Call .class );
546+ String testData = "0xabcdef" ;
547+
548+ EnsGatewayResponseDTO responseDTO = new EnsGatewayResponseDTO (testData );
549+ String responseJson = om .writeValueAsString (responseDTO );
550+
551+ okhttp3 .Response responseObj =
552+ new okhttp3 .Response .Builder ()
553+ .request (new okhttp3 .Request .Builder ().url (urls .get (0 )).build ())
554+ .protocol (Protocol .HTTP_2 )
555+ .code (200 )
556+ .body (ResponseBody .create (responseJson , JSON_MEDIA_TYPE ))
557+ .message ("OK" )
558+ .build ();
559+
560+ ensResolver .setHttpClient (httpClientMock );
561+ when (httpClientMock .newCall (any ())).thenReturn (call );
562+ when (call .execute ()).thenReturn (responseObj );
563+
564+ ArgumentCaptor <String > functionCallCaptor = ArgumentCaptor .forClass (String .class );
565+ when (resolver .executeCallWithoutDecoding (functionCallCaptor .capture ()))
566+ .thenReturn (RESOLVED_NAME_HEX );
567+
568+ String result = ensResolver .resolveOffchain (LOOKUP_HEX , resolver , 4 );
569+ assertEquals ("0x41563129cdbbd0c5d3e1c86cf9563926b243834d" , result );
570+
571+ String capturedFunctionCall = functionCallCaptor .getValue ();
572+ assertTrue (
573+ capturedFunctionCall .contains (testData .substring (2 )),
574+ "Function call should contain the encoded test data" );
575+ }
576+
461577 class EnsResolverForTest extends EnsResolver {
462578 private OffchainResolverContract resolverMock ;
463579
0 commit comments