@@ -412,6 +412,166 @@ contract RemoveLiquidityUniswapV3Test is BaseTest {
412412 }
413413 }
414414
415+ function testRevert_InvalidERC721Data () public {
416+ {
417+ address posOwner = IUniswapV3PM (pm).ownerOf (963_350 );
418+ vm.prank (posOwner);
419+ IERC721 (pm).safeTransferFrom (posOwner, mainAddress, 963_350 );
420+ }
421+ { // Claim all fees of two positions
422+ vm.startPrank (mainAddress);
423+ bytes [] memory claimCalldata = new bytes [](2 );
424+ claimCalldata[0 ] = abi.encodeWithSelector (
425+ IUniswapV3PM.collect.selector ,
426+ IUniswapV3PM.CollectParams ({
427+ tokenId: tokenId,
428+ recipient: mainAddress,
429+ amount0Max: type (uint128 ).max,
430+ amount1Max: type (uint128 ).max
431+ })
432+ );
433+ claimCalldata[1 ] = abi.encodeWithSelector (
434+ IUniswapV3PM.collect.selector ,
435+ IUniswapV3PM.CollectParams ({
436+ tokenId: 963_350 ,
437+ recipient: mainAddress,
438+ amount0Max: type (uint128 ).max,
439+ amount1Max: type (uint128 ).max
440+ })
441+ );
442+
443+ IUniswapV3PM (pm).multicall (claimCalldata);
444+ vm.stopPrank ();
445+ }
446+
447+ bytes [] memory multiCalldata;
448+
449+ multiCalldata = new bytes [](5 );
450+ multiCalldata[0 ] = abi.encodeWithSelector (
451+ IUniswapV3PM.decreaseLiquidity.selector ,
452+ IUniswapV3PM.DecreaseLiquidityParams ({
453+ tokenId: tokenId,
454+ liquidity: uint128 (uniswapV3.removeLiqParams.liquidityToRemove),
455+ amount0Min: 0 ,
456+ amount1Min: 0 ,
457+ deadline: block .timestamp + 1 days
458+ })
459+ );
460+ multiCalldata[1 ] = abi.encodeWithSelector (
461+ IUniswapV3PM.collect.selector ,
462+ IUniswapV3PM.CollectParams ({
463+ tokenId: tokenId,
464+ recipient: address (pm),
465+ amount0Max: type (uint128 ).max,
466+ amount1Max: type (uint128 ).max
467+ })
468+ );
469+ multiCalldata[2 ] = abi.encodeWithSelector (
470+ IERC721 .transferFrom.selector , address (forwarder), mainAddress, tokenId
471+ );
472+ multiCalldata[3 ] = abi.encodeWithSelector (IUniswapV3PM.unwrapWETH9.selector , 0 , address (router));
473+ multiCalldata[4 ] = abi.encodeWithSelector (
474+ IUniswapV3PM.sweepToken.selector , uniswapV3.outputParams.tokens[0 ], 0 , address (router)
475+ );
476+
477+ IntentData memory intentData;
478+ {
479+ KSRemoveLiquidityUniswapV3Hook.RemoveLiquidityHookData memory hookData;
480+ hookData.nftAddresses = new address [](1 );
481+ hookData.nftAddresses[0 ] = address (pm);
482+ hookData.nftIds = new uint256 [](1 );
483+ hookData.nftIds[0 ] = 963_350 ;
484+ hookData.maxFees = new uint256 [](1 );
485+ hookData.maxFees[0 ] = (maxFeePercents << 128 ) | maxFeePercents;
486+ hookData.recipient = mainAddress;
487+
488+ address [] memory pools = new address [](1 );
489+ pools[0 ] = address (pool);
490+ hookData.additionalData = abi.encode (pools);
491+
492+ hookData.nodes = new Node [][](1 );
493+ // Only one time condition true, no child conditions needed
494+ Condition memory condition = _createTimeCondition (true );
495+
496+ Node[] memory nodes = new Node [](1 );
497+ nodes[0 ] = _createLeafNode (condition); // leaf node with time condition true
498+
499+ hookData.nodes[0 ] = nodes;
500+
501+ hookData.recipient = mainAddress;
502+
503+ address [] memory actionContracts = new address [](2 );
504+ actionContracts[0 ] = address (mockActionContract);
505+ actionContracts[1 ] = address (pm);
506+
507+ bytes4 [] memory actionSelectors = new bytes4 [](2 );
508+ actionSelectors[0 ] = MockActionContract.removeUniswapV3.selector ;
509+ actionSelectors[1 ] = IUniswapV3PM.multicall.selector ;
510+
511+ IntentCoreData memory coreData = IntentCoreData ({
512+ mainAddress: mainAddress,
513+ signatureVerifier: address (0 ),
514+ delegatedKey: delegatedPublicKey,
515+ actionContracts: actionContracts,
516+ actionSelectors: actionSelectors,
517+ hook: address (rmLqValidator),
518+ hookIntentData: abi.encode (hookData)
519+ });
520+
521+ TokenData memory tokenData;
522+ tokenData.erc721Data = new ERC721Data [](1 );
523+ tokenData.erc721Data[0 ] = ERC721Data ({token: address (pm), tokenId: tokenId, permitData: '' });
524+
525+ intentData = IntentData ({coreData: coreData, tokenData: tokenData, extraData: '' });
526+ }
527+
528+ _setUpMainAddress (intentData, false , tokenId);
529+
530+ FeeInfo memory feeInfo;
531+ {
532+ feeInfo.protocolRecipient = protocolRecipient;
533+ feeInfo.partnerFeeConfigs = new FeeConfig [][](2 );
534+ feeInfo.partnerFeeConfigs[0 ] = _buildPartnersConfigs (
535+ PartnersFeeConfigBuildParams ({
536+ feeModes: [false , true ].toMemoryArray (),
537+ partnerFees: [0.25e6 , 0.25e6 ].toMemoryArray (),
538+ partnerRecipients: [partnerRecipient, makeAddr ('partnerRecipient2 ' )].toMemoryArray ()
539+ })
540+ );
541+
542+ feeInfo.partnerFeeConfigs[1 ] = feeInfo.partnerFeeConfigs[0 ];
543+ }
544+
545+ ActionData memory actionData;
546+ {
547+ actionData = ActionData ({
548+ erc20Ids: new uint256 [](0 ),
549+ erc20Amounts: new uint256 [](0 ),
550+ erc721Ids: [uint256 (0 )].toMemoryArray (),
551+ feeInfo: feeInfo,
552+ actionSelectorId: 1 ,
553+ approvalFlags: type (uint256 ).max,
554+ actionCalldata: abi.encode (multiCalldata),
555+ hookActionData: abi.encode (
556+ 0 ,
557+ uniswapV3.removeLiqParams.positionInfo.unclaimedFees[0 ],
558+ uniswapV3.removeLiqParams.positionInfo.unclaimedFees[1 ],
559+ 0 ,
560+ false ,
561+ (intentFeesPercent0 << 128 ) | intentFeesPercent1
562+ ),
563+ extraData: '' ,
564+ deadline: block .timestamp + 1 days,
565+ nonce: 0
566+ });
567+ }
568+
569+ (, bytes memory dkSignature , bytes memory gdSignature ) =
570+ _getCallerAndSignatures (0 , intentData, actionData);
571+ vm.expectRevert (BaseTickBasedRemoveLiquidityHook.InvalidERC721Data.selector );
572+ router.execute (intentData, dkSignature, guardian, gdSignature, actionData);
573+ }
574+
415575 function buildConditionTree (
416576 Node[] calldata nodes ,
417577 uint256 fee0Collected ,
0 commit comments