feat: Perform staticcall to CallbackVerifier
This commit is contained in:
163
foundry/test/CallbackVerificationDispatcher.t.sol
Normal file
163
foundry/test/CallbackVerificationDispatcher.t.sol
Normal file
@@ -0,0 +1,163 @@
|
||||
// SPDX-License-Identifier: UNLICENSED
|
||||
pragma solidity ^0.8.28;
|
||||
|
||||
import "@src/CallbackVerificationDispatcher.sol";
|
||||
import "./TychoRouterTestSetup.sol";
|
||||
|
||||
contract CallbackVerificationDispatcherExposed is
|
||||
CallbackVerificationDispatcher
|
||||
{
|
||||
function exposedCallVerifier(bytes calldata data)
|
||||
external
|
||||
returns (
|
||||
uint256 amountOwed,
|
||||
uint256 amountReceived,
|
||||
address tokenOwed,
|
||||
uint16 dataOffset
|
||||
)
|
||||
{
|
||||
return _callVerifyCallback(data);
|
||||
}
|
||||
|
||||
function exposedDecodeVerifierAndSelector(bytes calldata data)
|
||||
external
|
||||
pure
|
||||
returns (address executor, bytes4 selector, bytes memory protocolData)
|
||||
{
|
||||
return _decodeVerifierAndSelector(data);
|
||||
}
|
||||
|
||||
function exposedSetVerifier(address target) external {
|
||||
callbackVerifiers[target] = true;
|
||||
}
|
||||
|
||||
function exposedRemoveVerifier(address target) external {}
|
||||
}
|
||||
|
||||
contract CallbackVerificationDispatcherTest is Constants {
|
||||
CallbackVerificationDispatcherExposed dispatcherExposed;
|
||||
|
||||
event VerifierSet(address indexed executor);
|
||||
event VerifierRemoved(address indexed executor);
|
||||
|
||||
function setUp() public {
|
||||
uint256 forkBlock = 20673900;
|
||||
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
|
||||
dispatcherExposed = new CallbackVerificationDispatcherExposed();
|
||||
deal(WETH_ADDR, address(dispatcherExposed), 15 ether);
|
||||
deployDummyContract();
|
||||
}
|
||||
|
||||
function testCallVerifierSuccess() public {
|
||||
// For this test, we can use any callback verifier and any calldata that we
|
||||
// know works for this verifier. We don't care about which calldata/executor,
|
||||
// since we are only testing the functionality of the staticcall and not
|
||||
// the inner verifier.
|
||||
// Thus, this test case designed from scratch using previously-deployed
|
||||
// Maverick callback verifier. Looking at the code, we can easily design
|
||||
// passing calldata.
|
||||
dispatcherExposed.exposedSetVerifier(
|
||||
address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8)
|
||||
);
|
||||
bytes memory data =
|
||||
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e876b20f8a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
||||
vm.startPrank(address(0xD0b2F5018B5D22759724af6d4281AC0B13266360));
|
||||
(
|
||||
uint256 amountOwed,
|
||||
uint256 amountReceived,
|
||||
address tokenOwed,
|
||||
uint16 dataOffset
|
||||
) = dispatcherExposed.exposedCallVerifier(data);
|
||||
vm.stopPrank();
|
||||
|
||||
// The values themselves are irrelevant, we just need to make sure that we
|
||||
// correctly parse the expected output of the existing Maverick verifier
|
||||
assert(amountOwed == 1);
|
||||
assert(amountReceived == 1);
|
||||
assert(tokenOwed == address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48));
|
||||
assert(dataOffset == 148);
|
||||
}
|
||||
|
||||
function testCallVerifierNoSelector() public {
|
||||
// For this test, we can use any callback verifier and any calldata that we
|
||||
// know works for this verifier. We don't care about which calldata/executor,
|
||||
// since we are only testing the functionality of the staticcall and not
|
||||
// the inner verifier.
|
||||
// Thus, this test case designed from scratch using previously-deployed
|
||||
// Maverick callback verifier. Looking at the code, we can easily design
|
||||
// passing calldata.
|
||||
dispatcherExposed.exposedSetVerifier(
|
||||
address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8)
|
||||
);
|
||||
|
||||
// Pass all-zero selector. This should default to the verifyCallback selector
|
||||
bytes memory data =
|
||||
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
||||
vm.startPrank(address(0xD0b2F5018B5D22759724af6d4281AC0B13266360));
|
||||
(
|
||||
uint256 amountOwed,
|
||||
uint256 amountReceived,
|
||||
address tokenOwed,
|
||||
uint16 dataOffset
|
||||
) = dispatcherExposed.exposedCallVerifier(data);
|
||||
vm.stopPrank();
|
||||
|
||||
// The values themselves are irrelevant, we just need to make sure that we
|
||||
// correctly parse the expected output of the existing Maverick verifier
|
||||
assert(amountOwed == 1);
|
||||
assert(amountReceived == 1);
|
||||
assert(tokenOwed == address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48));
|
||||
assert(dataOffset == 148);
|
||||
}
|
||||
|
||||
function testCallVerifierBadSelector() public {
|
||||
// A bad selector is provided to an approved executor - causing the call
|
||||
// itself to fail. Make sure this actually reverts.
|
||||
dispatcherExposed.exposedSetVerifier(
|
||||
address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8)
|
||||
);
|
||||
vm.startPrank(address(0xD0b2F5018B5D22759724af6d4281AC0B13266360));
|
||||
bytes memory data =
|
||||
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8aa0000000000";
|
||||
vm.expectRevert(bytes("Callback verification failed"));
|
||||
dispatcherExposed.exposedCallVerifier(data);
|
||||
vm.stopPrank();
|
||||
}
|
||||
|
||||
function testCallVerifierParseRevertMessage() public {
|
||||
// Verification should fail because caller is not a Maverick pool
|
||||
// Check that we correctly parse the revert message
|
||||
dispatcherExposed.exposedSetVerifier(
|
||||
address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8)
|
||||
);
|
||||
bytes memory data =
|
||||
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
||||
vm.expectRevert(
|
||||
abi.encodeWithSignature(
|
||||
"Error(string)", "Must call from a Maverick Factory Pool"
|
||||
)
|
||||
);
|
||||
dispatcherExposed.exposedCallVerifier(data);
|
||||
}
|
||||
|
||||
function testCallVerifierUnapprovedVerifier() public {
|
||||
bytes memory data =
|
||||
hex"5d622C9053b8FFB1B3465495C8a42E603632bA70aabbccdd1111111111111111";
|
||||
vm.expectRevert();
|
||||
dispatcherExposed.exposedCallVerifier(data);
|
||||
}
|
||||
|
||||
function testDecodeVerifierAndSelector() public {
|
||||
bytes memory data =
|
||||
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e876b20f8aA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
||||
(address executor, bytes4 selector, bytes memory verifierData) =
|
||||
dispatcherExposed.exposedDecodeVerifierAndSelector(data);
|
||||
assert(executor == address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8));
|
||||
assert(selector == bytes4(0x76b20f8a));
|
||||
// Direct bytes comparison not supported - must use keccak
|
||||
assert(
|
||||
keccak256(verifierData)
|
||||
== keccak256(hex"A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user