mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-11 15:08:09 -05:00
Compare commits
1 Commits
revert_mon
...
feat/forwa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82af544cbb |
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
78
contracts/src/misc/Forwarder.sol
Normal file
78
contracts/src/misc/Forwarder.sol
Normal 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);
|
||||
}
|
||||
}
|
||||
68
contracts/src/test/Forwarder.t.sol
Normal file
68
contracts/src/test/Forwarder.t.sol
Normal 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");
|
||||
}
|
||||
}
|
||||
15
contracts/src/test/mocks/MockTarget.sol
Normal file
15
contracts/src/test/mocks/MockTarget.sol
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user