Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ TrailsIntentEntrypointTest:testPermitAmountExcessiveWithFee() (gas: 83027)
TrailsIntentEntrypointTest:testPermitAmountInsufficientWithFee() (gas: 82059)
TrailsIntentEntrypointTest:testUsedIntentsMapping() (gas: 113770)
TrailsIntentEntrypointTest:testVersionConstant() (gas: 10381)
TrailsRouterDeploymentTest:test_DeployTrailsRouter_SameAddress() (gas: 1773856)
TrailsRouterDeploymentTest:test_DeployTrailsRouter_Success() (gas: 1764409)
TrailsRouterDeploymentTest:test_DeployedRouter_HasCorrectConfiguration() (gas: 1764205)
TrailsRouterShimDeploymentTest:test_DeployRouterShim_SameAddress() (gas: 7285038)
TrailsRouterShimDeploymentTest:test_DeployRouterShim_Success() (gas: 4709602)
TrailsRouterShimDeploymentTest:test_DeployedContract_HasCorrectConfiguration() (gas: 4709648)
TrailsRouterDeploymentTest:test_DeployTrailsRouter_SameAddress() (gas: 1784084)
TrailsRouterDeploymentTest:test_DeployTrailsRouter_Success() (gas: 1771019)
TrailsRouterDeploymentTest:test_DeployedRouter_HasCorrectConfiguration() (gas: 1770815)
TrailsRouterShimDeploymentTest:test_DeployRouterShim_SameAddress() (gas: 7469868)
TrailsRouterShimDeploymentTest:test_DeployRouterShim_Success() (gas: 4803591)
TrailsRouterShimDeploymentTest:test_DeployedContract_HasCorrectConfiguration() (gas: 4803637)
TrailsRouterShimTest:testConstructorValidation() (gas: 69336)
TrailsRouterShimTest:testForwardToRouterReturnValue() (gas: 713355)
TrailsRouterShimTest:testRouterAddressImmutable() (gas: 1391679)
TrailsRouterShimTest:test_constructor_revert_zeroRouter() (gas: 68984)
TrailsRouterShimTest:test_delegatecall_forwards_and_sets_sentinel_sstore_inactive() (gas: 1766894)
TrailsRouterShimTest:test_delegatecall_forwards_and_sets_sentinel_sstore_inactive() (gas: 1767156)
TrailsRouterShimTest:test_delegatecall_forwards_and_sets_sentinel_tstore_active() (gas: 38392)
TrailsRouterShimTest:test_delegatecall_router_revert_bubbles_as_RouterCallFailed() (gas: 82109)
TrailsRouterShimTest:test_delegatecall_sets_sentinel_with_sstore_when_no_tstore() (gas: 1749120)
TrailsRouterShimTest:test_delegatecall_sets_sentinel_with_sstore_when_no_tstore() (gas: 1749382)
TrailsRouterShimTest:test_delegatecall_sets_sentinel_with_tstore_when_supported() (gas: 20706)
TrailsRouterShimTest:test_direct_handleSequenceDelegateCall_reverts_not_delegatecall() (gas: 9840)
TrailsRouterShimTest:test_forwardToRouter_return_data_handling() (gas: 729052)
Expand Down
10 changes: 7 additions & 3 deletions script/TrailsRouter.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.30;

import {SingletonDeployer, console} from "erc2470-libs/script/SingletonDeployer.s.sol";
import {TrailsRouter} from "../src/TrailsRouter.sol";
import {MULTICALL3_ADDRESS} from "../test/mocks/MockMulticall3.sol";

