181 lines
8.2 KiB
Solidity
181 lines
8.2 KiB
Solidity
// SPDX-License-Identifier: UNLICENSED
|
|
pragma solidity ^0.8.26;
|
|
|
|
import "@src/CallbackVerificationDispatcher.sol";
|
|
import "./TychoRouterTestSetup.sol";
|
|
|
|
contract CallbackVerificationDispatcherExposed is
|
|
CallbackVerificationDispatcher
|
|
{
|
|
function exposedCallVerifier(bytes calldata data)
|
|
external
|
|
view
|
|
returns (uint256 amountOwed, address tokenOwed)
|
|
{
|
|
return _callVerifyCallback(data);
|
|
}
|
|
|
|
function exposedDecodeVerifierAndSelector(bytes calldata data)
|
|
external
|
|
pure
|
|
returns (address executor, bytes4 selector, bytes memory protocolData)
|
|
{
|
|
return _decodeVerifierAndSelector(data);
|
|
}
|
|
|
|
function exposedSetCallbackVerifier(address target) external {
|
|
_setCallbackVerifier(target);
|
|
}
|
|
|
|
function exposedRemoveCallbackVerifier(address target) external {
|
|
_removeCallbackVerifier(target);
|
|
}
|
|
}
|
|
|
|
contract CallbackVerificationDispatcherTest is Constants {
|
|
CallbackVerificationDispatcherExposed dispatcherExposed;
|
|
|
|
event CallbackVerifierSet(address indexed callbackVerifier);
|
|
event CallbackVerifierRemoved(address indexed callbackVerifier);
|
|
|
|
function setUp() public {
|
|
uint256 forkBlock = 20673900;
|
|
vm.createSelectFork(vm.rpcUrl("mainnet"), forkBlock);
|
|
dispatcherExposed = new CallbackVerificationDispatcherExposed();
|
|
deal(WETH_ADDR, address(dispatcherExposed), 15 ether);
|
|
deployDummyContract();
|
|
}
|
|
|
|
function testSetValidVerifier() public {
|
|
vm.expectEmit();
|
|
// Define the event we expect to be emitted at the next step
|
|
emit CallbackVerifierSet(DUMMY);
|
|
dispatcherExposed.exposedSetCallbackVerifier(DUMMY);
|
|
assert(dispatcherExposed.callbackVerifiers(DUMMY) == true);
|
|
}
|
|
|
|
function testRemoveVerifier() public {
|
|
dispatcherExposed.exposedSetCallbackVerifier(DUMMY);
|
|
vm.expectEmit();
|
|
// Define the event we expect to be emitted at the next step
|
|
emit CallbackVerifierRemoved(DUMMY);
|
|
dispatcherExposed.exposedRemoveCallbackVerifier(DUMMY);
|
|
assert(dispatcherExposed.callbackVerifiers(DUMMY) == false);
|
|
}
|
|
|
|
function testRemoveUnSetVerifier() public {
|
|
dispatcherExposed.exposedRemoveCallbackVerifier(BOB);
|
|
assert(dispatcherExposed.callbackVerifiers(BOB) == false);
|
|
}
|
|
|
|
function testSetVerifierNonContract() public {
|
|
vm.expectRevert(
|
|
abi.encodeWithSelector(
|
|
CallbackVerificationDispatcher__NonContractVerifier.selector
|
|
)
|
|
);
|
|
dispatcherExposed.exposedSetCallbackVerifier(BOB);
|
|
}
|
|
|
|
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.exposedSetCallbackVerifier(
|
|
address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8)
|
|
);
|
|
bytes memory data =
|
|
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e876b20f8a0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
|
vm.startPrank(address(0xD0b2F5018B5D22759724af6d4281AC0B13266360));
|
|
(uint256 amountOwed, address tokenOwed) =
|
|
dispatcherExposed.exposedCallVerifier(data);
|
|
vm.stopPrank();
|
|
|
|
// The specific values returned are not important for this test.
|
|
// The goal is to ensure correct calling of the Maverick verifier's.
|
|
// Since the verifier's output format has changed, the asserted values may not be meaningful.
|
|
// Full validation of the functionality will be covered in the integration tests.
|
|
assert(amountOwed == 1);
|
|
assert(tokenOwed == address(0x0000000000000000000000000000000000000001));
|
|
}
|
|
|
|
function testCallVerifierNoSelector() public {
|
|
// This test is exactly the same as testCallVerifierSuccess, except that the
|
|
// fn selector is not explicitly passed. The test should still pass using the
|
|
// default selector.
|
|
dispatcherExposed.exposedSetCallbackVerifier(
|
|
address(0x2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8)
|
|
);
|
|
|
|
// Pass all-zero selector. This should default to the verifyCallback selector
|
|
bytes memory data =
|
|
hex"2C960bD1CFE09A26105ad3C351bEa0a3fAD0F8e8000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
|
|
vm.startPrank(address(0xD0b2F5018B5D22759724af6d4281AC0B13266360));
|
|
(uint256 amountOwed, address tokenOwed) =
|
|
dispatcherExposed.exposedCallVerifier(data);
|
|
vm.stopPrank();
|
|
|
|
// The specific values returned are not important for this test.
|
|
// The goal is to ensure correct calling of the Maverick verifier's.
|
|
// Since the verifier's output format has changed, the asserted values may not be meaningful.
|
|
// Full validation of the functionality will be covered in the integration tests.
|
|
assert(amountOwed == 1);
|
|
assert(tokenOwed == address(0x0000000000000000000000000000000000000001));
|
|
}
|
|
|
|
function testCallVerifierBadSelector() public {
|
|
// A bad selector is provided to an approved executor - causing the call
|
|
// itself to fail. Make sure this actually reverts.
|
|
dispatcherExposed.exposedSetCallbackVerifier(
|
|
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.exposedSetCallbackVerifier(
|
|
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 view {
|
|
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")
|
|
);
|
|
}
|
|
}
|