Compare commits

..

7 Commits

Author SHA1 Message Date
georgehao
816a3b4a15 fix(coordinator&prover): jwt token expired bug (#736)
Co-authored-by: colinlyguo <colinlyguo@scroll.io>
2023-08-06 19:56:16 +08:00
HAOYUatHZ
11fac0330f feat(coordinator): add log to valid proof result (#734) 2023-08-06 17:36:02 +08:00
Xi Lin
e2185ffe20 refactor(contracts): OZ-L1-L03 Code Redundancy, OZ-L1-N15 Unused Imports and OZ-L2-N02 Unused Imports (#698)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 10:21:18 +02:00
ChuhanJin
b0628b67ee fix(bridge-history-api): fix txhashes api error (#732)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 09:51:37 +02:00
Xi Lin
bb0a0d0d09 feat(contracts): better access control of the ScrollChain (#700)
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
2023-08-06 09:43:39 +02:00
Péter Garamvölgyi
b977e5a62f fix: handle importGenesisBatch in bridge-history calldata decoder (#731) 2023-08-06 07:41:29 +02:00
Péter Garamvölgyi
1b77f9044a fix(bridge-history): do not fail if all proofs in DB are empty (#730) 2023-08-06 06:48:22 +02:00
51 changed files with 485 additions and 324 deletions

View File

@@ -53,11 +53,11 @@ func (m *MsgProofUpdater) Start() {
continue
}
latestBatchIndexWithProof, err := m.l2SentMsgOrm.GetLatestL2SentMsgBatchIndex(m.ctx)
log.Info("latest batc with proof", "batch_index", latestBatchIndexWithProof)
if err != nil {
log.Error("MsgProofUpdater: Can not get latest L2SentMsgBatchIndex: ", "err", err)
continue
}
log.Info("latest batch with proof", "batch_index", latestBatchIndexWithProof)
var start uint64
if latestBatchIndexWithProof < 0 {
start = 1

View File

@@ -204,7 +204,7 @@ func (c *CrossMsg) DeleteL1CrossMsgAfterHeight(ctx context.Context, height uint6
// GetL2CrossMsgByHash returns layer2 cross message by given hash
func (c *CrossMsg) GetL2CrossMsgByHash(ctx context.Context, l2Hash common.Hash) (*CrossMsg, error) {
var result CrossMsg
err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer2_hash = ? AND msg_type = ?", l2Hash.String(), Layer1Msg).First(&result).Error
err := c.db.WithContext(ctx).Model(&CrossMsg{}).Where("layer2_hash = ? AND msg_type = ?", l2Hash.String(), Layer2Msg).First(&result).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil

View File

@@ -2,6 +2,7 @@ package orm
import (
"context"
"errors"
"fmt"
"time"
@@ -102,6 +103,9 @@ func (l *L2SentMsg) GetLatestL2SentMsgBatchIndex(ctx context.Context) (int64, er
Select("batch_index").
First(&result).
Error
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
return -1, nil
}
if err != nil {
return -1, fmt.Errorf("L2SentMsg.GetLatestL2SentMsgBatchIndex error: %w", err)
}

View File

@@ -1,7 +1,6 @@
package utils
import (
"bytes"
"context"
"encoding/binary"
"errors"
@@ -76,6 +75,14 @@ func GetBatchRangeFromCalldataV2(calldata []byte) (uint64, uint64, uint64, error
method := backendabi.ScrollChainV2ABI.Methods["commitBatch"]
values, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
// special case: import genesis batch
method = backendabi.ScrollChainV2ABI.Methods["importGenesisBatch"]
_, err2 := method.Inputs.Unpack(calldata[4:])
if err2 == nil {
// genesis batch
return 0, 0, 0, nil
}
// none of "commitBatch" and "importGenesisBatch" match, give up
return 0, 0, 0, err
}
args := commitBatchArgs{}
@@ -110,48 +117,3 @@ func GetBatchRangeFromCalldataV2(calldata []byte) (uint64, uint64, uint64, error
return batchIndex, startBlock, finishBlock, err
}
// GetBatchRangeFromCalldataV1 find the block range from calldata, both inclusive.
func GetBatchRangeFromCalldataV1(calldata []byte) ([]uint64, []uint64, []uint64, error) {
var batchIndices []uint64
var startBlocks []uint64
var finishBlocks []uint64
if bytes.Equal(calldata[0:4], common.Hex2Bytes("cb905499")) {
// commitBatches
method := backendabi.ScrollChainABI.Methods["commitBatches"]
values, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
args := make([]backendabi.IScrollChainBatch, len(values))
err = method.Inputs.Copy(&args, values)
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
for i := 0; i < len(args); i++ {
batchIndices = append(batchIndices, args[i].BatchIndex)
startBlocks = append(startBlocks, args[i].Blocks[0].BlockNumber)
finishBlocks = append(finishBlocks, args[i].Blocks[len(args[i].Blocks)-1].BlockNumber)
}
} else if bytes.Equal(calldata[0:4], common.Hex2Bytes("8c73235d")) {
// commitBatch
method := backendabi.ScrollChainABI.Methods["commitBatch"]
values, err := method.Inputs.Unpack(calldata[4:])
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
args := backendabi.IScrollChainBatch{}
err = method.Inputs.Copy(&args, values)
if err != nil {
return batchIndices, startBlocks, finishBlocks, err
}
batchIndices = append(batchIndices, args.BatchIndex)
startBlocks = append(startBlocks, args.Blocks[0].BlockNumber)
finishBlocks = append(finishBlocks, args.Blocks[len(args.Blocks)-1].BlockNumber)
} else {
return batchIndices, startBlocks, finishBlocks, errors.New("invalid selector")
}
return batchIndices, startBlocks, finishBlocks, nil
}

View File

@@ -33,4 +33,11 @@ func TestGetBatchRangeFromCalldataV2(t *testing.T) {
assert.Equal(t, start, uint64(10))
assert.Equal(t, finish, uint64(20))
assert.Equal(t, batchIndex, uint64(2))
// genesis batch
batchIndex, start, finish, err = utils.GetBatchRangeFromCalldataV2(common.Hex2Bytes("3fdeecb200000000000000000000000000000000000000000000000000000000000000402dcb5308098d24a37fc1487a229fcedb09fa4343ede39cbad365bc925535bb09000000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000c252bc9780c4d83cf11f14b8cd03c92c4d18ce07710ba836d31d12da216c8330000000000000000000000000000000000000000000000000000000000000000000000000000000"))
assert.NoError(t, err)
assert.Equal(t, start, uint64(0))
assert.Equal(t, finish, uint64(0))
assert.Equal(t, batchIndex, uint64(0))
}

View File

@@ -83,7 +83,9 @@ func (c *Cmd) Write(data []byte) (int, error) {
out := string(data)
if verbose || c.openLog {
fmt.Printf("%s:\n\t%v", c.name, out)
} else if strings.Contains(strings.ToLower(out), "error") || strings.Contains(strings.ToLower(out), "warning") || strings.Contains(strings.ToLower(out), "info") {
} else if strings.Contains(strings.ToLower(out), "error") ||
strings.Contains(strings.ToLower(out), "warning") ||
strings.Contains(strings.ToLower(out), "info") {
fmt.Printf("%s:\n\t%v", c.name, out)
}
go c.checkFuncs.IterCb(func(_ string, value interface{}) {

View File

@@ -5,7 +5,7 @@ import (
"runtime/debug"
)
var tag = "v4.1.7"
var tag = "v4.1.12"
var commit = func() string {
if info, ok := debug.ReadBuildInfo(); ok {

View File

@@ -214,6 +214,34 @@ function onDropMessage(bytes _message) external payable
|---|---|---|
| _message | bytes | undefined |
### owner
```solidity
function owner() external view returns (address)
```
*Returns the address of the current owner.*
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | address | undefined |
### renounceOwnership
```solidity
function renounceOwnership() external nonpayable
```
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
### router
```solidity
@@ -231,6 +259,22 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _0 | address | undefined |
### transferOwnership
```solidity
function transferOwnership(address newOwner) external nonpayable
```
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
#### Parameters
| Name | Type | Description |
|---|---|---|
| newOwner | address | undefined |
## Events
@@ -293,6 +337,23 @@ event Initialized(uint8 version)
|---|---|---|
| version | uint8 | undefined |
### OwnershipTransferred
```solidity
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
```
#### Parameters
| Name | Type | Description |
|---|---|---|
| previousOwner `indexed` | address | undefined |
| newOwner `indexed` | address | undefined |
### RefundERC20
```solidity

View File

@@ -212,6 +212,34 @@ function onDropMessage(bytes _message) external payable
|---|---|---|
| _message | bytes | undefined |
### owner
```solidity
function owner() external view returns (address)
```
*Returns the address of the current owner.*
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | address | undefined |
### renounceOwnership
```solidity
function renounceOwnership() external nonpayable
```
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
### router
```solidity
@@ -229,6 +257,22 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _0 | address | undefined |
### transferOwnership
```solidity
function transferOwnership(address newOwner) external nonpayable
```
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
#### Parameters
| Name | Type | Description |
|---|---|---|
| newOwner | address | undefined |
## Events
@@ -291,6 +335,23 @@ event Initialized(uint8 version)
|---|---|---|
| version | uint8 | undefined |
### OwnershipTransferred
```solidity
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
```
#### Parameters
| Name | Type | Description |
|---|---|---|
| previousOwner `indexed` | address | undefined |
| newOwner `indexed` | address | undefined |
### RefundERC20
```solidity

View File

@@ -47,7 +47,7 @@ The address of fee vault, collecting cross domain messaging fee.
### initialize
```solidity
function initialize(address _counterpart, address _feeVault) external nonpayable
function initialize(address _counterpart) external nonpayable
```
@@ -59,7 +59,6 @@ function initialize(address _counterpart, address _feeVault) external nonpayable
| Name | Type | Description |
|---|---|---|
| _counterpart | address | undefined |
| _feeVault | address | undefined |
### isL1MessageExecuted

View File

@@ -128,6 +128,34 @@ The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|---|---|---|
| _0 | address | undefined |
### owner
```solidity
function owner() external view returns (address)
```
*Returns the address of the current owner.*
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | address | undefined |
### renounceOwnership
```solidity
function renounceOwnership() external nonpayable
```
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
### router
```solidity
@@ -162,6 +190,22 @@ The address of ScrollStandardERC20Factory.
|---|---|---|
| _0 | address | undefined |
### transferOwnership
```solidity
function transferOwnership(address newOwner) external nonpayable
```
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
#### Parameters
| Name | Type | Description |
|---|---|---|
| newOwner | address | undefined |
### withdrawERC20
```solidity
@@ -260,6 +304,23 @@ event Initialized(uint8 version)
|---|---|---|
| version | uint8 | undefined |
### OwnershipTransferred
```solidity
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
```
#### Parameters
| Name | Type | Description |
|---|---|---|
| previousOwner `indexed` | address | undefined |
| newOwner `indexed` | address | undefined |
### WithdrawERC20
```solidity

View File

@@ -161,6 +161,34 @@ The address of corresponding L1ScrollMessenger/L2ScrollMessenger contract.
|---|---|---|
| _0 | address | undefined |
### owner
```solidity
function owner() external view returns (address)
```
*Returns the address of the current owner.*
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | address | undefined |
### renounceOwnership
```solidity
function renounceOwnership() external nonpayable
```
*Leaves the contract without owner. It will not be possible to call `onlyOwner` functions. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby disabling any functionality that is only available to the owner.*
### router
```solidity
@@ -178,6 +206,22 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _0 | address | undefined |
### transferOwnership
```solidity
function transferOwnership(address newOwner) external nonpayable
```
*Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.*
#### Parameters
| Name | Type | Description |
|---|---|---|
| newOwner | address | undefined |
### withdrawERC20
```solidity
@@ -276,6 +320,23 @@ event Initialized(uint8 version)
|---|---|---|
| version | uint8 | undefined |
### OwnershipTransferred
```solidity
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)
```
#### Parameters
| Name | Type | Description |
|---|---|---|
| previousOwner `indexed` | address | undefined |
| newOwner `indexed` | address | undefined |
### WithdrawERC20
```solidity

View File

@@ -1,7 +1,6 @@
/* eslint-disable node/no-unpublished-import */
/* eslint-disable node/no-missing-import */
import { constants } from "ethers";
import { concat } from "ethers/lib/utils";
import { ethers } from "hardhat";
import { ScrollChain, L1MessageQueue } from "../typechain";
@@ -28,7 +27,7 @@ describe("ScrollChain", async () => {
await chain.deployed();
await chain.initialize(queue.address, constants.AddressZero, 44);
await chain.updateSequencer(deployer.address, true);
await chain.addSequencer(deployer.address);
await queue.initialize(
constants.AddressZero,
chain.address,

View File

@@ -66,8 +66,8 @@ contract InitializeL1BridgeContracts is Script {
L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR,
MAX_L2_TX_IN_CHUNK
);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).updateSequencer(L1_ROLLUP_OPERATOR_ADDR, true);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).updateProver(L1_ROLLUP_OPERATOR_ADDR, true);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addSequencer(L1_ROLLUP_OPERATOR_ADDR);
ScrollChain(L1_SCROLL_CHAIN_PROXY_ADDR).addProver(L1_ROLLUP_OPERATOR_ADDR);
// initialize L2GasPriceOracle
L2GasPriceOracle(L2_GAS_PRICE_ORACLE_PROXY_ADDR).initialize(

View File

@@ -65,10 +65,7 @@ contract InitializeL2BridgeContracts is Script {
L1GasPriceOracle(L1_GAS_PRICE_ORACLE_ADDR).updateWhitelist(L2_WHITELIST_ADDR);
// initialize L2ScrollMessenger
L2ScrollMessenger(payable(L2_SCROLL_MESSENGER_PROXY_ADDR)).initialize(
L1_SCROLL_MESSENGER_PROXY_ADDR,
L2_TX_FEE_VAULT_ADDR
);
L2ScrollMessenger(payable(L2_SCROLL_MESSENGER_PROXY_ADDR)).initialize(L1_SCROLL_MESSENGER_PROXY_ADDR);
// initialize L2GatewayRouter
L2GatewayRouter(L2_GATEWAY_ROUTER_PROXY_ADDR).initialize(

View File

@@ -2,15 +2,12 @@
pragma solidity =0.8.16;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IScrollChain} from "./rollup/IScrollChain.sol";
import {IL1MessageQueue} from "./rollup/IL1MessageQueue.sol";
import {IL1ScrollMessenger} from "./IL1ScrollMessenger.sol";
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
import {IScrollMessenger} from "../libraries/IScrollMessenger.sol";
import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
import {AddressAliasHelper} from "../libraries/common/AddressAliasHelper.sol";
import {WithdrawTrieVerifier} from "../libraries/verifier/WithdrawTrieVerifier.sol";
import {IMessageDropCallback} from "../libraries/callbacks/IMessageDropCallback.sol";
@@ -28,7 +25,7 @@ import {IMessageDropCallback} from "../libraries/callbacks/IMessageDropCallback.
///
/// @dev All deposited Ether (including `WETH` deposited throng `L1WETHGateway`) will locked in
/// this contract.
contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1ScrollMessenger {
contract L1ScrollMessenger is ScrollMessengerBase, IL1ScrollMessenger {
/***********
* Structs *
***********/
@@ -97,8 +94,7 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
address _rollup,
address _messageQueue
) public initializer {
PausableUpgradeable.__Pausable_init();
ScrollMessengerBase._initialize(_counterpart, _feeVault);
ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, _feeVault);
rollup = _rollup;
messageQueue = _messageQueue;
@@ -295,17 +291,6 @@ contract L1ScrollMessenger is PausableUpgradeable, ScrollMessengerBase, IL1Scrol
* Restricted Functions *
************************/
/// @notice Pause the contract
/// @dev This function can only called by contract owner.
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/// @notice Update max replay times.
/// @dev This function can only called by contract owner.
/// @param _maxReplayTimes The new max replay times.

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
@@ -18,7 +17,7 @@ import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
/// finalize withdraw the tokens from layer 2.
/// @dev The deposited tokens are held in this gateway. On finalizing withdraw, the corresponding
/// tokens will be transfer to the recipient directly.
contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20Gateway {
contract L1CustomERC20Gateway is L1ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/**********
@@ -56,7 +55,6 @@ contract L1CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L1ERC20G
) external initializer {
require(_router != address(0), "zero router address");
OwnableUpgradeable.__Ownable_init();
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
}

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
import {ERC1155HolderUpgradeable, ERC1155ReceiverUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
@@ -20,13 +19,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// NFT will be transfer to the recipient directly.
///
/// This will be changed if we have more specific scenarios.
contract L1ERC1155Gateway is
OwnableUpgradeable,
ERC1155HolderUpgradeable,
ScrollGatewayBase,
IL1ERC1155Gateway,
IMessageDropCallback
{
contract L1ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC1155Gateway, IMessageDropCallback {
/**********
* Events *
**********/
@@ -55,7 +48,6 @@ contract L1ERC1155Gateway is
/// @param _counterpart The address of L2ERC1155Gateway in L2.
/// @param _messenger The address of L1ScrollMessenger.
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC1155HolderUpgradeable.__ERC1155Holder_init();
ERC1155ReceiverUpgradeable.__ERC1155Receiver_init();

View File

@@ -2,14 +2,12 @@
pragma solidity ^0.8.16;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IScrollMessenger} from "../../libraries/IScrollMessenger.sol";
import {ScrollConstants} from "../../libraries/constants/ScrollConstants.sol";
@@ -19,7 +17,7 @@ import {IMessageDropCallback} from "../../libraries/callbacks/IMessageDropCallba
// solhint-disable no-empty-blocks
abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, ScrollGatewayBase {
using SafeERC20 for IERC20;
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
* Variables *
@@ -75,7 +73,7 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
// @note can possible trigger reentrant call to this contract or messenger,
// but it seems not a big problem.
IERC20(_l1Token).safeTransfer(_to, _amount);
IERC20Upgradeable(_l1Token).safeTransfer(_to, _amount);
_doCallback(_to, _data);
@@ -96,7 +94,7 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
// do dome check for each custom gateway
_beforeDropMessage(_token, _receiver, _amount);
IERC20(_token).safeTransfer(_receiver, _amount);
IERC20Upgradeable(_token).safeTransfer(_receiver, _amount);
emit RefundERC20(_token, _receiver, _amount);
}
@@ -154,9 +152,9 @@ abstract contract L1ERC20Gateway is IL1ERC20Gateway, IMessageDropCallback, Scrol
_amount = IL1GatewayRouter(msg.sender).requestERC20(_from, _token, _amount);
} else {
// common practice to handle fee on transfer token.
uint256 _before = IERC20(_token).balanceOf(address(this));
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
uint256 _after = IERC20(_token).balanceOf(address(this));
uint256 _before = IERC20Upgradeable(_token).balanceOf(address(this));
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
uint256 _after = IERC20Upgradeable(_token).balanceOf(address(this));
// no unchecked here, since some weird token may return arbitrary balance.
_amount = _after - _before;
}

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
@@ -20,13 +19,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// NFT will be transfer to the recipient directly.
///
/// This will be changed if we have more specific scenarios.
contract L1ERC721Gateway is
OwnableUpgradeable,
ERC721HolderUpgradeable,
ScrollGatewayBase,
IL1ERC721Gateway,
IMessageDropCallback
{
contract L1ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC721Gateway, IMessageDropCallback {
/**********
* Events *
**********/
@@ -55,7 +48,6 @@ contract L1ERC721Gateway is
/// @param _counterpart The address of L2ERC721Gateway in L2.
/// @param _messenger The address of L1ScrollMessenger.
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC721HolderUpgradeable.__ERC721Holder_init();
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);

View File

@@ -2,8 +2,6 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IL2ETHGateway} from "../../L2/gateways/IL2ETHGateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
@@ -18,7 +16,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// finalize withdraw ETH from layer 2.
/// @dev The deposited ETH tokens are held in this gateway. On finalizing withdraw, the corresponding
/// ETH will be transfer to the recipient directly.
contract L1ETHGateway is Initializable, ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback {
contract L1ETHGateway is ScrollGatewayBase, IL1ETHGateway, IMessageDropCallback {
/***************
* Constructor *
***************/

View File

@@ -6,8 +6,6 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IScrollGateway} from "../../libraries/gateway/IScrollGateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
import {IL1ETHGateway} from "./IL1ETHGateway.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
import {IL1GatewayRouter} from "./IL1GatewayRouter.sol";

View File

@@ -2,12 +2,9 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {ClonesUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/ClonesUpgradeable.sol";
import {IERC20MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import {IERC20Metadata} from "../../interfaces/IERC20Metadata.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
import {IL1ERC20Gateway} from "./IL1ERC20Gateway.sol";
@@ -21,9 +18,7 @@ import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
/// @dev The deposited ERC20 tokens are held in this gateway. On finalizing withdraw, the corresponding
/// token will be transfer to the recipient directly. Any ERC20 that requires non-standard functionality
/// should use a separate gateway.
contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20 for IERC20;
contract L1StandardERC20Gateway is L1ERC20Gateway {
/*************
* Variables *
*************/
@@ -81,7 +76,7 @@ contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gate
// we can calculate the l2 address directly.
bytes32 _salt = keccak256(abi.encodePacked(counterpart, keccak256(abi.encodePacked(_l1Token))));
return Clones.predictDeterministicAddress(l2TokenImplementation, _salt, l2TokenFactory);
return ClonesUpgradeable.predictDeterministicAddress(l2TokenImplementation, _salt, l2TokenFactory);
}
/**********************
@@ -143,9 +138,9 @@ contract L1StandardERC20Gateway is Initializable, ScrollGatewayBase, L1ERC20Gate
_l2Token = getL2ERC20Address(_token);
// passing symbol/name/decimal in order to deploy in L2.
string memory _symbol = IERC20Metadata(_token).symbol();
string memory _name = IERC20Metadata(_token).name();
uint8 _decimals = IERC20Metadata(_token).decimals();
string memory _symbol = IERC20MetadataUpgradeable(_token).symbol();
string memory _name = IERC20MetadataUpgradeable(_token).name();
uint8 _decimals = IERC20MetadataUpgradeable(_token).decimals();
_l2Data = abi.encode(true, abi.encode(_data, abi.encode(_symbol, _name, _decimals)));
} else {
_l2Data = abi.encode(false, _data);

View File

@@ -2,10 +2,6 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IWETH} from "../../interfaces/IWETH.sol";
import {IL2ERC20Gateway} from "../../L2/gateways/IL2ERC20Gateway.sol";
import {IL1ScrollMessenger} from "../IL1ScrollMessenger.sol";
@@ -21,9 +17,7 @@ import {L1ERC20Gateway} from "./L1ERC20Gateway.sol";
/// as Ether and then the Ether will be sent to the `L1ScrollMessenger` contract.
/// On finalizing withdraw, the Ether will be transfered from `L1ScrollMessenger`, then
/// wrapped as WETH and finally transfer to recipient.
contract L1WETHGateway is Initializable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20 for IERC20;
contract L1WETHGateway is L1ERC20Gateway {
/*************
* Constants *
*************/

View File

@@ -3,6 +3,7 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IL1MessageQueue} from "./IL1MessageQueue.sol";
import {IScrollChain} from "./IScrollChain.sol";
@@ -15,7 +16,7 @@ import {IRollupVerifier} from "../../libraries/verifier/IRollupVerifier.sol";
/// @title ScrollChain
/// @notice This contract maintains data for the Scroll rollup.
contract ScrollChain is OwnableUpgradeable, IScrollChain {
contract ScrollChain is OwnableUpgradeable, PausableUpgradeable, IScrollChain {
/**********
* Events *
**********/
@@ -165,7 +166,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
bytes calldata _parentBatchHeader,
bytes[] memory _chunks,
bytes calldata _skippedL1MessageBitmap
) external override OnlySequencer {
) external override OnlySequencer whenNotPaused {
require(_version == 0, "invalid version");
// check whether the batch is empty
@@ -291,7 +292,7 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
bytes32 _postStateRoot,
bytes32 _withdrawRoot,
bytes calldata _aggrProof
) external override OnlyProver {
) external override OnlyProver whenNotPaused {
require(_prevStateRoot != bytes32(0), "previous state root is zero");
require(_postStateRoot != bytes32(0), "new state root is zero");
@@ -355,24 +356,36 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
* Restricted Functions *
************************/
/// @notice Update the status of sequencer.
/// @dev This function can only called by contract owner.
/// @param _account The address of account to update.
/// @param _status The status of the account to update.
function updateSequencer(address _account, bool _status) external onlyOwner {
isSequencer[_account] = _status;
/// @notice Add an account to the sequencer list.
/// @param _account The address of account to add.
function addSequencer(address _account) external onlyOwner {
isSequencer[_account] = true;
emit UpdateSequencer(_account, _status);
emit UpdateSequencer(_account, true);
}
/// @notice Update the status of prover.
/// @dev This function can only called by contract owner.
/// @param _account The address of account to update.
/// @param _status The status of the account to update.
function updateProver(address _account, bool _status) external onlyOwner {
isProver[_account] = _status;
/// @notice Remove an account from the sequencer list.
/// @param _account The address of account to remove.
function removeSequencer(address _account) external onlyOwner {
isSequencer[_account] = false;
emit UpdateProver(_account, _status);
emit UpdateSequencer(_account, false);
}
/// @notice Add an account to the prover list.
/// @param _account The address of account to add.
function addProver(address _account) external onlyOwner {
isProver[_account] = true;
emit UpdateProver(_account, true);
}
/// @notice Add an account from the prover list.
/// @param _account The address of account to remove.
function removeProver(address _account) external onlyOwner {
isProver[_account] = false;
emit UpdateProver(_account, false);
}
/// @notice Update the address verifier contract.
@@ -393,6 +406,16 @@ contract ScrollChain is OwnableUpgradeable, IScrollChain {
emit UpdateMaxNumL2TxInChunk(_oldMaxNumL2TxInChunk, _maxNumL2TxInChunk);
}
/// @notice Pause the contract
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/**********************
* Internal Functions *
**********************/

View File

@@ -2,12 +2,8 @@
pragma solidity =0.8.16;
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {IL2ScrollMessenger} from "./IL2ScrollMessenger.sol";
import {L2MessageQueue} from "./predeploys/L2MessageQueue.sol";
import {IL1BlockContainer} from "./predeploys/IL1BlockContainer.sol";
import {IL1GasPriceOracle} from "./predeploys/IL1GasPriceOracle.sol";
import {PatriciaMerkleTrieVerifier} from "../libraries/verifier/PatriciaMerkleTrieVerifier.sol";
import {ScrollConstants} from "../libraries/constants/ScrollConstants.sol";
@@ -26,7 +22,7 @@ import {ScrollMessengerBase} from "../libraries/ScrollMessengerBase.sol";
///
/// @dev It should be a predeployed contract on layer 2 and should hold infinite amount
/// of Ether (Specifically, `uint256(-1)`), which can be initialized in Genesis Block.
contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2ScrollMessenger {
contract L2ScrollMessenger is ScrollMessengerBase, IL2ScrollMessenger {
/**********
* Events *
**********/
@@ -68,9 +64,8 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
messageQueue = _messageQueue;
}
function initialize(address _counterpart, address _feeVault) external initializer {
PausableUpgradeable.__Pausable_init();
ScrollMessengerBase._initialize(_counterpart, _feeVault);
function initialize(address _counterpart) external initializer {
ScrollMessengerBase.__ScrollMessengerBase_init(_counterpart, address(0));
maxFailedExecutionTimes = 3;
}
@@ -122,17 +117,6 @@ contract L2ScrollMessenger is ScrollMessengerBase, PausableUpgradeable, IL2Scrol
* Restricted Functions *
************************/
/// @notice Pause the contract
/// @dev This function can only called by contract owner.
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/// @notice Update max failed execution times.
/// @dev This function can only called by contract owner.
/// @param _maxFailedExecutionTimes The new max failed execution times.

View File

@@ -2,21 +2,18 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC20} from "../../libraries/token/IScrollERC20.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC20Upgradeable} from "../../libraries/token/IScrollERC20Upgradeable.sol";
/// @title L2ERC20Gateway
/// @notice The `L2ERC20Gateway` is used to withdraw custom ERC20 compatible tokens on layer 2 and
/// finalize deposit the tokens from layer 1.
/// @dev The withdrawn tokens tokens will be burned directly. On finalizing deposit, the corresponding
/// tokens will be minted and transfered to the recipient.
contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway {
contract L2CustomERC20Gateway is L2ERC20Gateway {
/**********
* Events *
**********/
@@ -47,7 +44,6 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
address _messenger
) external initializer {
require(_router != address(0), "zero router address");
OwnableUpgradeable.__Ownable_init();
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
}
@@ -83,7 +79,7 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
require(_l1Token != address(0), "token address cannot be 0");
require(_l1Token == tokenMapping[_l2Token], "l1 token mismatch");
IScrollERC20(_l2Token).mint(_to, _amount);
IScrollERC20Upgradeable(_l2Token).mint(_to, _amount);
_doCallback(_to, _data);
@@ -129,7 +125,7 @@ contract L2CustomERC20Gateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20G
}
// 2. Burn token.
IScrollERC20(_token).burn(_from, _amount);
IScrollERC20Upgradeable(_token).burn(_from, _amount);
// 3. Generate message passed to L1StandardERC20Gateway.
bytes memory _message = abi.encodeCall(

View File

@@ -2,14 +2,12 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC1155Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/IERC1155Upgradeable.sol";
import {ERC1155HolderUpgradeable, ERC1155ReceiverUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC1155/utils/ERC1155HolderUpgradeable.sol";
import {IL2ERC1155Gateway} from "./IL2ERC1155Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC1155Gateway} from "../../L1/gateways/IL1ERC1155Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC1155} from "../../libraries/token/IScrollERC1155.sol";
/// @title L2ERC1155Gateway
@@ -19,7 +17,7 @@ import {IScrollERC1155} from "../../libraries/token/IScrollERC1155.sol";
/// NFT will be minted and transfered to the recipient.
///
/// This will be changed if we have more specific scenarios.
contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
contract L2ERC1155Gateway is ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
/**********
* Events *
**********/
@@ -45,7 +43,6 @@ contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, Scrol
}
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC1155HolderUpgradeable.__ERC1155Holder_init();
ERC1155ReceiverUpgradeable.__ERC1155Receiver_init();

View File

@@ -4,9 +4,11 @@ pragma solidity ^0.8.16;
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
// solhint-disable no-empty-blocks
abstract contract L2ERC20Gateway is IL2ERC20Gateway {
abstract contract L2ERC20Gateway is ScrollGatewayBase, IL2ERC20Gateway {
/*************
* Variables *
*************/

View File

@@ -2,14 +2,12 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol";
import {ERC721HolderUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/utils/ERC721HolderUpgradeable.sol";
import {IL2ERC721Gateway} from "./IL2ERC721Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC721Gateway} from "../../L1/gateways/IL1ERC721Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {IScrollERC721} from "../../libraries/token/IScrollERC721.sol";
/// @title L2ERC721Gateway
@@ -19,7 +17,7 @@ import {IScrollERC721} from "../../libraries/token/IScrollERC721.sol";
/// NFT will be minted and transfered to the recipient.
///
/// This will be changed if we have more specific scenarios.
contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
contract L2ERC721Gateway is ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
/**********
* Events *
**********/
@@ -45,7 +43,6 @@ contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollG
}
function initialize(address _counterpart, address _messenger) external initializer {
OwnableUpgradeable.__Ownable_init();
ERC721HolderUpgradeable.__ERC721Holder_init();
ScrollGatewayBase._initialize(_counterpart, address(0), _messenger);

View File

@@ -2,8 +2,6 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IL1ETHGateway} from "../../L1/gateways/IL1ETHGateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
@@ -15,7 +13,7 @@ import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// finalize deposit ETH from layer 1.
/// @dev The ETH are not held in the gateway. The ETH will be sent to the `L2ScrollMessenger` contract.
/// On finalizing deposit, the Ether will be transfered from `L2ScrollMessenger`, then transfer to recipient.
contract L2ETHGateway is Initializable, ScrollGatewayBase, IL2ETHGateway {
contract L2ETHGateway is ScrollGatewayBase, IL2ETHGateway {
/***************
* Constructor *
***************/

View File

@@ -7,9 +7,6 @@ import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Own
import {IL2GatewayRouter} from "./IL2GatewayRouter.sol";
import {IL2ETHGateway} from "./IL2ETHGateway.sol";
import {IL2ERC20Gateway} from "./IL2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ETHGateway} from "../../L1/gateways/IL1ETHGateway.sol";
import {IScrollGateway} from "../../libraries/gateway/IScrollGateway.sol";
/// @title L2GatewayRouter
/// @notice The `L2GatewayRouter` is the main entry for withdrawing Ether and ERC20 tokens.

View File

@@ -2,18 +2,15 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {AddressUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
import {IScrollERC20} from "../../libraries/token/IScrollERC20.sol";
import {IScrollERC20Upgradeable} from "../../libraries/token/IScrollERC20Upgradeable.sol";
import {ScrollStandardERC20} from "../../libraries/token/ScrollStandardERC20.sol";
import {IScrollStandardERC20Factory} from "../../libraries/token/IScrollStandardERC20Factory.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L2StandardERC20Gateway
/// @notice The `L2StandardERC20Gateway` is used to withdraw standard ERC20 tokens on layer 2 and
@@ -21,9 +18,8 @@ import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollG
/// @dev The withdrawn ERC20 tokens will be burned directly. On finalizing deposit, the corresponding
/// token will be minted and transfered to the recipient. Any ERC20 that requires non-standard functionality
/// should use a separate gateway.
contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
using SafeERC20 for IERC20;
using Address for address;
contract L2StandardERC20Gateway is L2ERC20Gateway {
using AddressUpgradeable for address;
/*************
* Variables *
@@ -114,7 +110,7 @@ contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gate
_deployL2Token(_deployData, _l1Token);
}
IScrollERC20(_l2Token).mint(_to, _amount);
IScrollERC20Upgradeable(_l2Token).mint(_to, _amount);
_doCallback(_to, _callData);
@@ -145,7 +141,7 @@ contract L2StandardERC20Gateway is Initializable, ScrollGatewayBase, L2ERC20Gate
require(_l1Token != address(0), "no corresponding l1 token");
// 2. Burn token.
IScrollERC20(_token).burn(_from, _amount);
IScrollERC20Upgradeable(_token).burn(_from, _amount);
// 3. Generate message passed to L1StandardERC20Gateway.
bytes memory _message = abi.encodeCall(

View File

@@ -2,15 +2,14 @@
pragma solidity =0.8.16;
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {IL2ERC20Gateway, L2ERC20Gateway} from "./L2ERC20Gateway.sol";
import {IL2ScrollMessenger} from "../IL2ScrollMessenger.sol";
import {IWETH} from "../../interfaces/IWETH.sol";
import {IL1ERC20Gateway} from "../../L1/gateways/IL1ERC20Gateway.sol";
import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollGatewayBase.sol";
import {ScrollGatewayBase} from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L2WETHGateway
/// @notice The `L2WETHGateway` contract is used to withdraw `WETH` token on layer 2 and
@@ -19,8 +18,8 @@ import {ScrollGatewayBase, IScrollGateway} from "../../libraries/gateway/ScrollG
/// then the Ether will be sent to the `L2ScrollMessenger` contract.
/// On finalizing deposit, the Ether will be transfered from `L2ScrollMessenger`, then
/// wrapped as WETH and finally transfer to recipient.
contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
using SafeERC20 for IERC20;
contract L2WETHGateway is L2ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
* Constants *
@@ -89,7 +88,7 @@ contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
require(_amount == msg.value, "msg.value mismatch");
IWETH(_l2Token).deposit{value: _amount}();
IERC20(_l2Token).safeTransfer(_to, _amount);
IERC20Upgradeable(_l2Token).safeTransfer(_to, _amount);
_doCallback(_to, _data);
@@ -118,7 +117,7 @@ contract L2WETHGateway is Initializable, ScrollGatewayBase, L2ERC20Gateway {
}
// 2. Transfer token into this contract.
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
IERC20Upgradeable(_token).safeTransferFrom(_from, address(this), _amount);
IWETH(_token).withdraw(_amount);
// 3. Generate message passed to L2StandardERC20Gateway.

View File

@@ -2,7 +2,6 @@
pragma solidity =0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
@@ -17,7 +16,7 @@ import {L2ERC20Gateway} from "../L2ERC20Gateway.sol";
/// @title L2USDCGateway
/// @notice The `L2USDCGateway` contract is used to withdraw `USDC` token on layer 2 and
/// finalize deposit `USDC` from layer 1.
contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway {
contract L2USDCGateway is L2ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/*************
@@ -56,8 +55,6 @@ contract L2USDCGateway is OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway
) external initializer {
require(_router != address(0), "zero router address");
ScrollGatewayBase._initialize(_counterpart, _router, _messenger);
OwnableUpgradeable.__Ownable_init();
}
/*************************

View File

@@ -5,7 +5,6 @@ pragma solidity =0.8.16;
import {OwnableBase} from "../../libraries/common/OwnableBase.sol";
import {IWhitelist} from "../../libraries/common/IWhitelist.sol";
import {IL1BlockContainer} from "./IL1BlockContainer.sol";
import {IL1GasPriceOracle} from "./IL1GasPriceOracle.sol";
contract L1GasPriceOracle is OwnableBase, IL1GasPriceOracle {

View File

@@ -1,11 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface IERC20Metadata {
function symbol() external view returns (string memory);
function name() external view returns (string memory);
function decimals() external view returns (uint8);
}

View File

@@ -3,13 +3,20 @@
pragma solidity ^0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {ScrollConstants} from "./constants/ScrollConstants.sol";
import {IScrollMessenger} from "./IScrollMessenger.sol";
// solhint-disable var-name-mixedcase
abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
abstract contract ScrollMessengerBase is
OwnableUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable,
IScrollMessenger
{
/**********
* Events *
**********/
@@ -19,14 +26,6 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
/// @param _newFeeVault The address of new fee vault contract.
event UpdateFeeVault(address _oldFeeVault, address _newFeeVault);
/*************
* Constants *
*************/
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/security/ReentrancyGuard.sol
uint256 internal constant _NOT_ENTERED = 1;
uint256 internal constant _ENTERED = 2;
/*************
* Variables *
*************/
@@ -40,31 +39,13 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
/// @notice The address of fee vault, collecting cross domain messaging fee.
address public feeVault;
// @note move to ScrollMessengerBase in next big refactor
/// @dev The status of for non-reentrant check.
uint256 private _lock_status;
/// @dev The storage slots for future usage.
uint256[46] private __gap;
uint256[47] private __gap;
/**********************
* Function Modifiers *
**********************/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_lock_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_lock_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_lock_status = _NOT_ENTERED;
}
modifier notInExecution() {
require(
xDomainMessageSender == ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER,
@@ -77,14 +58,18 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
* Constructor *
***************/
function _initialize(address _counterpart, address _feeVault) internal {
function __ScrollMessengerBase_init(address _counterpart, address _feeVault) internal onlyInitializing {
OwnableUpgradeable.__Ownable_init();
PausableUpgradeable.__Pausable_init();
ReentrancyGuardUpgradeable.__ReentrancyGuard_init();
// initialize to a nonzero value
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;
counterpart = _counterpart;
feeVault = _feeVault;
if (_feeVault != address(0)) {
feeVault = _feeVault;
}
}
// make sure only owner can send ether to messenger to avoid possible user fund loss.
@@ -104,6 +89,17 @@ abstract contract ScrollMessengerBase is OwnableUpgradeable, IScrollMessenger {
emit UpdateFeeVault(_oldFeeVault, _newFeeVault);
}
/// @notice Pause the contract
/// @dev This function can only called by contract owner.
/// @param _status The pause status to update.
function setPause(bool _status) external onlyOwner {
if (_status) {
_pause();
} else {
_unpause();
}
}
/**********************
* Internal Functions *
**********************/

View File

@@ -2,20 +2,15 @@
pragma solidity ^0.8.16;
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {IScrollGateway} from "./IScrollGateway.sol";
import {IScrollMessenger} from "../IScrollMessenger.sol";
import {IScrollGatewayCallback} from "../callbacks/IScrollGatewayCallback.sol";
import {ScrollConstants} from "../constants/ScrollConstants.sol";
abstract contract ScrollGatewayBase is IScrollGateway {
/*************
* Constants *
*************/
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.5.0/contracts/security/ReentrancyGuard.sol
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
abstract contract ScrollGatewayBase is ReentrancyGuardUpgradeable, OwnableUpgradeable, IScrollGateway {
/*************
* Variables *
*************/
@@ -29,35 +24,13 @@ abstract contract ScrollGatewayBase is IScrollGateway {
/// @inheritdoc IScrollGateway
address public override messenger;
/// @dev The status of for non-reentrant check.
uint256 private _status;
/// @dev The storage slots for future usage.
uint256[46] private __gap;
uint256[47] private __gap;
/**********************
* Function Modifiers *
**********************/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
modifier onlyMessenger() {
require(msg.sender == messenger, "only messenger can call");
_;
}
modifier onlyCallByCounterpart() {
address _messenger = messenger; // gas saving
require(msg.sender == _messenger, "only messenger can call");
@@ -87,6 +60,9 @@ abstract contract ScrollGatewayBase is IScrollGateway {
require(_counterpart != address(0), "zero counterpart address");
require(_messenger != address(0), "zero messenger address");
ReentrancyGuardUpgradeable.__ReentrancyGuard_init();
OwnableUpgradeable.__Ownable_init();
counterpart = _counterpart;
messenger = _messenger;
@@ -94,9 +70,6 @@ abstract contract ScrollGatewayBase is IScrollGateway {
if (_router != address(0)) {
router = _router;
}
// for reentrancy guard
_status = _NOT_ENTERED;
}
/**********************

View File

@@ -76,12 +76,7 @@ contract ScrollStandardERC20 is ERC20PermitUpgradeable, IScrollERC20Upgradeable
}
function isContract(address _addr) private view returns (bool hasCode) {
uint256 length;
// solhint-disable-next-line no-inline-assembly
assembly {
length := extcodesize(_addr)
}
return length > 0;
hasCode = _addr.code.length > 0;
}
/// @inheritdoc IScrollERC20Upgradeable

View File

@@ -101,8 +101,8 @@ abstract contract L1GatewayTestBase is DSTestPlus {
}
function prepareL2MessageRoot(bytes32 messageHash) internal {
rollup.updateSequencer(address(this), true);
rollup.updateProver(address(this), true);
rollup.addSequencer(address(this));
rollup.addProver(address(this));
// import genesis batch
bytes memory batchHeader0 = new bytes(89);

View File

@@ -58,7 +58,7 @@ abstract contract L2GatewayTestBase is DSTestPlus {
);
// Initialize L2 contracts
l2Messenger.initialize(address(l1Messenger), feeVault);
l2Messenger.initialize(address(l1Messenger));
l2MessageQueue.initialize(address(l2Messenger));
l1GasOracle.updateWhitelist(address(whitelist));

View File

@@ -40,7 +40,7 @@ contract L2ScrollMessengerTest is DSTestPlus {
);
// Initialize L2 contracts
l2Messenger.initialize(address(l1Messenger), feeVault);
l2Messenger.initialize(address(l1Messenger));
l2MessageQueue.initialize(address(l2Messenger));
l1GasOracle.updateWhitelist(address(whitelist));
}

View File

@@ -62,7 +62,7 @@ contract ScrollChainTest is DSTestPlus {
hevm.expectRevert("caller not sequencer");
rollup.commitBatch(0, batchHeader0, new bytes[](0), new bytes(0));
rollup.updateSequencer(address(this), true);
rollup.addSequencer(address(this));
// invalid version, revert
hevm.expectRevert("invalid version");
@@ -130,8 +130,8 @@ contract ScrollChainTest is DSTestPlus {
hevm.expectRevert("caller not prover");
rollup.finalizeBatchWithProof(new bytes(0), bytes32(0), bytes32(0), bytes32(0), new bytes(0));
rollup.updateProver(address(this), true);
rollup.updateSequencer(address(this), true);
rollup.addProver(address(this));
rollup.addSequencer(address(this));
bytes memory batchHeader0 = new bytes(89);
@@ -218,8 +218,8 @@ contract ScrollChainTest is DSTestPlus {
}
function testCommitAndFinalizeWithL1Messages() public {
rollup.updateSequencer(address(this), true);
rollup.updateProver(address(this), true);
rollup.addSequencer(address(this));
rollup.addProver(address(this));
// import 300 L1 messages
for (uint256 i = 0; i < 300; i++) {
@@ -453,7 +453,7 @@ contract ScrollChainTest is DSTestPlus {
rollup.revertBatch(new bytes(89), 1);
hevm.stopPrank();
rollup.updateSequencer(address(this), true);
rollup.addSequencer(address(this));
bytes memory batchHeader0 = new bytes(89);
@@ -518,11 +518,13 @@ contract ScrollChainTest is DSTestPlus {
assertEq(uint256(rollup.committedBatches(2)), 0);
}
function testUpdateSequencer(address _sequencer) public {
function testAddAndRemoveSequencer(address _sequencer) public {
// set by non-owner, should revert
hevm.startPrank(address(1));
hevm.expectRevert("Ownable: caller is not the owner");
rollup.updateSequencer(_sequencer, true);
rollup.addSequencer(_sequencer);
hevm.expectRevert("Ownable: caller is not the owner");
rollup.removeSequencer(_sequencer);
hevm.stopPrank();
// change to random operator
@@ -530,20 +532,22 @@ contract ScrollChainTest is DSTestPlus {
emit UpdateSequencer(_sequencer, true);
assertBoolEq(rollup.isSequencer(_sequencer), false);
rollup.updateSequencer(_sequencer, true);
rollup.addSequencer(_sequencer);
assertBoolEq(rollup.isSequencer(_sequencer), true);
hevm.expectEmit(true, false, false, true);
emit UpdateSequencer(_sequencer, false);
rollup.updateSequencer(_sequencer, false);
rollup.removeSequencer(_sequencer);
assertBoolEq(rollup.isSequencer(_sequencer), false);
}
function testUpdateProver(address _prover) public {
function testAddAndRemoveProver(address _prover) public {
// set by non-owner, should revert
hevm.startPrank(address(1));
hevm.expectRevert("Ownable: caller is not the owner");
rollup.updateProver(_prover, true);
rollup.addProver(_prover);
hevm.expectRevert("Ownable: caller is not the owner");
rollup.removeProver(_prover);
hevm.stopPrank();
// change to random operator
@@ -551,15 +555,39 @@ contract ScrollChainTest is DSTestPlus {
emit UpdateProver(_prover, true);
assertBoolEq(rollup.isProver(_prover), false);
rollup.updateProver(_prover, true);
rollup.addProver(_prover);
assertBoolEq(rollup.isProver(_prover), true);
hevm.expectEmit(true, false, false, true);
emit UpdateProver(_prover, false);
rollup.updateProver(_prover, false);
rollup.removeProver(_prover);
assertBoolEq(rollup.isProver(_prover), false);
}
function testSetPause() external {
rollup.addSequencer(address(this));
rollup.addProver(address(this));
// not owner, revert
hevm.startPrank(address(1));
hevm.expectRevert("Ownable: caller is not the owner");
rollup.setPause(false);
hevm.stopPrank();
// pause
rollup.setPause(true);
assertBoolEq(true, rollup.paused());
hevm.expectRevert("Pausable: paused");
rollup.commitBatch(0, new bytes(0), new bytes[](0), new bytes(0));
hevm.expectRevert("Pausable: paused");
rollup.finalizeBatchWithProof(new bytes(0), bytes32(0), bytes32(0), bytes32(0), new bytes(0));
// unpause
rollup.setPause(false);
assertBoolEq(false, rollup.paused());
}
function testUpdateVerifier(address _newVerifier) public {
// set by non-owner, should revert
hevm.startPrank(address(1));

View File

@@ -89,6 +89,8 @@ func (c *CoordinatorApp) MockConfig(store bool) error {
}
cfg.DB.DSN = base.DBImg.Endpoint()
cfg.L2.ChainID = 111
cfg.Auth.ChallengeExpireDurationSec = 1
cfg.Auth.LoginExpireDurationSec = 1
c.Config = cfg
if !store {

View File

@@ -21,7 +21,7 @@
},
"auth": {
"secret": "prover secret key",
"challenge_expire_duration_sec": 3600,
"login_expire_duration_sec": 10
"challenge_expire_duration_sec": 10,
"login_expire_duration_sec": 3600
}
}

View File

@@ -33,7 +33,7 @@ type L2 struct {
type Auth struct {
Secret string `json:"secret"`
ChallengeExpireDurationSec int `json:"challenge_expire_duration_sec"`
LoginExpireDurationSec int `json:"token_expire_duration_sec"`
LoginExpireDurationSec int `json:"login_expire_duration_sec"`
}
// Config load configuration items.

View File

@@ -146,6 +146,9 @@ func (m *ProofReceiverLogic) HandleZkProof(ctx *gin.Context, proofMsg *message.P
return verifyErr
}
log.Info("proof verified and valid", "proof id", proofMsg.ID, "prover name", proverTask.ProverName,
"prover pk", pk, "prove type", proofMsg.Type, "proof time", proofTimeSec)
if err := m.closeProofTask(ctx, proofMsg.ID, pk, proofMsg); err != nil {
m.proofRecover(ctx, proofMsg.ID, pk, proofMsg.Type)
return err

View File

@@ -101,6 +101,8 @@ func setupCoordinator(t *testing.T, proversPerSession uint8, coordinatorURL stri
assert.NoError(t, runErr)
}
}()
time.Sleep(time.Second * 2)
return proofCollector, srv
}

View File

@@ -91,10 +91,12 @@ func (c *CoordinatorClient) Login(ctx context.Context) error {
Signature: authMsg.Signature,
}
// store JWT token for login requests
c.client.SetAuthToken(challengeResult.Data.Token)
var loginResult LoginResponse
loginResp, err := c.client.R().
SetHeader("Content-Type", "application/json").
SetHeader("Authorization", fmt.Sprintf("Bearer %s", challengeResult.Data.Token)).
SetBody(loginReq).
SetResult(&loginResult).
Post("/coordinator/v1/login")
@@ -136,10 +138,11 @@ func (c *CoordinatorClient) GetTask(ctx context.Context, req *GetTaskRequest) (*
}
if result.ErrCode == types.ErrJWTTokenExpired {
log.Debug("JWT expired, attempting to re-login")
log.Info("JWT expired, attempting to re-login")
if err := c.Login(ctx); err != nil {
return nil, fmt.Errorf("JWT expired, re-login failed: %v", err)
}
log.Info("re-login success")
return c.GetTask(ctx, req)
}
if result.ErrCode != types.Success {
@@ -168,10 +171,11 @@ func (c *CoordinatorClient) SubmitProof(ctx context.Context, req *SubmitProofReq
}
if result.ErrCode == types.ErrJWTTokenExpired {
log.Debug("JWT expired, attempting to re-login")
log.Info("JWT expired, attempting to re-login")
if err := c.Login(ctx); err != nil {
return fmt.Errorf("JWT expired, re-login failed: %v", err)
}
log.Info("re-login success")
return c.SubmitProof(ctx, req)
}
if result.ErrCode != types.Success {

View File

@@ -129,3 +129,23 @@ func TestCoordinatorProverInteraction(t *testing.T) {
batchProverApp.WaitExit()
coordinatorApp.WaitExit()
}
func TestProverReLogin(t *testing.T) {
// Start postgres docker containers.
base.RunL2Geth(t)
base.RunDBImage(t)
assert.NoError(t, migrate.ResetDB(base.DBClient(t)))
// Run coordinator app.
coordinatorApp.RunApp(t) // login timeout: 1 sec
// Run prover app.
chunkProverApp.RunAppWithExpectedResult(t, "re-login success") // chunk prover login.
batchProverApp.RunAppWithExpectedResult(t, "re-login success") // batch prover login.
// Free apps.
chunkProverApp.WaitExit()
batchProverApp.WaitExit()
coordinatorApp.WaitExit()
}