contract Deploy is SingletonDeployer {
// -------------------------------------------------------------------------
Expand All @@ -14,19 +15,22 @@ contract Deploy is SingletonDeployer {
address deployerAddress = vm.addr(pk);
console.log("Deployer Address:", deployerAddress);

address router = deployRouter(pk);
address multicall3 = vm.envOr("MULTICALL3_ADDRESS", MULTICALL3_ADDRESS);
console.log("Multicall3 Address:", multicall3);

address router = deployRouter(pk, multicall3);
console.log("TrailsRouter deployed at:", router);
}

// -------------------------------------------------------------------------
// Deploy Router
// -------------------------------------------------------------------------

function deployRouter(uint256 pk) public returns (address) {
function deployRouter(uint256 pk, address multicall3) public returns (address) {
bytes32 salt = bytes32(0);

// Deploy TrailsRouter
bytes memory initCode = type(TrailsRouter).creationCode;
bytes memory initCode = abi.encodePacked(type(TrailsRouter).creationCode, abi.encode(multicall3));
address router = _deployIfNotAlready("TrailsRouter", initCode, salt, pk);

return router;
Expand Down
9 changes: 5 additions & 4 deletions script/TrailsRouterShim.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.30;

import {SingletonDeployer, console} from "erc2470-libs/script/SingletonDeployer.s.sol";
import {TrailsRouterShim} from "../src/TrailsRouterShim.sol";
import {MULTICALL3_ADDRESS} from "../test/mocks/MockMulticall3.sol";
import {Deploy as TrailsRouterDeploy} from "./TrailsRouter.s.sol";

contract Deploy is SingletonDeployer {
Expand All @@ -21,14 +22,14 @@ contract Deploy is SingletonDeployer {
address deployerAddress = vm.addr(pk);
console.log("Deployer Address:", deployerAddress);

address multicall3 = vm.envOr("MULTICALL3_ADDRESS", MULTICALL3_ADDRESS);
console.log("Multicall3 Address:", multicall3);

bytes32 salt = bytes32(0);

// Deploy TrailsRouter using the TrailsRouter deployment script
TrailsRouterDeploy routerDeploy = new TrailsRouterDeploy();
routerDeploy.run();

// Get the deployed router address from the deployment script
routerAddress = routerDeploy.deployRouter(pk);
routerAddress = routerDeploy.deployRouter(pk, multicall3);
console.log("TrailsRouter deployed at:", routerAddress);

// Deploy TrailsRouterShim with the router address
Expand Down
10 changes: 9 additions & 1 deletion src/TrailsRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,15 @@ contract TrailsRouter is IDelegatedExtension, ITrailsRouter, DelegatecallGuard,
// Immutable Variables
// -------------------------------------------------------------------------

address public immutable MULTICALL3 = 0xcA11bde05977b3631167028862bE2a173976CA11;
address public immutable MULTICALL3;

// -------------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------------

constructor(address multicall3) {
MULTICALL3 = multicall3;
}

// -------------------------------------------------------------------------
// Errors
Expand Down
22 changes: 11 additions & 11 deletions test/TrailsRouter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {TrailsRouter} from "src/TrailsRouter.sol";
import {DelegatecallGuard} from "src/guards/DelegatecallGuard.sol";
import {MockSenderGetter} from "test/mocks/MockSenderGetter.sol";
import {MockERC20} from "test/mocks/MockERC20.sol";
import {MockMulticall3} from "test/mocks/MockMulticall3.sol";
import {MockMulticall3, MULTICALL3_ADDRESS} from "test/mocks/MockMulticall3.sol";
import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol";
import {IERC20Errors} from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol";
import {IDelegatedExtension} from "wallet-contracts-v3/modules/interfaces/IDelegatedExtension.sol";
Expand Down Expand Up @@ -197,9 +197,9 @@ contract TrailsRouterTest is Test {
function setUp() public {
// Deploy mock multicall3 at the expected address
MockMulticall3 mockMulticall3 = new MockMulticall3();
vm.etch(0xcA11bde05977b3631167028862bE2a173976CA11, address(mockMulticall3).code);
vm.etch(MULTICALL3_ADDRESS, address(mockMulticall3).code);

router = new TrailsRouter();
router = new TrailsRouter(MULTICALL3_ADDRESS);
getter = new MockSenderGetter();
mockToken = new MockERC20("MockToken", "MTK", 18);
failingToken = new FailingToken();
Expand Down Expand Up @@ -346,7 +346,7 @@ contract TrailsRouterTest is Test {
}

function test_Multicall3Address_IsCorrect() public view {
assertEq(router.MULTICALL3(), 0xcA11bde05977b3631167028862bE2a173976CA11);
assertEq(router.MULTICALL3(), MULTICALL3_ADDRESS);
}

// -------------------------------------------------------------------------
Expand Down Expand Up @@ -795,14 +795,14 @@ contract TrailsRouterTest is Test {

function testExecute_WithFailingMulticall() public {
// Save original multicall code
bytes memory originalCode = 0xcA11bde05977b3631167028862bE2a173976CA11.code;
bytes memory originalCode = MULTICALL3_ADDRESS.code;

// Deploy and etch failing multicall
MockMulticall3 failingMulticall = new MockMulticall3();
vm.etch(0xcA11bde05977b3631167028862bE2a173976CA11, address(failingMulticall).code);
vm.etch(MULTICALL3_ADDRESS, address(failingMulticall).code);

// Verify the etch worked
assertEq(keccak256(0xcA11bde05977b3631167028862bE2a173976CA11.code), keccak256(address(failingMulticall).code));
assertEq(keccak256(MULTICALL3_ADDRESS.code), keccak256(address(failingMulticall).code));

// Set the failure flag directly in storage since delegatecall uses caller's storage
// The shouldFail variable is at slot 0 in MockMulticall3
Expand All @@ -824,18 +824,18 @@ contract TrailsRouterTest is Test {
router.execute(callData);

// Restore original code
vm.etch(0xcA11bde05977b3631167028862bE2a173976CA11, originalCode);
vm.etch(MULTICALL3_ADDRESS, originalCode);
}

function test_pullAndExecute_WithFailingMulticall() public {
uint256 transferAmount = 100e18;

// Save original multicall code
bytes memory originalCode = 0xcA11bde05977b3631167028862bE2a173976CA11.code;
bytes memory originalCode = MULTICALL3_ADDRESS.code;

// Mock multicall3 to return failure
MockMulticall3 failingMulticall = new MockMulticall3();
vm.etch(0xcA11bde05977b3631167028862bE2a173976CA11, address(failingMulticall).code);
vm.etch(MULTICALL3_ADDRESS, address(failingMulticall).code);

// Set the failure flag directly in storage since delegatecall uses caller's storage
vm.store(address(router), bytes32(0), bytes32(uint256(1))); // Set shouldFail = true in router's storage
Expand All @@ -860,7 +860,7 @@ contract TrailsRouterTest is Test {
router.pullAndExecute(address(mockToken), callData);

// Restore original code
vm.etch(0xcA11bde05977b3631167028862bE2a173976CA11, originalCode);
vm.etch(MULTICALL3_ADDRESS, originalCode);
}

function testInjectSweepAndCall_WithETH_ZeroBalance() public {
Expand Down
5 changes: 3 additions & 2 deletions test/TrailsRouterShim.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.30;

import {Test} from "forge-std/Test.sol";
import {MULTICALL3_ADDRESS} from "test/mocks/MockMulticall3.sol";
import {TrailsRouterShim} from "src/TrailsRouterShim.sol";
import {DelegatecallGuard} from "src/guards/DelegatecallGuard.sol";
import {TrailsSentinelLib} from "src/libraries/TrailsSentinelLib.sol";
Expand Down Expand Up @@ -253,7 +254,7 @@ contract TrailsRouterShimTest is Test {

// Verify sentinel by re-etching TrailsRouter and validating via delegated entrypoint
bytes memory original = address(shimImpl).code;
vm.etch(holder, address(new TrailsRouter()).code);
vm.etch(holder, address(new TrailsRouter(MULTICALL3_ADDRESS)).code);

address payable recipient = payable(address(0x111));
vm.deal(holder, callValue);
Expand Down Expand Up @@ -309,7 +310,7 @@ contract TrailsRouterShimTest is Test {

// Verify via TrailsRouter delegated validation
bytes memory original = address(shimImpl).code;
vm.etch(holder, address(new TrailsRouter()).code);
vm.etch(holder, address(new TrailsRouter(MULTICALL3_ADDRESS)).code);
address payable recipient = payable(address(0x112));
vm.deal(holder, 1 ether);
bytes memory data =
Expand Down
2 changes: 2 additions & 0 deletions test/mocks/MockMulticall3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pragma solidity ^0.8.30;

import {IMulticall3} from "src/interfaces/IMulticall3.sol";

address constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;

// -----------------------------------------------------------------------------
// Mock Contract
// -----------------------------------------------------------------------------
Expand Down
13 changes: 8 additions & 5 deletions test/script/TrailsRouter.s.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {Test} from "forge-std/Test.sol";
import {Deploy as TrailsRouterDeploy} from "script/TrailsRouter.s.sol";
import {TrailsRouter} from "src/TrailsRouter.sol";
import {Create2Utils} from "../utils/Create2Utils.sol";
import {MULTICALL3_ADDRESS} from "../mocks/MockMulticall3.sol";

// -----------------------------------------------------------------------------
// Test Contract
Expand All @@ -25,8 +26,10 @@ contract TrailsRouterDeploymentTest is Test {
// -------------------------------------------------------------------------

// Expected predetermined address (calculated using CREATE2)
function expectedRouterAddress() internal pure returns (address payable) {
return Create2Utils.calculateCreate2Address(type(TrailsRouter).creationCode, Create2Utils.standardSalt());
function expectedRouterAddress(address multicall3) internal pure returns (address payable) {
return Create2Utils.calculateCreate2Address(
abi.encodePacked(type(TrailsRouter).creationCode, abi.encode(multicall3)), Create2Utils.standardSalt()
);
}

// -------------------------------------------------------------------------
Expand All @@ -52,7 +55,7 @@ contract TrailsRouterDeploymentTest is Test {
_deployScript.run();

// Verify TrailsRouter was deployed at the expected address
address payable expectedAddr = expectedRouterAddress();
address payable expectedAddr = expectedRouterAddress(MULTICALL3_ADDRESS);
assertEq(expectedAddr.code.length > 0, true, "TrailsRouter should be deployed");

// Verify the deployed contract is functional
Expand All @@ -68,7 +71,7 @@ contract TrailsRouterDeploymentTest is Test {
_deployScript.run();

// Verify first deployment address
address payable expectedAddr = expectedRouterAddress();
address payable expectedAddr = expectedRouterAddress(MULTICALL3_ADDRESS);
assertEq(expectedAddr.code.length > 0, true, "First deployment: TrailsRouter deployed");

// Re-set the PRIVATE_KEY for second deployment
Expand All @@ -89,7 +92,7 @@ contract TrailsRouterDeploymentTest is Test {
_deployScript.run();

// Get reference to deployed contract
address payable expectedAddr = expectedRouterAddress();
address payable expectedAddr = expectedRouterAddress(MULTICALL3_ADDRESS);
TrailsRouter router = TrailsRouter(expectedAddr);

// Verify contract is deployed and functional
Expand Down
9 changes: 6 additions & 3 deletions test/script/TrailsRouterShim.s.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Deploy as TrailsRouterShimDeploy} from "script/TrailsRouterShim.s.sol";
import {TrailsRouterShim} from "src/TrailsRouterShim.sol";
import {TrailsRouter} from "src/TrailsRouter.sol";
import {Create2Utils} from "../utils/Create2Utils.sol";
import {MULTICALL3_ADDRESS} from "../mocks/MockMulticall3.sol";

// -----------------------------------------------------------------------------
// Test Contract
Expand All @@ -26,12 +27,14 @@ contract TrailsRouterShimDeploymentTest is Test {
// -------------------------------------------------------------------------

// Expected predetermined addresses (calculated using CREATE2)
function expectedRouterAddress() internal pure returns (address payable) {
return Create2Utils.calculateCreate2Address(type(TrailsRouter).creationCode, Create2Utils.standardSalt());
function expectedRouterAddress(address multicall3) internal pure returns (address payable) {
return Create2Utils.calculateCreate2Address(
abi.encodePacked(type(TrailsRouter).creationCode, abi.encode(multicall3)), Create2Utils.standardSalt()
);
}

function expectedShimAddress() internal pure returns (address payable) {
address routerAddr = expectedRouterAddress();
address routerAddr = expectedRouterAddress(MULTICALL3_ADDRESS);
bytes memory shimInitCode = abi.encodePacked(type(TrailsRouterShim).creationCode, abi.encode(routerAddr));
return Create2Utils.calculateCreate2Address(shimInitCode, Create2Utils.standardSalt());
}
Expand Down