Commit 579d6ffe authored by Roberto Bayardo's avatar Roberto Bayardo Committed by GitHub

Ecotone L2 contract updates (#8726)

Co-authored-by: default avataranikaraghu <anika.raghuvanshi@coinbase.com>
parent 81366afa
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,11 +9,11 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc"
)
const L1BlockStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"number\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":1001,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"timestamp\",\"offset\":8,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":1002,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"basefee\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"},{\"astId\":1003,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"hash\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_bytes32\"},{\"astId\":1004,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"sequenceNumber\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_uint64\"},{\"astId\":1005,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"batcherHash\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_bytes32\"},{\"astId\":1006,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"l1FeeOverhead\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_uint256\"},{\"astId\":1007,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"l1FeeScalar\",\"offset\":0,\"slot\":\"6\",\"type\":\"t_uint256\"}],\"types\":{\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"}}}"
const L1BlockStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"number\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":1001,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"timestamp\",\"offset\":8,\"slot\":\"0\",\"type\":\"t_uint64\"},{\"astId\":1002,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"basefee\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_uint256\"},{\"astId\":1003,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"hash\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_bytes32\"},{\"astId\":1004,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"sequenceNumber\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_uint64\"},{\"astId\":1005,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"blobBasefeeScalar\",\"offset\":8,\"slot\":\"3\",\"type\":\"t_uint32\"},{\"astId\":1006,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"basefeeScalar\",\"offset\":12,\"slot\":\"3\",\"type\":\"t_uint32\"},{\"astId\":1007,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"batcherHash\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_bytes32\"},{\"astId\":1008,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"l1FeeOverhead\",\"offset\":0,\"slot\":\"5\",\"type\":\"t_uint256\"},{\"astId\":1009,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"l1FeeScalar\",\"offset\":0,\"slot\":\"6\",\"type\":\"t_uint256\"},{\"astId\":1010,\"contract\":\"src/L2/L1Block.sol:L1Block\",\"label\":\"blobBasefee\",\"offset\":0,\"slot\":\"7\",\"type\":\"t_uint256\"}],\"types\":{\"t_bytes32\":{\"encoding\":\"inplace\",\"label\":\"bytes32\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"},\"t_uint32\":{\"encoding\":\"inplace\",\"label\":\"uint32\",\"numberOfBytes\":\"4\"},\"t_uint64\":{\"encoding\":\"inplace\",\"label\":\"uint64\",\"numberOfBytes\":\"8\"}}}"
var L1BlockStorageLayout = new(solc.StorageLayout)
var L1BlockDeployedBin = "0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80638381f58a11610081578063b80777ea1161005b578063b80777ea146101a4578063e591b282146101c4578063e81b2c6d1461020457600080fd5b80638381f58a1461017e5780638b239f73146101925780639e8c49661461019b57600080fd5b806354fd4d50116100b257806354fd4d50146100ff5780635cf249691461014857806364ca23ef1461015157600080fd5b8063015d8eb9146100ce57806309bd5a60146100e3575b600080fd5b6100e16100dc366004610369565b61020d565b005b6100ec60025481565b6040519081526020015b60405180910390f35b61013b6040518060400160405280600581526020017f312e312e3000000000000000000000000000000000000000000000000000000081525081565b6040516100f691906103db565b6100ec60015481565b6003546101659067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100f6565b6000546101659067ffffffffffffffff1681565b6100ec60055481565b6100ec60065481565b6000546101659068010000000000000000900467ffffffffffffffff1681565b6101df73deaddeaddeaddeaddeaddeaddeaddeaddead000181565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100f6565b6100ec60045481565b3373deaddeaddeaddeaddeaddeaddeaddeaddead0001146102b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4c31426c6f636b3a206f6e6c7920746865206465706f7369746f72206163636f60448201527f756e742063616e20736574204c3120626c6f636b2076616c7565730000000000606482015260840160405180910390fd5b6000805467ffffffffffffffff98891668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116998916999099179890981790975560019490945560029290925560038054919094167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009190911617909255600491909155600555600655565b803567ffffffffffffffff8116811461036457600080fd5b919050565b600080600080600080600080610100898b03121561038657600080fd5b61038f8961034c565b975061039d60208a0161034c565b965060408901359550606089013594506103b960808a0161034c565b979a969950949793969560a0850135955060c08501359460e001359350915050565b600060208083528351808285015260005b81811015610408578581018301518582016040015282016103ec565b8181111561041a576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a"
var L1BlockDeployedBin = "0x608060405234801561001057600080fd5b50600436106100f55760003560e01c80637744864d11610097578063b80777ea11610066578063b80777ea14610212578063bfb14fb714610232578063e591b28214610252578063e81b2c6d1461029257600080fd5b80637744864d146101bb5780638381f58a146101ec5780638b239f73146102005780639e8c49661461020957600080fd5b806354fd4d50116100d357806354fd4d50146101335780635cf249691461017c57806364ca23ef1461018557806375c7e4a9146101b257600080fd5b8063015d8eb9146100fa57806309bd5a601461010f578063440a5e201461012b575b600080fd5b61010d61010836600461044c565b61029b565b005b61011860025481565b6040519081526020015b60405180910390f35b61010d6103da565b61016f6040518060400160405280600581526020017f312e322e3000000000000000000000000000000000000000000000000000000081525081565b60405161012291906104be565b61011860015481565b6003546101999067ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610122565b61011860075481565b6003546101d79068010000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610122565b6000546101999067ffffffffffffffff1681565b61011860055481565b61011860065481565b6000546101999068010000000000000000900467ffffffffffffffff1681565b6003546101d7906c01000000000000000000000000900463ffffffff1681565b61026d73deaddeaddeaddeaddeaddeaddeaddeaddead000181565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610122565b61011860045481565b3373deaddeaddeaddeaddeaddeaddeaddeaddead000114610342576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603b60248201527f4c31426c6f636b3a206f6e6c7920746865206465706f7369746f72206163636f60448201527f756e742063616e20736574204c3120626c6f636b2076616c7565730000000000606482015260840160405180910390fd5b6000805467ffffffffffffffff98891668010000000000000000027fffffffffffffffffffffffffffffffff00000000000000000000000000000000909116998916999099179890981790975560019490945560029290925560038054919094167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009190911617909255600491909155600555600655565b3373deaddeaddeaddeaddeaddeaddeaddeaddead00011461040357633cc50b456000526004601cfd5b60043560801c60035560143560801c600055602435600155604435600755606435600255608435600455565b803567ffffffffffffffff8116811461044757600080fd5b919050565b600080600080600080600080610100898b03121561046957600080fd5b6104728961042f565b975061048060208a0161042f565b9650604089013595506060890135945061049c60808a0161042f565b979a969950949793969560a0850135955060c08501359460e001359350915050565b600060208083528351808285015260005b818110156104eb578581018301518582016040015282016104cf565b818111156104fd576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01692909201604001939250505056fea164736f6c634300080f000a"
func init() {
......
......@@ -48,12 +48,12 @@
"sourceCodeHash": "0xd787bd2a192ba5025fa0a8de2363af66a8de20de226e411bdb576adb64636cd0"
},
"src/L2/GasPriceOracle.sol": {
"initCodeHash": "0x6e235d82993606ca4d19b523096678b3cb13bad7a140567dd4f42de2cf0a2b8e",
"sourceCodeHash": "0x6dd53c5d8164eb2c96c3e210d0b667a24daa674056c9b75ac1f93433b7e737fa"
"initCodeHash": "0xc980e2ca81850ca4f72fd207e8f8a4e5eebe966393c03e3ecc21c5e87a55aa05",
"sourceCodeHash": "0x9eea8b1f68dd6a244323d58aaef24a3938e166575c71b3665a804dd4f32060de"
},
"src/L2/L1Block.sol": {
"initCodeHash": "0x280927b73942e7d00c6170b15c0b1e087da0be3adf5a63a59d3a71ad64b33685",
"sourceCodeHash": "0x50e1aae72b91da2d288bbd0b7ffb693b13bd375962d9c1ac0d8b47a913520fd9"
"initCodeHash": "0xecdd18698880762e6c9561d271a447e64fdad03f25d144580fb0ebb39bfb7148",
"sourceCodeHash": "0x271b6c80593bca95dfcd3543116bed541d8177f0751bbded611680b64a81818a"
},
"src/L2/L1FeeVault.sol": {
"initCodeHash": "0x2744d34573be83206d1b75d049d18a7bb37f9058e68c0803e5008c46b0dc2474",
......
......@@ -683,6 +683,30 @@
"length": 29,
"filename_relative": "src/universal/Proxy.sol"
},
{
"id": "8a3cbb409970f13c99fdfb6c1c35d7cdb67fa2ea79f2578425f5d167153382c3",
"impact": "High",
"confidence": "High",
"check": "uninitialized-state",
"description": "L1Block.blobBasefee (src/L2/L1Block.sol#50) is never initialized. It is used in:\n\t- L1Block.setL1BlockValuesEcotone() (src/L2/L1Block.sol#101-118)\n",
"type": "variable",
"name": "blobBasefee",
"start": 1897,
"length": 26,
"filename_relative": "src/L2/L1Block.sol"
},
{
"id": "8a3cbb409970f13c99fdfb6c1c35d7cdb67fa2ea79f2578425f5d167153382c3",
"impact": "High",
"confidence": "High",
"check": "uninitialized-state",
"description": "L1Block.blobBasefee (src/L2/L1Block.sol#50) is never initialized. It is used in:\n\t- L1Block.setL1BlockValuesEcotone() (src/L2/L1Block.sol#101-118)\n",
"type": "function",
"name": "setL1BlockValuesEcotone",
"start": 3879,
"length": 956,
"filename_relative": "src/L2/L1Block.sol"
},
{
"id": "89460308ae3bd86a612657eb7bfe28221ced6a7a7fe723ec2a19149bfc819cb5",
"impact": "Medium",
......
......@@ -25,6 +25,45 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "basefeeScalar",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blobBasefee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blobBasefeeScalar",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "decimals",
......@@ -89,6 +128,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "isEcotone",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "l1BaseFee",
......@@ -128,6 +180,13 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "setEcotone",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "version",
......
......@@ -25,6 +25,19 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "basefeeScalar",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "batcherHash",
......@@ -38,6 +51,32 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blobBasefee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "blobBasefeeScalar",
"outputs": [
{
"internalType": "uint32",
"name": "",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "hash",
......@@ -151,6 +190,13 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "setL1BlockValuesEcotone",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "timestamp",
......
[]
\ No newline at end of file
[
{
"bytes": "1",
"label": "isEcotone",
"offset": 0,
"slot": "0",
"type": "bool"
}
]
\ No newline at end of file
......@@ -34,6 +34,20 @@
"slot": "3",
"type": "uint64"
},
{
"bytes": "4",
"label": "blobBasefeeScalar",
"offset": 8,
"slot": "3",
"type": "uint32"
},
{
"bytes": "4",
"label": "basefeeScalar",
"offset": 12,
"slot": "3",
"type": "uint32"
},
{
"bytes": "32",
"label": "batcherHash",
......@@ -54,5 +68,12 @@
"offset": 0,
"slot": "6",
"type": "uint256"
},
{
"bytes": "32",
"label": "blobBasefee",
"offset": 0,
"slot": "7",
"type": "uint256"
}
]
\ No newline at end of file
......@@ -24,20 +24,31 @@ contract GasPriceOracle is ISemver {
uint256 public constant DECIMALS = 6;
/// @notice Semantic version.
/// @custom:semver 1.1.0
string public constant version = "1.1.0";
/// @custom:semver 1.2.0
string public constant version = "1.2.0";
/// @notice Indicates whether the network has gone through the Ecotone upgrade.
bool public isEcotone;
/// @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) {
uint256 l1GasUsed = getL1GasUsed(_data);
uint256 l1Fee = l1GasUsed * l1BaseFee();
uint256 divisor = 10 ** DECIMALS;
uint256 unscaled = l1Fee * scalar();
uint256 scaled = unscaled / divisor;
return scaled;
if (isEcotone) {
return _getL1FeeEcotone(_data);
}
return _getL1FeeBedrock(_data);
}
/// @notice Set chain to be Ecotone chain (callable by depositor account)
function setEcotone() external {
require(
msg.sender == L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).DEPOSITOR_ACCOUNT(),
"GasPriceOracle: only the depositor account can set isEcotone flag"
);
require(isEcotone == false, "GasPriceOracle: Ecotone already active");
isEcotone = true;
}
/// @notice Retrieves the current gas price (base fee).
......@@ -52,15 +63,19 @@ contract GasPriceOracle is ISemver {
return block.basefee;
}
/// @custom:legacy
/// @notice Retrieves the current fee overhead.
/// @return Current fee overhead.
function overhead() public view returns (uint256) {
require(!isEcotone, "GasPriceOracle: overhead() is deprecated");
return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeOverhead();
}
/// @custom:legacy
/// @notice Retrieves the current fee scalar.
/// @return Current fee scalar.
function scalar() public view returns (uint256) {
require(!isEcotone, "GasPriceOracle: scalar() is deprecated");
return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeScalar();
}
......@@ -70,6 +85,24 @@ contract GasPriceOracle is ISemver {
return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).basefee();
}
/// @notice Retrieves the current blob base fee.
/// @return Current blob base fee.
function blobBasefee() public view returns (uint256) {
return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).blobBasefee();
}
/// @notice Retrieves the current base fee scalar.
/// @return Current base fee scalar.
function basefeeScalar() public view returns (uint32) {
return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).basefeeScalar();
}
/// @notice Retrieves the current blob base fee scalar.
/// @return Current blob base fee scalar.
function blobBasefeeScalar() public view returns (uint32) {
return L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).blobBasefeeScalar();
}
/// @custom:legacy
/// @notice Retrieves the number of decimals used in the scalar.
/// @return Number of decimals used in the scalar.
......@@ -77,13 +110,43 @@ contract GasPriceOracle is ISemver {
return DECIMALS;
}
/// @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.
/// @notice Computes the amount of L1 gas used for a transaction. 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) public view returns (uint256) {
uint256 l1GasUsed = _getCalldataGas(_data);
if (isEcotone) {
return l1GasUsed;
}
return l1GasUsed + L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeOverhead();
}
/// @notice Computation of the L1 portion of the fee for Bedrock.
/// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for.
/// @return L1 fee that should be paid for the tx
function _getL1FeeBedrock(bytes memory _data) internal view returns (uint256) {
uint256 l1GasUsed = _getCalldataGas(_data);
uint256 fee = (l1GasUsed + L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeOverhead()) * l1BaseFee()
* L1Block(Predeploys.L1_BLOCK_ATTRIBUTES).l1FeeScalar();
return fee / (10 ** DECIMALS);
}
/// @notice L1 portion of the fee after Ecotone.
/// @param _data Unsigned fully RLP-encoded transaction to get the L1 fee for.
/// @return L1 fee that should be paid for the tx
function _getL1FeeEcotone(bytes memory _data) internal view returns (uint256) {
uint256 l1GasUsed = _getCalldataGas(_data);
uint256 scaledBasefee = basefeeScalar() * 16 * l1BaseFee();
uint256 scaledBlobBasefee = blobBasefeeScalar() * blobBasefee();
uint256 fee = l1GasUsed * (scaledBasefee + scaledBlobBasefee);
return fee / (16 * 10 ** DECIMALS);
}
/// @notice L1 gas estimation calculation.
/// @param _data Unsigned fully RLP-encoded transaction to get the L1 gas for.
/// @return Amount of L1 gas used to publish the transaction.
function _getCalldataGas(bytes memory _data) internal pure returns (uint256) {
uint256 total = 0;
uint256 length = _data.length;
for (uint256 i = 0; i < length; i++) {
......@@ -93,7 +156,6 @@ contract GasPriceOracle is ISemver {
total += 16;
}
}
uint256 unsigned = total + overhead();
return unsigned + (68 * 16);
return total + (68 * 16);
}
}
......@@ -29,18 +29,30 @@ contract L1Block is ISemver {
/// @notice The number of L2 blocks in the same epoch.
uint64 public sequenceNumber;
/// @notice The scalar value applied to the L1 blob base fee portion of the blob-capable L1 cost func.
uint32 public blobBasefeeScalar;
/// @notice The scalar value applied to the L1 base fee portion of the blob-capable L1 cost func.
uint32 public basefeeScalar;
/// @notice The versioned hash to authenticate the batcher by.
bytes32 public batcherHash;
/// @notice The overhead value applied to the L1 portion of the transaction fee.
/// @custom:legacy
uint256 public l1FeeOverhead;
/// @notice The scalar value applied to the L1 portion of the transaction fee.
/// @custom:legacy
uint256 public l1FeeScalar;
/// @custom:semver 1.1.0
string public constant version = "1.1.0";
/// @notice The latest L1 blob basefee.
uint256 public blobBasefee;
/// @custom:semver 1.2.0
string public constant version = "1.2.0";
/// @custom:legacy
/// @notice Updates the L1 block values.
/// @param _number L1 blocknumber.
/// @param _timestamp L1 timestamp.
......@@ -73,4 +85,35 @@ contract L1Block is ISemver {
l1FeeOverhead = _l1FeeOverhead;
l1FeeScalar = _l1FeeScalar;
}
/// @notice Updates the L1 block values for an Ecotone upgraded chain.
/// Params are packed and passed in as raw msg.data instead of ABI to reduce calldata size.
/// Params are expected to be in the following order:
/// 1. _basefeeScalar L1 basefee scalar
/// 2. _blobBasefeeScalar L1 blob basefee scalar
/// 3. _sequenceNumber Number of L2 blocks since epoch start.
/// 4. _timestamp L1 timestamp.
/// 5. _number L1 blocknumber.
/// 6. _basefee L1 basefee.
/// 7. _blobBasefee L1 blobBasefee.
/// 8. _hash L1 blockhash.
/// 9. _batcherHash Versioned hash to authenticate batcher by.
function setL1BlockValuesEcotone() external {
assembly {
// Revert if the caller is not the depositor account.
if xor(caller(), DEPOSITOR_ACCOUNT) {
mstore(0x00, 0x3cc50b45) // 0x3cc50b45 is the 4-byte selector of "NotDepositor()"
revert(0x1C, 0x04) // returns the stored 4-byte selector from above
}
let data := calldataload(4)
// sequencenum (uint64), blobBasefeeScalar (uint32), basefeeScalar (uint32)
sstore(sequenceNumber.slot, shr(128, calldataload(4)))
// number (uint64) and timestamp (uint64)
sstore(number.slot, shr(128, calldataload(20)))
sstore(basefee.slot, calldataload(36)) // uint256
sstore(blobBasefee.slot, calldataload(68)) // uint256
sstore(hash.slot, calldataload(100)) // bytes32
sstore(batcherHash.slot, calldataload(132)) // bytes32
}
}
}
......@@ -133,4 +133,44 @@ library Encoding {
}
return (nonce, version);
}
/// @notice Returns an appropriately encoded call to L1Block.setL1BlockValuesEcotone
/// @param basefeeScalar L1 basefee Scalar
/// @param blobBasefeeScalar L1 blob basefee Scalar
/// @param sequenceNumber Number of L2 blocks since epoch start.
/// @param timestamp L1 timestamp.
/// @param number L1 blocknumber.
/// @param basefee L1 basefee.
/// @param blobBasefee L1 blob basefee.
/// @param hash L1 blockhash.
/// @param batcherHash Versioned hash to authenticate batcher by.
function encodeSetL1BlockValuesEcotone(
uint32 basefeeScalar,
uint32 blobBasefeeScalar,
uint64 sequenceNumber,
uint64 timestamp,
uint64 number,
uint256 basefee,
uint256 blobBasefee,
bytes32 hash,
bytes32 batcherHash
)
internal
pure
returns (bytes memory)
{
bytes4 functionSignature = bytes4(keccak256("setL1BlockValuesEcotone()"));
return abi.encodePacked(
functionSignature,
basefeeScalar,
blobBasefeeScalar,
sequenceNumber,
timestamp,
number,
basefee,
blobBasefee,
hash,
batcherHash
);
}
}
......@@ -4,6 +4,9 @@ pragma solidity 0.8.15;
// Testing utilities
import { CommonTest } from "test/setup/CommonTest.sol";
// Libraries
import { Encoding } from "src/libraries/Encoding.sol";
contract GasPriceOracle_Test is CommonTest {
event OverheadUpdated(uint256);
event ScalarUpdated(uint256);
......@@ -14,18 +17,27 @@ contract GasPriceOracle_Test is CommonTest {
// The initial L1 context values
uint64 constant number = 10;
uint64 constant timestamp = 11;
uint256 constant basefee = 100;
uint256 constant basefee = 2 * (10 ** 6);
uint256 constant blobBasefee = 3 * (10 ** 6);
bytes32 constant hash = bytes32(uint256(64));
uint64 constant sequenceNumber = 0;
bytes32 constant batcherHash = bytes32(uint256(777));
uint256 constant l1FeeOverhead = 310;
uint256 constant l1FeeScalar = 10;
uint32 constant blobBasefeeScalar = 15;
uint32 constant basefeeScalar = 20;
/// @dev Sets up the test suite.
function setUp() public virtual override {
super.setUp();
depositor = l1Block.DEPOSITOR_ACCOUNT();
}
}
contract GasPriceOracleBedrock_Test is GasPriceOracle_Test {
/// @dev Sets up the test suite.
function setUp() public virtual override {
super.setUp();
vm.prank(depositor);
l1Block.setL1BlockValues({
......@@ -93,3 +105,91 @@ contract GasPriceOracle_Test is CommonTest {
assertEq(returndata, hex"");
}
}
contract GasPriceOracleEcotone_Test is GasPriceOracle_Test {
/// @dev Sets up the test suite.
function setUp() public virtual override {
super.setUp();
bytes memory calldataPacked = Encoding.encodeSetL1BlockValuesEcotone(
basefeeScalar, blobBasefeeScalar, sequenceNumber, timestamp, number, basefee, blobBasefee, hash, batcherHash
);
// Execute the function call
vm.prank(depositor);
(bool success,) = address(l1Block).call(calldataPacked);
require(success, "Function call failed");
vm.prank(depositor);
gasPriceOracle.setEcotone();
}
/// @dev Tests that `setEcotone` is only callable by the depositor.
function test_setEcotone_wrongCaller_reverts() external {
vm.expectRevert("GasPriceOracle: only the depositor account can set isEcotone flag");
gasPriceOracle.setEcotone();
}
/// @dev Tests that `gasPrice` is set correctly.
function test_gasPrice_succeeds() external {
vm.fee(100);
uint256 gasPrice = gasPriceOracle.gasPrice();
assertEq(gasPrice, 100);
}
/// @dev Tests that `baseFee` is set correctly.
function test_baseFee_succeeds() external {
vm.fee(64);
uint256 gasPrice = gasPriceOracle.baseFee();
assertEq(gasPrice, 64);
}
/// @dev Tests that `overhead` reverts since it was removed in ecotone.
function test_overhead_legacyFunction_reverts() external {
vm.expectRevert("GasPriceOracle: overhead() is deprecated");
gasPriceOracle.overhead();
}
/// @dev Tests that `scalar` reverts since it was removed in ecotone.
function test_scalar_legacyFunction_reverts() external {
vm.expectRevert("GasPriceOracle: scalar() is deprecated");
gasPriceOracle.scalar();
}
/// @dev Tests that `l1BaseFee` is set correctly.
function test_l1BaseFee_succeeds() external {
assertEq(gasPriceOracle.l1BaseFee(), basefee);
}
/// @dev Tests that `blobBasefee` is set correctly.
function test_blobBasefee_succeeds() external {
assertEq(gasPriceOracle.blobBasefee(), blobBasefee);
}
/// @dev Tests that `basefeeScalar` is set correctly.
function test_basefeeScalar_succeeds() external {
assertEq(gasPriceOracle.basefeeScalar(), basefeeScalar);
}
/// @dev Tests that `blobBasefeeScalar` is set correctly.
function test_blobBasefeeScalar_succeeds() external {
assertEq(gasPriceOracle.blobBasefeeScalar(), blobBasefeeScalar);
}
/// @dev Tests that `decimals` is set correctly.
function test_decimals_succeeds() external {
assertEq(gasPriceOracle.decimals(), 6);
assertEq(gasPriceOracle.DECIMALS(), 6);
}
/// @dev Tests that `getL1GasUsed` and `getL1Fee` return expected values
function test_getL1Fee_succeeds() external {
bytes memory data = hex"0000010203"; // 2 zero bytes, 3 non-zero bytes
// (2*4) + (3*16) + (68*16) == 1144
uint256 gas = gasPriceOracle.getL1GasUsed(data);
assertEq(gas, 1144);
uint256 price = gasPriceOracle.getL1Fee(data);
// gas * (2M*16*20 + 3M*15) / 16M == 48977.5
assertEq(price, 48977);
}
}
......@@ -4,6 +4,9 @@ pragma solidity 0.8.15;
// Testing utilities
import { CommonTest } from "test/setup/CommonTest.sol";
// Libraries
import { Encoding } from "src/libraries/Encoding.sol";
// Target contract
import { L1Block } from "src/L2/L1Block.sol";
......@@ -13,22 +16,12 @@ contract L1BlockTest is CommonTest {
/// @dev Sets up the test suite.
function setUp() public virtual override {
super.setUp();
depositor = l1Block.DEPOSITOR_ACCOUNT();
vm.prank(depositor);
l1Block.setL1BlockValues({
_number: uint64(1),
_timestamp: uint64(2),
_basefee: 3,
_hash: keccak256(abi.encode(block.number)),
_sequenceNumber: uint64(4),
_batcherHash: bytes32(0),
_l1FeeOverhead: 2,
_l1FeeScalar: 3
});
}
}
/// @dev Tests that `setL1BlockValues` updates the values correctly.
contract L1BlockBedrock_Test is L1BlockTest {
// @dev Tests that `setL1BlockValues` updates the values correctly.
function testFuzz_updatesValues_succeeds(
uint64 n,
uint64 t,
......@@ -53,31 +46,6 @@ contract L1BlockTest is CommonTest {
assertEq(l1Block.l1FeeScalar(), fs);
}
/// @dev Tests that `number` returns the correct value.
function test_number_succeeds() external {
assertEq(l1Block.number(), uint64(1));
}
/// @dev Tests that `timestamp` returns the correct value.
function test_timestamp_succeeds() external {
assertEq(l1Block.timestamp(), uint64(2));
}
/// @dev Tests that `basefee` returns the correct value.
function test_basefee_succeeds() external {
assertEq(l1Block.basefee(), 3);
}
/// @dev Tests that `hash` returns the correct value.
function test_hash_succeeds() external {
assertEq(l1Block.hash(), keccak256(abi.encode(block.number)));
}
/// @dev Tests that `sequenceNumber` returns the correct value.
function test_sequenceNumber_succeeds() external {
assertEq(l1Block.sequenceNumber(), uint64(4));
}
/// @dev Tests that `setL1BlockValues` can set max values.
function test_updateValues_succeeds() external {
vm.prank(depositor);
......@@ -93,3 +61,90 @@ contract L1BlockTest is CommonTest {
});
}
}
contract L1BlockEcotone_Test is L1BlockTest {
/// @dev Tests that setL1BlockValuesEcotone updates the values appropriately.
function testFuzz_setL1BlockValuesEcotone_succeeds(
uint32 basefeeScalar,
uint32 blobBasefeeScalar,
uint64 sequenceNumber,
uint64 timestamp,
uint64 number,
uint256 basefee,
uint256 blobBasefee,
bytes32 hash,
bytes32 batcherHash
)
external
{
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesEcotone(
basefeeScalar, blobBasefeeScalar, sequenceNumber, timestamp, number, basefee, blobBasefee, hash, batcherHash
);
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "Function call failed");
assertEq(l1Block.basefeeScalar(), basefeeScalar);
assertEq(l1Block.blobBasefeeScalar(), blobBasefeeScalar);
assertEq(l1Block.sequenceNumber(), sequenceNumber);
assertEq(l1Block.timestamp(), timestamp);
assertEq(l1Block.number(), number);
assertEq(l1Block.basefee(), basefee);
assertEq(l1Block.blobBasefee(), blobBasefee);
assertEq(l1Block.hash(), hash);
assertEq(l1Block.batcherHash(), batcherHash);
// ensure we didn't accidentally pollute the 128 bits of the sequencenum+scalars slot that
// should be empty
bytes32 scalarsSlot = vm.load(address(l1Block), bytes32(uint256(3)));
bytes32 mask128 = hex"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000";
assertEq(0, scalarsSlot & mask128);
// ensure we didn't accidentally pollute the 128 bits of the number & timestamp slot that
// should be empty
bytes32 numberTimestampSlot = vm.load(address(l1Block), bytes32(uint256(0)));
assertEq(0, numberTimestampSlot & mask128);
}
/// @dev Tests that `setL1BlockValuesEcotone` succeeds if sender address is the depositor
function test_setL1BlockValuesEcotone_isDepositor_succeeds() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesEcotone(
type(uint32).max,
type(uint32).max,
type(uint64).max,
type(uint64).max,
type(uint64).max,
type(uint256).max,
type(uint256).max,
bytes32(type(uint256).max),
bytes32(type(uint256).max)
);
vm.prank(depositor);
(bool success,) = address(l1Block).call(functionCallDataPacked);
assertTrue(success, "function call failed");
}
/// @dev Tests that `setL1BlockValuesEcotone` fails if sender address is not the depositor
function test_setL1BlockValuesEcotone_notDepositor_fails() external {
bytes memory functionCallDataPacked = Encoding.encodeSetL1BlockValuesEcotone(
type(uint32).max,
type(uint32).max,
type(uint64).max,
type(uint64).max,
type(uint64).max,
type(uint256).max,
type(uint256).max,
bytes32(type(uint256).max),
bytes32(type(uint256).max)
);
(bool success, bytes memory data) = address(l1Block).call(functionCallDataPacked);
assertTrue(!success, "function call should have failed");
// make sure return value is the expected function selector for "NotDepositor()"
bytes memory expReturn = hex"3cc50b45";
assertEq(data, expReturn);
}
}
......@@ -173,8 +173,8 @@ ways:
- using direct storage-reads:
- basefee `uint256` in slot `1`
- blobBasefee `uint256` in slot `7`
- l1BasefeeScalar big-endian `uint32` slot `8` offset `4`
- l1BlobBasefeeScalar as big-endian `uint32` in slot `8` offset `0`
- l1BasefeeScalar big-endian `uint32` slot `3` at offset `12`
- l1BlobBasefeeScalar big-endian `uint32` in slot `3` at offset `8`
## Engine API
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment