mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-12 07:28:08 -05:00
Compare commits
2 Commits
v4.0.22
...
feat/forwa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82af544cbb | ||
|
|
b4cb30e2a1 |
@@ -39,6 +39,12 @@ var (
|
||||
L2WithdrawERC721Sig common.Hash
|
||||
L2WithdrawERC1155Sig common.Hash
|
||||
|
||||
// batch nft sigs
|
||||
L1BatchDepositERC721Sig common.Hash
|
||||
L1BatchDepositERC1155Sig common.Hash
|
||||
L2BatchWithdrawERC721Sig common.Hash
|
||||
L2BatchWithdrawERC1155Sig common.Hash
|
||||
|
||||
// scroll mono repo
|
||||
|
||||
// ScrollChainABI holds information about ScrollChain's context and available invokable methods.
|
||||
@@ -116,6 +122,12 @@ func init() {
|
||||
L2ERC1155GatewayABI, _ = L2ERC1155GatewayMetaData.GetAbi()
|
||||
L2WithdrawERC1155Sig = L2ERC1155GatewayABI.Events["WithdrawERC1155"].ID
|
||||
|
||||
// batch nft events
|
||||
L1BatchDepositERC721Sig = L1ERC721GatewayABI.Events["BatchDepositERC721"].ID
|
||||
L1BatchDepositERC1155Sig = L1ERC1155GatewayABI.Events["BatchDepositERC1155"].ID
|
||||
L2BatchWithdrawERC721Sig = L2ERC721GatewayABI.Events["BatchWithdrawERC721"].ID
|
||||
L2BatchWithdrawERC1155Sig = L2ERC1155GatewayABI.Events["BatchWithdrawERC1155"].ID
|
||||
|
||||
// scroll monorepo
|
||||
ScrollChainABI, _ = ScrollChainMetaData.GetAbi()
|
||||
ScrollChainV2ABI, _ = ScrollChainV2MetaData.GetAbi()
|
||||
@@ -277,6 +289,23 @@ type ERC1155MessageEvent struct {
|
||||
Amount *big.Int
|
||||
}
|
||||
|
||||
type BatchERC721MessageEvent struct {
|
||||
L1Token common.Address
|
||||
L2Token common.Address
|
||||
From common.Address
|
||||
To common.Address
|
||||
TokenIDs []*big.Int
|
||||
}
|
||||
|
||||
type BatchERC1155MessageEvent struct {
|
||||
L1Token common.Address
|
||||
L2Token common.Address
|
||||
From common.Address
|
||||
To common.Address
|
||||
TokenIDs []*big.Int
|
||||
TokenAmounts []*big.Int
|
||||
}
|
||||
|
||||
// scroll monorepo
|
||||
|
||||
// L1SentMessageEvent represents a SentMessage event raised by the L1ScrollMessenger contract.
|
||||
|
||||
@@ -2,6 +2,8 @@ package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -108,7 +110,43 @@ func ParseBackendL1EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedM
|
||||
}
|
||||
// since every deposit event will emit after a sent event, so can use this msg_hash as next withdraw event's msg_hash
|
||||
msgHash = ComputeMessageHash(event.Sender, event.Target, event.Value, event.MessageNonce, event.Message).Hex()
|
||||
|
||||
case backendabi.L1BatchDepositERC721Sig:
|
||||
event := backendabi.BatchERC721MessageEvent{}
|
||||
err := UnpackLog(backendabi.L1ERC721GatewayABI, &event, "BatchDepositERC721", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack BatchDepositERC721 event", "err", err)
|
||||
return l1CrossMsg, relayedMsgs, err
|
||||
}
|
||||
l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{
|
||||
Height: vlog.BlockNumber,
|
||||
Sender: event.From.String(),
|
||||
Target: event.To.String(),
|
||||
Asset: int(orm.ERC721),
|
||||
Layer1Hash: vlog.TxHash.Hex(),
|
||||
Layer1Token: event.L1Token.Hex(),
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
TokenIDs: convertBigIntArrayToString(event.TokenIDs),
|
||||
MsgHash: msgHash,
|
||||
})
|
||||
case backendabi.L1BatchDepositERC1155Sig:
|
||||
event := backendabi.BatchERC1155MessageEvent{}
|
||||
err := UnpackLog(backendabi.L1ERC1155GatewayABI, &event, "BatchDepositERC1155", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack BatchDepositERC1155 event", "err", err)
|
||||
return l1CrossMsg, relayedMsgs, err
|
||||
}
|
||||
l1CrossMsg = append(l1CrossMsg, &orm.CrossMsg{
|
||||
Height: vlog.BlockNumber,
|
||||
Sender: event.From.String(),
|
||||
Target: event.To.String(),
|
||||
Asset: int(orm.ERC1155),
|
||||
Layer1Hash: vlog.TxHash.Hex(),
|
||||
Layer1Token: event.L1Token.Hex(),
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
TokenIDs: convertBigIntArrayToString(event.TokenIDs),
|
||||
TokenAmounts: convertBigIntArrayToString(event.TokenAmounts),
|
||||
MsgHash: msgHash,
|
||||
})
|
||||
case backendabi.L1RelayedMessageEventSignature:
|
||||
event := backendabi.L1RelayedMessageEvent{}
|
||||
err := UnpackLog(backendabi.L1ScrollMessengerABI, &event, "RelayedMessage", vlog)
|
||||
@@ -172,6 +210,7 @@ func ParseBackendL2EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedM
|
||||
Layer2Hash: vlog.TxHash.Hex(),
|
||||
Layer1Token: event.L1Token.Hex(),
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash,
|
||||
})
|
||||
case backendabi.L2WithdrawERC721Sig:
|
||||
event := backendabi.ERC721MessageEvent{}
|
||||
@@ -190,6 +229,7 @@ func ParseBackendL2EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedM
|
||||
Layer1Token: event.L1Token.Hex(),
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
TokenIDs: event.TokenID.String(),
|
||||
MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash,
|
||||
})
|
||||
case backendabi.L2WithdrawERC1155Sig:
|
||||
event := backendabi.ERC1155MessageEvent{}
|
||||
@@ -209,6 +249,46 @@ func ParseBackendL2EventLogs(logs []types.Log) ([]*orm.CrossMsg, []*orm.RelayedM
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
TokenIDs: event.TokenID.String(),
|
||||
Amount: event.Amount.String(),
|
||||
MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash,
|
||||
})
|
||||
case backendabi.L2BatchWithdrawERC721Sig:
|
||||
event := backendabi.BatchERC721MessageEvent{}
|
||||
err := UnpackLog(backendabi.L2ERC721GatewayABI, &event, "BatchWithdrawERC721", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack BatchWithdrawERC721 event", "err", err)
|
||||
return l2CrossMsg, relayedMsgs, l2SentMsgs, err
|
||||
}
|
||||
l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex()
|
||||
l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{
|
||||
Height: vlog.BlockNumber,
|
||||
Sender: event.From.String(),
|
||||
Target: event.To.String(),
|
||||
Asset: int(orm.ERC721),
|
||||
Layer1Hash: vlog.TxHash.Hex(),
|
||||
Layer1Token: event.L1Token.Hex(),
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
TokenIDs: convertBigIntArrayToString(event.TokenIDs),
|
||||
MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash,
|
||||
})
|
||||
case backendabi.L2BatchWithdrawERC1155Sig:
|
||||
event := backendabi.BatchERC1155MessageEvent{}
|
||||
err := UnpackLog(backendabi.L2ERC1155GatewayABI, &event, "BatchWithdrawERC1155", vlog)
|
||||
if err != nil {
|
||||
log.Warn("Failed to unpack BatchWithdrawERC1155 event", "err", err)
|
||||
return l2CrossMsg, relayedMsgs, l2SentMsgs, err
|
||||
}
|
||||
l2SentMsgs[len(l2SentMsgs)-1].OriginalSender = event.From.Hex()
|
||||
l2CrossMsg = append(l2CrossMsg, &orm.CrossMsg{
|
||||
Height: vlog.BlockNumber,
|
||||
Sender: event.From.String(),
|
||||
Target: event.To.String(),
|
||||
Asset: int(orm.ERC1155),
|
||||
Layer1Hash: vlog.TxHash.Hex(),
|
||||
Layer1Token: event.L1Token.Hex(),
|
||||
Layer2Token: event.L2Token.Hex(),
|
||||
TokenIDs: convertBigIntArrayToString(event.TokenIDs),
|
||||
TokenAmounts: convertBigIntArrayToString(event.TokenAmounts),
|
||||
MsgHash: l2SentMsgs[len(l2SentMsgs)-1].MsgHash,
|
||||
})
|
||||
case backendabi.L2SentMessageEventSignature:
|
||||
event := backendabi.L2SentMessageEvent{}
|
||||
@@ -304,3 +384,13 @@ func ParseBatchInfoFromScrollChain(ctx context.Context, client *ethclient.Client
|
||||
}
|
||||
return rollupBatches, nil
|
||||
}
|
||||
|
||||
func convertBigIntArrayToString(array []*big.Int) string {
|
||||
stringArray := make([]string, len(array))
|
||||
for i, num := range array {
|
||||
stringArray[i] = num.String()
|
||||
}
|
||||
|
||||
result := strings.Join(stringArray, ", ")
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var tag = "v4.0.22"
|
||||
var tag = "v4.0.23"
|
||||
|
||||
var commit = func() string {
|
||||
if info, ok := debug.ReadBuildInfo(); ok {
|
||||
|
||||
@@ -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