add L2GasPriceOracle and Version

This commit is contained in:
zimpha
2023-02-02 03:21:27 +08:00
parent 5b91abd2a7
commit 764cd19403
39 changed files with 610 additions and 45 deletions

View File

@@ -366,6 +366,23 @@ Update layer 2 to layer 2 token mapping.
| _l1Token | address | The address of corresponding ERC1155 token in layer 2. |
| _l2Token | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
## Events

View File

@@ -311,6 +311,23 @@ Update layer 2 to layer 2 token mapping.
| _l1Token | address | The address of corresponding ERC721 token in layer 2. |
| _l2Token | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
## Events

View File

@@ -380,6 +380,23 @@ function transferOwnership(address newOwner) external nonpayable
|---|---|---|
| newOwner | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
## Events

View File

@@ -369,6 +369,23 @@ Update whitelist contract.
|---|---|---|
| _newWhitelist | address | The address of new whitelist contract. |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### whitelist
```solidity

View File

@@ -226,6 +226,23 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _0 | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
## Events

View File

@@ -226,6 +226,23 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _0 | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
## Events

View File

@@ -327,6 +327,23 @@ Update layer 2 to layer 1 token mapping.
| _l2Token | address | undefined |
| _l1Token | address | The address of ERC1155 token in layer 1. |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### withdrawERC1155
```solidity

View File

@@ -274,6 +274,23 @@ Update layer 2 to layer 1 token mapping.
| _l2Token | address | undefined |
| _l1Token | address | The address of ERC721 token in layer 1. |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### withdrawERC721
```solidity

View File

@@ -312,6 +312,23 @@ function transferOwnership(address newOwner) external nonpayable
|---|---|---|
| newOwner | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### withdrawERC20
```solidity

View File

@@ -295,6 +295,23 @@ Update whitelist contract.
|---|---|---|
| _newWhitelist | address | The address of new whitelist contract. |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### whitelist
```solidity

View File

@@ -173,6 +173,23 @@ The address of ScrollStandardERC20Factory.
|---|---|---|
| _0 | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### withdrawERC20
```solidity

View File

