Compare commits

...

1 Commits

Author SHA1 Message Date
zimpha
82af544cbb move Forwarder contract from PR 528 2023-07-18 12:16:53 +08:00
5 changed files with 163 additions and 2 deletions

View File

@@ -9,7 +9,7 @@ libraries = [] # a list of deploy
cache = true # whether to cache builds or not
force = true # whether to ignore the cache (clean build)
evm_version = 'london' # the evm version (by hardfork name)
solc_version = '0.8.10' # override for the solc version (setting this ignores `auto_detect_solc`)
solc_version = '0.8.16' # override for the solc version (setting this ignores `auto_detect_solc`)
optimizer = true # enable or disable the solc optimizer
optimizer_runs = 200 # the number of optimizer runs
verbosity = 2 # the verbosity of tests

View File

@@ -22,7 +22,7 @@ const RINKEBY_PRIVATE_KEY = process.env.RINKEBY_PRIVATE_KEY || "1".repeat(64);
const L1_DEPLOYER_PRIVATE_KEY = process.env.L1_DEPLOYER_PRIVATE_KEY || "1".repeat(64);
const L2_DEPLOYER_PRIVATE_KEY = process.env.L2_DEPLOYER_PRIVATE_KEY || "1".repeat(64);
const SOLC_DEFAULT = "0.8.10";
const SOLC_DEFAULT = "0.8.16";
// try use forge config
let foundry: any;

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.16;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
// solhint-disable no-inline-assembly
/// @notice This contract is designed as a proxy contract to forward contract call to some other
/// target contract. There are two roles in the contract: the `owner` is the super admin and the
/// `admin`. The `owner` can change the address of the `admin`. Both roles can forward contract call.
contract Forwarder is Ownable {
/**********
* Events *
**********/
/// @notice Emitted when forward call happens.
/// @param caller The address of the caller.
/// @param target The address of the target contract.
/// @param value The value passed to the target contract.
/// @param data The calldata passed to the target contract.
event Forwarded(address indexed caller, address indexed target, uint256 value, bytes data);
/// @notice Emitted when the address of admin is updated.
/// @param oldAdmin The address of the old admin.
/// @param newAdmin The address of the new admin.
event SetAdmin(address indexed oldAdmin, address indexed newAdmin);
/*************
* Variables *
*************/
/// @notice The address of contract admin.
address public admin;
/***************
* Constructor *
***************/
constructor(address _admin) {
admin = _admin;
emit SetAdmin(address(0), _admin);
}
/************************
* Restricted Functions *
************************/
/// @notice Update the address of admin.
/// @param _newAdmin The address of the new admin.
function setAdmin(address _newAdmin) external onlyOwner {
address _oldAdmin = admin;
admin = _newAdmin;
emit SetAdmin(_oldAdmin, _newAdmin);
}
/// @notice Forward calldata to some target contract.
/// @param _target The address of the target contract.
/// @param _data The data forwarded to the target contract.
function forward(address _target, bytes calldata _data) external payable {
require(msg.sender == owner() || msg.sender == admin, "only owner or admin");
(bool success, ) = _target.call{value: msg.value}(_data);
// bubble up revert reason
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
emit Forwarded(msg.sender, _target, msg.value, _data);
}
}

View File

@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.16;
import {DSTestPlus} from "solmate/test/utils/DSTestPlus.sol";
import {WETH} from "solmate/tokens/WETH.sol";
import {MockTarget} from "./mocks/MockTarget.sol";
import {Forwarder} from "../misc/Forwarder.sol";
import {IL1ScrollMessenger, L1ScrollMessenger} from "../L1/L1ScrollMessenger.sol";
contract ForwarderTest is DSTestPlus {
MockTarget public target;
Forwarder public forwarder;
L1ScrollMessenger internal l1Messenger;
address public admin = address(2);
address public superAdmin = address(3);
function setUp() public {
target = new MockTarget();
forwarder = new Forwarder(admin);
forwarder.transferOwnership(superAdmin);
l1Messenger = new L1ScrollMessenger();
l1Messenger.initialize(address(0), address(0), address(0), address(0));
l1Messenger.transferOwnership(address(forwarder));
}
function testAdminFail() external {
hevm.expectRevert("only owner or admin");
forwarder.forward(address(l1Messenger), hex"00");
hevm.expectRevert("Ownable: caller is not the owner");
forwarder.setAdmin(address(0));
}
function testAdmin() external {
// cast calldata "transferOwnership(address)" 0x0000000000000000000000000000000000000005
// 0xf2fde38b0000000000000000000000000000000000000000000000000000000000000005
hevm.startPrank(admin);
forwarder.forward(
address(l1Messenger),
hex"f2fde38b0000000000000000000000000000000000000000000000000000000000000006"
);
assertEq(address(6), l1Messenger.owner());
hevm.stopPrank();
}
function testForwardSuperAdmin() external {
hevm.startPrank(superAdmin);
forwarder.forward(
address(l1Messenger),
hex"f2fde38b0000000000000000000000000000000000000000000000000000000000000006"
);
assertEq(address(6), l1Messenger.owner());
forwarder.setAdmin(address(0));
assertEq(forwarder.admin(), address(0));
}
function testNestedRevert() external {
hevm.startPrank(superAdmin);
hevm.expectRevert("test error");
forwarder.forward(address(target), hex"38df7677");
}
}

View File

@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.16;
contract MockTarget {
event ABC(uint256);
function err() external pure {
revert("test error");
}
function succeed() external {
emit ABC(1);
}
}