@@ -191,6 +191,23 @@ The address of L1GatewayRouter/L2GatewayRouter contract.
|---|---|---|
| _0 | address | undefined |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
### withdrawERC20
```solidity

View File

@@ -364,6 +364,23 @@ Update the address of operator.
|---|---|---|
| _newOperator | address | The new operator address to update. |
### version
```solidity
function version() external view returns (string)
```
the current contract version.
#### Returns
| Name | Type | Description |
|---|---|---|
| _0 | string | undefined |
## Events

View File

@@ -129,6 +129,7 @@ describe("L1BlockContainer", async () => {
test.parentHash,
test.blockHeight - 1,
test.blockTimestamp - 1,
test.baseFee,
test.stateRoot
);
const Whitelist = await ethers.getContractFactory("Whitelist", deployer);
@@ -144,6 +145,7 @@ describe("L1BlockContainer", async () => {
test.parentHash,
test.blockHeight - 1,
test.blockTimestamp - 1,
test.baseFee,
test.stateRoot
);
const headerRLP = encodeHeader(test);
@@ -158,6 +160,7 @@ describe("L1BlockContainer", async () => {
test.parentHash,
test.blockHeight - 1,
test.blockTimestamp - 1,
test.baseFee,
test.stateRoot
);
const headerRLP = encodeHeader(test);
@@ -172,6 +175,7 @@ describe("L1BlockContainer", async () => {
constants.HashZero,
test.blockHeight - 1,
test.blockTimestamp - 1,
test.baseFee,
test.stateRoot
);
const headerRLP = encodeHeader(test);
@@ -184,6 +188,7 @@ describe("L1BlockContainer", async () => {
test.parentHash,
test.blockHeight,
test.blockTimestamp - 1,
test.baseFee,
test.stateRoot
);
const headerRLP = encodeHeader(test);
@@ -196,6 +201,7 @@ describe("L1BlockContainer", async () => {
test.parentHash,
test.blockHeight - 1,
test.blockTimestamp + 1,
test.baseFee,
test.stateRoot
);
const headerRLP = encodeHeader(test);
@@ -210,16 +216,20 @@ describe("L1BlockContainer", async () => {
test.parentHash,
test.blockHeight - 1,
test.blockTimestamp - 1,
test.baseFee,
test.stateRoot
);
expect(await container.latestBlockHash()).to.eq(test.parentHash);
const headerRLP = encodeHeader(test);
await expect(container.importBlockHeader(test.hash, headerRLP, "0x"))
.to.emit(container, "ImportBlock")
.withArgs(test.hash, test.blockHeight, test.blockTimestamp, test.stateRoot);
.withArgs(test.hash, test.blockHeight, test.blockTimestamp, test.baseFee, test.stateRoot);
expect(await container.getStateRoot(test.hash)).to.eq(test.stateRoot);
expect(await container.getBlockTimestamp(test.hash)).to.eq(test.blockTimestamp);
expect(await container.latestBlockHash()).to.eq(test.hash);
expect(await container.latestBaseFee()).to.eq(test.baseFee);
expect(await container.latestBlockNumber()).to.eq(test.blockHeight);
expect(await container.latestBlockTimestamp()).to.eq(test.blockTimestamp);
});
});
}
@@ -238,7 +248,14 @@ describe("L1BlockContainer", async () => {
await container.deployed();
const block = await ethers.provider.getBlock("latest");
await container.initialize(deployer.address, block.hash, block.number, block.timestamp, block.hash);
await container.initialize(
deployer.address,
block.hash,
block.number,
block.timestamp,
block.baseFeePerGas!,
block.hash
);
});
it("should revert, when block not imported", async () => {

View File

@@ -8,6 +8,7 @@ import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/securit
import { IZKRollup } from "./rollup/IZKRollup.sol";
import { L1MessageQueue } from "./rollup/L1MessageQueue.sol";
import { IL1ScrollMessenger, IScrollMessenger } from "./IL1ScrollMessenger.sol";
import { Version } from "../libraries/common/Version.sol";
import { IGasOracle } from "../libraries/oracle/IGasOracle.sol";
import { ScrollConstants } from "../libraries/ScrollConstants.sol";
import { ScrollMessengerBase } from "../libraries/ScrollMessengerBase.sol";
@@ -23,7 +24,7 @@ import { ZkTrieVerifier } from "../libraries/verifier/ZkTrieVerifier.sol";
///
/// @dev All deposited Ether (including `WETH` deposited throng `L1WETHGateway`) will locked in
/// this contract.
contract L1ScrollMessenger is OwnableUpgradeable, PausableUpgradeable, ScrollMessengerBase, IL1ScrollMessenger {
contract L1ScrollMessenger is Version, OwnableUpgradeable, PausableUpgradeable, ScrollMessengerBase, IL1ScrollMessenger {
/*************
* Variables *
*************/

View File

@@ -9,6 +9,7 @@ import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/
import { IL1ERC20Gateway, L1ERC20Gateway } from "./L1ERC20Gateway.sol";
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
import { IL2ERC20Gateway } from "../../L2/gateways/IL2ERC20Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L1CustomERC20Gateway
@@ -16,7 +17,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
/// 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 Version, OwnableUpgradeable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20Upgradeable for IERC20Upgradeable;
/**************************************** Events ****************************************/

View File

@@ -9,6 +9,7 @@ import { ERC1155HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/to
import { IL1ERC1155Gateway } from "./IL1ERC1155Gateway.sol";
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
import { IL2ERC1155Gateway } from "../../L2/gateways/IL2ERC1155Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L1ERC1155Gateway
@@ -19,7 +20,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
///
/// This will be changed if we have more specific scenarios.
// @todo Current implementation doesn't support calling from `L1GatewayRouter`.
contract L1ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC1155Gateway {
contract L1ERC1155Gateway is Version, OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL1ERC1155Gateway {
/**************************************** Events ****************************************/
/// @notice Emitted when token mapping for ERC1155 token is updated.

View File

@@ -2,11 +2,13 @@
pragma solidity ^0.8.0;
import { Version } from "../../libraries/common/Version.sol";
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
// solhint-disable no-empty-blocks
abstract contract L1ERC20Gateway is IL1ERC20Gateway {
abstract contract L1ERC20Gateway is Version, IL1ERC20Gateway {
/// @inheritdoc IL1ERC20Gateway
function depositERC20(
address _token,

View File

@@ -9,6 +9,7 @@ import { ERC721HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/tok
import { IL1ERC721Gateway } from "./IL1ERC721Gateway.sol";
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
import { IL2ERC721Gateway } from "../../L2/gateways/IL2ERC721Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L1ERC721Gateway
@@ -19,7 +20,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
///
/// This will be changed if we have more specific scenarios.
// @todo Current implementation doesn't support calling from `L1GatewayRouter`.
contract L1ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC721Gateway {
contract L1ERC721Gateway is Version, OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL1ERC721Gateway {
/**************************************** Events ****************************************/
/// @notice Emitted when token mapping for ERC721 token is updated.

View File

@@ -8,6 +8,7 @@ import { IL1GatewayRouter } from "./IL1GatewayRouter.sol";
import { IL1ERC20Gateway } from "./IL1ERC20Gateway.sol";
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
import { IL2GatewayRouter } from "../../L2/gateways/IL2GatewayRouter.sol";
import { Version } from "../../libraries/common/Version.sol";
import { IScrollGateway } from "../../libraries/gateway/IScrollGateway.sol";
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
@@ -16,7 +17,7 @@ import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol
/// All deposited tokens are routed to corresponding gateways.
/// @dev One can also use this contract to query L1/L2 token address mapping.
/// In the future, ERC-721 and ERC-1155 tokens will be added to the router too.
contract L1GatewayRouter is OwnableUpgradeable, ScrollGatewayBase, IL1GatewayRouter {
contract L1GatewayRouter is Version, OwnableUpgradeable, ScrollGatewayBase, IL1GatewayRouter {
/**************************************** Events ****************************************/
event SetDefaultERC20Gateway(address indexed _defaultERC20Gateway);

View File

@@ -11,6 +11,7 @@ import { L1ERC20Gateway, IL1ERC20Gateway } from "./L1ERC20Gateway.sol";
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
import { IERC20Metadata } from "../../interfaces/IERC20Metadata.sol";
import { IL2ERC20Gateway } from "../../L2/gateways/IL2ERC20Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L1StandardERC20Gateway
@@ -19,7 +20,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
/// @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 {
contract L1StandardERC20Gateway is Version, Initializable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20 for IERC20;
/**************************************** Variables ****************************************/

View File

@@ -10,6 +10,7 @@ import { L1ERC20Gateway, IL1ERC20Gateway } from "./L1ERC20Gateway.sol";
import { IL1ScrollMessenger } from "../IL1ScrollMessenger.sol";
import { IWETH } from "../../interfaces/IWETH.sol";
import { IL2ERC20Gateway } from "../../L2/gateways/IL2ERC20Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L1WETHGateway
@@ -19,7 +20,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
/// 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 {
contract L1WETHGateway is Version, Initializable, ScrollGatewayBase, L1ERC20Gateway {
using SafeERC20 for IERC20;
/**************************************** Variables ****************************************/

View File

@@ -2,12 +2,13 @@
pragma solidity ^0.8.0;
import { Version } from "../../libraries/common/Version.sol";
import { IL1MessageQueue } from "./IL1MessageQueue.sol";
/// @title L1MessageQueue
/// @notice This contract will hold all L1 to L2 messages.
/// Each appended message is assigned with a unique and increasing `uint256` index denoting the message nonce.
contract L1MessageQueue is IL1MessageQueue {
contract L1MessageQueue is Version, IL1MessageQueue {
/*************
* Constants *
*************/

View File

@@ -5,6 +5,7 @@ pragma solidity ^0.8.0;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IZKRollup } from "./IZKRollup.sol";
import { Version } from "../../libraries/common/Version.sol";
import { RollupVerifier } from "../../libraries/verifier/RollupVerifier.sol";
// solhint-disable reason-string
@@ -16,7 +17,7 @@ import { RollupVerifier } from "../../libraries/verifier/RollupVerifier.sol";
/// 2. the block tree generated by layer 2 and it's status.
///
/// @dev the message queue is not used yet, the offline relayer only use events in `L1ScrollMessenger`.
contract ZKRollup is OwnableUpgradeable, IZKRollup {
contract ZKRollup is Version, OwnableUpgradeable, IZKRollup {
/**********
* Events *
**********/

View File

@@ -6,6 +6,7 @@ import { IL2ScrollMessenger, IScrollMessenger } from "./IL2ScrollMessenger.sol";
import { L2MessageQueue } from "./predeploys/L2MessageQueue.sol";
import { IL1BlockContainer } from "./predeploys/IL1BlockContainer.sol";
import { OwnableBase } from "../libraries/common/OwnableBase.sol";
import { Version } from "../libraries/common/Version.sol";
import { IGasOracle } from "../libraries/oracle/IGasOracle.sol";
import { ScrollConstants } from "../libraries/ScrollConstants.sol";
import { ScrollMessengerBase } from "../libraries/ScrollMessengerBase.sol";
@@ -19,7 +20,7 @@ import { ScrollMessengerBase } from "../libraries/ScrollMessengerBase.sol";
///
/// @dev It should be a predeployed contract in layer 2 and should hold infinite amount
/// of Ether (Specifically, `uint256(-1)`), which can be initialized in Genesis Block.
contract L2ScrollMessenger is ScrollMessengerBase, OwnableBase, IL2ScrollMessenger {
contract L2ScrollMessenger is Version, ScrollMessengerBase, OwnableBase, IL2ScrollMessenger {
/**************************************** Variables ****************************************/
/// @notice Mapping from relay id to relay status.
@@ -36,7 +37,7 @@ contract L2ScrollMessenger is ScrollMessengerBase, OwnableBase, IL2ScrollMesseng
constructor(address _owner) {
ScrollMessengerBase._initialize();
owner = _owner;
_transferOwnership(_owner);
// initialize to a nonzero value
xDomainMessageSender = ScrollConstants.DEFAULT_XDOMAIN_MESSAGE_SENDER;

View File

@@ -8,6 +8,7 @@ import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC
import { IL2ERC20Gateway, L2ERC20Gateway } from "./L2ERC20Gateway.sol";
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
import { IL1ERC20Gateway } from "../../L1/gateways/IL1ERC20Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20.sol";
@@ -16,7 +17,7 @@ import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20
/// 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 Version, OwnableUpgradeable, ScrollGatewayBase, L2ERC20Gateway {
/**************************************** Events ****************************************/
/// @notice Emitted when token mapping for ERC20 token is updated.

View File

@@ -9,6 +9,7 @@ import { ERC1155HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/to
import { IL2ERC1155Gateway } from "./IL2ERC1155Gateway.sol";
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
import { IL1ERC1155Gateway } from "../../L1/gateways/IL1ERC1155Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
import { IScrollERC1155 } from "../../libraries/token/IScrollERC1155.sol";
@@ -20,7 +21,7 @@ import { IScrollERC1155 } from "../../libraries/token/IScrollERC1155.sol";
///
/// This will be changed if we have more specific scenarios.
// @todo Current implementation doesn't support calling from `L2GatewayRouter`.
contract L2ERC1155Gateway is OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
contract L2ERC1155Gateway is Version, OwnableUpgradeable, ERC1155HolderUpgradeable, ScrollGatewayBase, IL2ERC1155Gateway {
/**************************************** Events ****************************************/
/// @notice Emitted when token mapping for ERC1155 token is updated.

View File

@@ -3,10 +3,11 @@
pragma solidity ^0.8.0;
import { IL2ERC20Gateway } from "./IL2ERC20Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
// solhint-disable no-empty-blocks
abstract contract L2ERC20Gateway is IL2ERC20Gateway {
abstract contract L2ERC20Gateway is Version, IL2ERC20Gateway {
/// @inheritdoc IL2ERC20Gateway
function withdrawERC20(
address _token,

View File

@@ -9,6 +9,7 @@ import { ERC721HolderUpgradeable } from "@openzeppelin/contracts-upgradeable/tok
import { IL2ERC721Gateway } from "./IL2ERC721Gateway.sol";
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
import { IL1ERC721Gateway } from "../../L1/gateways/IL1ERC721Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
import { IScrollERC721 } from "../../libraries/token/IScrollERC721.sol";
@@ -20,7 +21,7 @@ import { IScrollERC721 } from "../../libraries/token/IScrollERC721.sol";
///
/// This will be changed if we have more specific scenarios.
// @todo Current implementation doesn't support calling from `L2GatewayRouter`.
contract L2ERC721Gateway is OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
contract L2ERC721Gateway is Version, OwnableUpgradeable, ERC721HolderUpgradeable, ScrollGatewayBase, IL2ERC721Gateway {
/**************************************** Events ****************************************/
/// @notice Emitted when token mapping for ERC721 token is updated.

View File

@@ -8,6 +8,7 @@ import { IL2GatewayRouter } from "./IL2GatewayRouter.sol";
import { IL2ERC20Gateway } from "./IL2ERC20Gateway.sol";
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
import { IL1GatewayRouter } from "../../L1/gateways/IL1GatewayRouter.sol";
import { Version } from "../../libraries/common/Version.sol";
import { IScrollGateway } from "../../libraries/gateway/IScrollGateway.sol";
import { ScrollGatewayBase } from "../../libraries/gateway/ScrollGatewayBase.sol";
import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20.sol";
@@ -17,7 +18,7 @@ import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20
/// All deposited tokens are routed to corresponding gateways.
/// @dev One can also use this contract to query L1/L2 token address mapping.
/// In the future, ERC-721 and ERC-1155 tokens will be added to the router too.
contract L2GatewayRouter is OwnableUpgradeable, ScrollGatewayBase, IL2GatewayRouter {
contract L2GatewayRouter is Version, OwnableUpgradeable, ScrollGatewayBase, IL2GatewayRouter {
/**************************************** Events ****************************************/
event SetDefaultERC20Gateway(address indexed _defaultERC20Gateway);

View File

@@ -10,6 +10,7 @@ import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { IL2ERC20Gateway, L2ERC20Gateway } from "./L2ERC20Gateway.sol";
import { IL2ScrollMessenger } from "../IL2ScrollMessenger.sol";
import { IL1ERC20Gateway } from "../../L1/gateways/IL1ERC20Gateway.sol";
import { Version } from "../../libraries/common/Version.sol";
import { IScrollStandardERC20 } from "../../libraries/token/IScrollStandardERC20.sol";
import { ScrollStandardERC20 } from "../../libraries/token/ScrollStandardERC20.sol";
import { IScrollStandardERC20Factory } from "../../libraries/token/IScrollStandardERC20Factory.sol";
@@ -21,7 +22,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
/// @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 {
contract L2StandardERC20Gateway is Version, Initializable, ScrollGatewayBase, L2ERC20Gateway {
using SafeERC20 for IERC20;
using Address for address;

View File

@@ -10,6 +10,7 @@ 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 { Version } from "../../libraries/common/Version.sol";
import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/ScrollGatewayBase.sol";
/// @title L2WETHGateway
@@ -19,7 +20,7 @@ import { ScrollGatewayBase, IScrollGateway } from "../../libraries/gateway/Scrol
/// 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 {
contract L2WETHGateway is Version, Initializable, ScrollGatewayBase, L2ERC20Gateway {
using SafeERC20 for IERC20;
/**************************************** Variables ****************************************/

View File

@@ -11,27 +11,26 @@ interface IL1BlockContainer {
/// @param blockHash The hash of the imported block.
/// @param blockHeight The height of the imported block.
/// @param blockTimestamp The timestamp of the imported block.
/// @param baseFee The base fee of the imported block.
/// @param stateRoot The state root of the imported block.
event ImportBlock(bytes32 indexed blockHash, uint256 blockHeight, uint256 blockTimestamp, bytes32 stateRoot);
/***********
* Structs *
***********/
/// @dev Compiler will pack this into single `uint256`.
struct BlockMetadata {
// The block height.
uint64 height;
// The block timestamp.
uint64 timestamp;
// The reserved field.
uint128 reserved;
}
event ImportBlock(bytes32 indexed blockHash, uint256 blockHeight, uint256 blockTimestamp, uint256 baseFee, bytes32 stateRoot);
/*************************
* Public View Functions *
*************************/
/// @notice Return the latest imported block hash
function latestBlockHash() external view returns (bytes32);
/// @notice Return the latest imported L1 base fee
function latestBaseFee() external view returns (uint256);
/// @notice Return the latest imported block number
function latestBlockNumber() external view returns (uint256);
/// @notice Return the latest imported block timestamp
function latestBlockTimestamp() external view returns (uint256);
/// @notice Check whether the message is included in the corresponding L1 block.
/// @param blockHash The block hash where the message should in.
/// @param msgHash The hash of the message to check.

View File

@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IL2GasPriceOracle {
/**********
* Events *
**********/
/// @notice Emitted when current fee overhead is updated.
/// @param overhead The current fee overhead updated.
event OverheadUpdated(uint256 overhead);
/// @notice Emitted when current fee scalar is updated.
/// @param scalar The current fee scalar updated.
event ScalarUpdated(uint256 scalar);
/*************************
* Public View Functions *
*************************/
/// @notice Return the current L2 base fee.
function baseFee() external view returns (uint256);
/// @notice Return the current L2 gas price (base fee).
function gasPrice() external view returns (uint256);
/// @notice Return the current l1 fee overhead.
function overhead() external view returns (uint256);
/// @notice Return the current l1 fee scalar.
function scalar() external view returns (uint256);
/// @notice Return the latest known l1 base fee.
function l1BaseFee() external view returns (uint256);
/// @notice Computes the L1 portion of the fee based on the size of the rlp encoded input
/// transaction, the current L1 base fee, and the various dynamic parameters.
/// @param data Unsigned fully RLP-encoded transaction to get the L1 fee for.
/// @return L1 fee that should be paid for the tx
function getL1Fee(bytes memory data) external view returns (uint256);
/// @notice Computes the amount of L1 gas used for a transaction. Adds the overhead which
/// represents the per-transaction gas overhead of posting the transaction and state
/// roots to L1. Adds 68 bytes of padding to account for the fact that the input does
/// not have a signature.
/// @param data Unsigned fully RLP-encoded transaction to get the L1 gas for.
/// @return Amount of L1 gas used to publish the transaction.
function getL1GasUsed(bytes memory data) external view returns (uint256);
}

View File

@@ -8,11 +8,12 @@ import { IL1BlockContainer } from "./IL1BlockContainer.sol";
import { OwnableBase } from "../../libraries/common/OwnableBase.sol";
import { IWhitelist } from "../../libraries/common/IWhitelist.sol";
import { Version } from "../../libraries/common/Version.sol";
import { PatriciaMerkleTrieVerifier } from "../../libraries/verifier/PatriciaMerkleTrieVerifier.sol";
/// @title L1BlockContainer
/// @notice This contract will maintain the list of blocks proposed in L1.
contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
contract L1BlockContainer is Version, Initializable, OwnableBase, IL1BlockContainer {
/**********
* Events *
**********/
@@ -32,6 +33,20 @@ contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
/// @notice The address of L1ScrollMessenger contract.
address public immutable messenger;
/***********
* Structs *
***********/
/// @dev Compiler will pack this into single `uint256`.
struct BlockMetadata {
// The block height.
uint64 height;
// The block timestamp.
uint64 timestamp;
// The base fee in the block.
uint128 baseFee;
}
/*************
* Variables *
*************/
@@ -41,8 +56,8 @@ contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
// @todo change to ring buffer to save gas usage.
/// @notice The hash of last imported block.
bytes32 public latestBlockHash;
/// @inheritdoc IL1BlockContainer
bytes32 public override latestBlockHash;
/// @notice Mapping from block hash to corresponding state root.
mapping(bytes32 => bytes32) public stateRoot;
@@ -65,21 +80,37 @@ contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
bytes32 _startBlockHash,
uint64 _startBlockHeight,
uint64 _startBlockTimestamp,
uint128 _startBlockBaseFee,
bytes32 _startStateRoot
) public initializer {
owner = _owner;
_transferOwnership(_owner);
latestBlockHash = _startBlockHash;
stateRoot[_startBlockHash] = _startStateRoot;
metadata[_startBlockHash] = BlockMetadata(_startBlockHeight, _startBlockTimestamp, 0);
metadata[_startBlockHash] = BlockMetadata(_startBlockHeight, _startBlockTimestamp, _startBlockBaseFee);
emit ImportBlock(_startBlockHash, _startBlockHeight, _startBlockTimestamp, _startStateRoot);
emit ImportBlock(_startBlockHash, _startBlockHeight, _startBlockTimestamp, _startBlockBaseFee, _startStateRoot);
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL1BlockContainer
function latestBaseFee() external override view returns (uint256) {
return metadata[latestBlockHash].baseFee;
}
/// @inheritdoc IL1BlockContainer
function latestBlockNumber() external override view returns (uint256) {
return metadata[latestBlockHash].height;
}
/// @inheritdoc IL1BlockContainer
function latestBlockTimestamp() external override view returns (uint256) {
return metadata[latestBlockHash].timestamp;
}
/// @inheritdoc IL1BlockContainer
function verifyMessageInclusionStatus(
bytes32 _blockHash,
@@ -181,6 +212,7 @@ contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
bytes32 _stateRoot;
uint64 _height;
uint64 _timestamp;
uint128 _baseFee;
assembly {
// reverts with error `msg`.
@@ -304,6 +336,8 @@ contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
_height := mload(add(memPtr, 0x100))
// load block timestamp, 12-th entry
_timestamp := mload(add(memPtr, 0x160))
// load base fee, 16-th entry
_baseFee := mload(add(memPtr, 0x1e0))
}
require(stateRoot[_parentHash] != bytes32(0), "Parent not imported");
BlockMetadata memory _parentMetadata = metadata[_parentHash];
@@ -312,9 +346,9 @@ contract L1BlockContainer is Initializable, OwnableBase, IL1BlockContainer {
latestBlockHash = _blockHash;
stateRoot[_blockHash] = _stateRoot;
metadata[_blockHash] = BlockMetadata(_height, _timestamp, 0);
metadata[_blockHash] = BlockMetadata(_height, _timestamp, _baseFee);
emit ImportBlock(_blockHash, _height, _timestamp, _stateRoot);
emit ImportBlock(_blockHash, _height, _timestamp, _baseFee, _stateRoot);
}
/************************

View File

@@ -0,0 +1,118 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { OwnableBase } from "../../libraries/common/OwnableBase.sol";
import { Version } from "../../libraries/common/Version.sol";
import "./IL1BlockContainer.sol";
import "./IL2GasPriceOracle.sol";
contract L2GasPriceOracle is Version, OwnableBase, IL2GasPriceOracle {
/*************
* Constants *
*************/
/// @dev The precision used in the scalar.
uint256 private constant PRECISION = 1e9;
/// @dev The maximum possible l1 fee overhead.
/// Computed based on current l1 block gas limit.
uint256 private constant MAX_OVERHEAD = 30000000/16;
/// @dev The maximum possible l1 fee scale.
/// x1000 should be enough.
uint256 private constant MAX_SCALE = 1000 * PRECISION;
/// @notice The address of L1BlockContainer contract.
address public immutable blockContainer;
/*************
* Variables *
*************/
/// @inheritdoc IL2GasPriceOracle
uint256 public override overhead;
/// @inheritdoc IL2GasPriceOracle
uint256 public override scalar;
/***************
* Constructor *
***************/
constructor(address _owner, address _blockContainer) {
_transferOwnership(_owner);
blockContainer = _blockContainer;
}
/*************************
* Public View Functions *
*************************/
/// @inheritdoc IL2GasPriceOracle
function baseFee() external view override returns (uint256) {
return block.basefee;
}
/// @inheritdoc IL2GasPriceOracle
function gasPrice() external view override returns (uint256) {
return block.basefee;
}
/// @notice Return the latest known l1 base fee.
function l1BaseFee() public view override returns (uint256) {
return IL1BlockContainer(blockContainer).latestBaseFee();
}
/// @inheritdoc IL2GasPriceOracle
function getL1Fee(bytes memory _data) external view override returns (uint256) {
unchecked {
uint256 _l1GasUsed = getL1GasUsed(_data);
uint256 _l1Fee = _l1GasUsed * l1BaseFee();
return (_l1Fee * scalar) / PRECISION;
}
}
/// @inheritdoc IL2GasPriceOracle
/// @dev See the comments in `OVM_GasPriceOracle1` for more details
/// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol
function getL1GasUsed(bytes memory _data) public view override returns (uint256) {
uint256 _total = 0;
uint256 _length = _data.length;
unchecked {
for (uint256 i = 0; i < _length; i++) {
if (_data[i] == 0) {
_total += 4;
} else {
_total += 16;
}
}
uint256 _unsigned = _total + overhead;
return _unsigned + (68 * 16);
}
}
/************************
* Restricted Functions *
************************/
/// @notice Allows the owner to modify the overhead.
/// @param _overhead New overhead
function setOverhead(uint256 _overhead) external onlyOwner {
require(_overhead <= MAX_OVERHEAD, "exceed maximum overhead");
overhead = _overhead;
emit OverheadUpdated(_overhead);
}
/// Allows the owner to modify the scalar.
/// @param _scalar New scalar
function setScalar(uint256 _scalar) external onlyOwner {
require(_scalar <= MAX_SCALE, "exceed maximum scale");
scalar = _scalar;
emit ScalarUpdated(_scalar);
}
}

View File

@@ -3,6 +3,7 @@
pragma solidity ^0.8.0;
import { AppendOnlyMerkleTree } from "../../libraries/common/AppendOnlyMerkleTree.sol";
import { Version } from "../../libraries/common/Version.sol";
/// @title L2MessageQueue
/// @notice The original idea is from Optimism, see [OVM_L2ToL1MessagePasser](https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/predeploys/OVM_L2ToL1MessagePasser.sol).
@@ -10,7 +11,7 @@ import { AppendOnlyMerkleTree } from "../../libraries/common/AppendOnlyMerkleTre
/// of a message on L2. The L1 Cross Domain Messenger performs this proof in its
/// _verifyStorageProof function, which verifies the existence of the transaction hash in this
/// contract's `sentMessages` mapping.
contract L2MessageQueue is AppendOnlyMerkleTree {
contract L2MessageQueue is Version, AppendOnlyMerkleTree {
/// @notice Emitted when a new message is added to the merkle tree.
/// @param index The index of the corresponding message.
/// @param messageHash The hash of the corresponding message.

View File

@@ -0,0 +1,8 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
abstract contract Version {
/// @notice the current contract version.
string public constant version = "0.0.1";
}

View File

@@ -0,0 +1,98 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { DSTestPlus } from "solmate/test/utils/DSTestPlus.sol";
import { WETH } from "solmate/tokens/WETH.sol";
import { L1BlockContainer } from "../L2/predeploys/L1BlockContainer.sol";
import { L2GasPriceOracle } from "../L2/predeploys/L2GasPriceOracle.sol";
contract L2GasPriceOracleTest is DSTestPlus {
uint256 private constant PRECISION = 1e9;
uint256 private constant MAX_OVERHEAD = 30000000 / 16;
uint256 private constant MAX_SCALE = 1000 * PRECISION;
L2GasPriceOracle private oracle;
L1BlockContainer private container;
function setUp() public {
container = new L1BlockContainer(address(0), address(0));
oracle = new L2GasPriceOracle(address(this), address(container));
}
function testSetOverhead(uint256 _overhead) external {
_overhead = bound(_overhead, 0, MAX_OVERHEAD);
// call by non-owner, should revert
hevm.startPrank(address(1));
hevm.expectRevert("caller is not the owner");
oracle.setOverhead(_overhead);
hevm.stopPrank();
// overhead is too large
hevm.expectRevert("exceed maximum overhead");
oracle.setOverhead(MAX_OVERHEAD + 1);
// call by owner, should succeed
assertEq(oracle.overhead(), 0);
oracle.setOverhead(_overhead);
assertEq(oracle.overhead(), _overhead);
}
function testSetScalar(uint256 _scalar) external {
_scalar = bound(_scalar, 0, MAX_SCALE);
// call by non-owner, should revert
hevm.startPrank(address(1));
hevm.expectRevert("caller is not the owner");
oracle.setScalar(_scalar);
hevm.stopPrank();
// scale is too large
hevm.expectRevert("exceed maximum scale");
oracle.setScalar(MAX_SCALE + 1);
// call by owner, should succeed
assertEq(oracle.scalar(), 0);
oracle.setScalar(_scalar);
assertEq(oracle.scalar(), _scalar);
}
function testGetL1GasUsed(uint256 _overhead, bytes memory _data) external {
_overhead = bound(_overhead, 0, MAX_OVERHEAD);
oracle.setOverhead(_overhead);
uint256 _gasUsed = _overhead + 68 * 16;
for (uint256 i = 0; i < _data.length; i++) {
if (_data[i] == 0) _gasUsed += 4;
else _gasUsed += 16;
}
assertEq(oracle.getL1GasUsed(_data), _gasUsed);
}
function testGetL1Fee(
uint256 _baseFee,
uint256 _overhead,
uint256 _scalar,
bytes memory _data
) external {
_overhead = bound(_overhead, 0, MAX_OVERHEAD);
_scalar = bound(_scalar, 0, MAX_SCALE);
_baseFee = bound(_baseFee, 0, 1e9 * 20000); // max 20k gwei
oracle.setOverhead(_overhead);
oracle.setScalar(_scalar);
container.initialize(address(0), bytes32(0), 0, 0, uint128(_baseFee), bytes32(0));
uint256 _gasUsed = _overhead + 68 * 16;
for (uint256 i = 0; i < _data.length; i++) {
if (_data[i] == 0) _gasUsed += 4;
else _gasUsed += 16;
}
assertEq(oracle.getL1Fee(_data), (_gasUsed * _baseFee * _scalar) / PRECISION);
}
}