Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
888a0f49
Unverified
Commit
888a0f49
authored
May 18, 2022
by
Mark Tyneway
Committed by
GitHub
May 18, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
contracts: add `GasPriceOracle` contract (#2566)
parent
f688a631
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
341 additions
and
0 deletions
+341
-0
.gas-snapshot
contracts-bedrock/.gas-snapshot
+13
-0
GasPriceOracle.sol
contracts-bedrock/contracts/L2/GasPriceOracle.sol
+158
-0
GasPriceOracle.t.sol
contracts-bedrock/contracts/test/GasPriceOracle.t.sol
+170
-0
No files found.
contracts-bedrock/.gas-snapshot
View file @
888a0f49
CrossDomainHashing_Test:test_l2TransactionHash() (gas: 78639)
GasPriceOracle_Test:test_baseFee() (gas: 11216)
GasPriceOracle_Test:test_gasPrice() (gas: 11205)
GasPriceOracle_Test:test_l1BaseFee() (gas: 10626)
GasPriceOracle_Test:test_onlyOwnerSetDecimals() (gas: 10575)
GasPriceOracle_Test:test_onlyOwnerSetOverhead() (gas: 10599)
GasPriceOracle_Test:test_onlyOwnerSetScalar() (gas: 10640)
GasPriceOracle_Test:test_owner() (gas: 9762)
GasPriceOracle_Test:test_setDecimals() (gas: 36798)
GasPriceOracle_Test:test_setGasPriceReverts() (gas: 11659)
GasPriceOracle_Test:test_setL1BaseFeeReverts() (gas: 11658)
GasPriceOracle_Test:test_setOverhead() (gas: 36767)
GasPriceOracle_Test:test_setScalar() (gas: 36840)
GasPriceOracle_Test:test_storageLayout() (gas: 86683)
L1BlockTest:test_basefee() (gas: 7575)
L1BlockTest:test_hash() (gas: 7552)
L1BlockTest:test_number() (gas: 7651)
...
...
contracts-bedrock/contracts/L2/GasPriceOracle.sol
0 → 100644
View file @
888a0f49
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/* External Imports */
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { L1Block } from "../L2/L1Block.sol";
/**
* @title GasPriceOracle
* @dev This contract maintains the variables responsible for computing the L1
* portion of the total fee charged on L2. The values stored in the contract
* are looked up as part of the L2 state transition function and used to compute
* the total fee paid by the user.
* The contract exposes an API that is useful for knowing how large the L1
* portion of their transaction fee will be.
* This predeploy is found at 0x420000000000000000000000000000000000000F in the
* L2 state.
* This contract should be behind an upgradable proxy such that when the gas
* prices change, the values can be updated accordingly.
*/
contract GasPriceOracle is Ownable {
/*************
* Variables *
*************/
// backwards compatibility
uint256 internal spacer0;
uint256 internal spacer1;
// Amortized cost of batch submission per transaction
uint256 public overhead;
// Value to scale the fee up by
uint256 public scalar;
// Number of decimals of the scalar
uint256 public decimals;
/***************
* Constructor *
***************/
/**
* @param _owner Address that will initially own this contract.
*/
constructor(address _owner) Ownable() {
transferOwnership(_owner);
}
/**********
* Events *
**********/
event OverheadUpdated(uint256);
event ScalarUpdated(uint256);
event DecimalsUpdated(uint256);
/********************
* Public Functions *
********************/
// legacy backwards compat
function gasPrice() public returns (uint256) {
return block.basefee;
}
function baseFee() public returns (uint256) {
return block.basefee;
}
function l1BaseFee() public view returns (uint256) {
return L1Block(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES).basefee();
}
/**
* Allows the owner to modify the overhead.
* @param _overhead New overhead
*/
// slither-disable-next-line external-function
function setOverhead(uint256 _overhead) public onlyOwner {
overhead = _overhead;
emit OverheadUpdated(_overhead);
}
/**
* Allows the owner to modify the scalar.
* @param _scalar New scalar
*/
// slither-disable-next-line external-function
function setScalar(uint256 _scalar) public onlyOwner {
scalar = _scalar;
emit ScalarUpdated(_scalar);
}
/**
* Allows the owner to modify the decimals.
* @param _decimals New decimals
*/
// slither-disable-next-line external-function
function setDecimals(uint256 _decimals) public onlyOwner {
decimals = _decimals;
emit DecimalsUpdated(_decimals);
}
/**
* Computes the L1 portion of the fee
* based on the size of the RLP encoded tx
* and the current l1BaseFee
* @param _data Unsigned RLP encoded tx, 6 elements
* @return L1 fee that should be paid for the tx
*/
// slither-disable-next-line external-function
function getL1Fee(bytes memory _data) public 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;
}
// solhint-disable max-line-length
/**
* Computes the amount of L1 gas used for a transaction
* The overhead represents the per batch gas overhead of
* posting both transaction and state roots to L1 given larger
* batch sizes.
* 4 gas for 0 byte
* https://github.com/ethereum/go-ethereum/blob/9ada4a2e2c415e6b0b51c50e901336872e028872/params/protocol_params.go#L33
* 16 gas for non zero byte
* https://github.com/ethereum/go-ethereum/blob/9ada4a2e2c415e6b0b51c50e901336872e028872/params/protocol_params.go#L87
* This will need to be updated if calldata gas prices change
* Account for the transaction being unsigned
* Padding is added to account for lack of signature on transaction
* 1 byte for RLP V prefix
* 1 byte for V
* 1 byte for RLP R prefix
* 32 bytes for R
* 1 byte for RLP S prefix
* 32 bytes for S
* Total: 68 bytes of padding
* @param _data Unsigned RLP encoded tx, 6 elements
* @return Amount of L1 gas used for a transaction
*/
// solhint-enable max-line-length
function getL1GasUsed(bytes memory _data) public view returns (uint256) {
uint256 total = 0;
uint256 length = _data.length;
for (uint256 i = 0; i < length; i++) {
if (_data[i] == 0) {
total += 4;
} else {
total += 16;
}
}
uint256 unsigned = total + overhead;
return unsigned + (68 * 16);
}
}
contracts-bedrock/contracts/test/GasPriceOracle.t.sol
0 → 100644
View file @
888a0f49
//SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import { CommonTest } from "./CommonTest.t.sol";
import { GasPriceOracle } from "../L2/GasPriceOracle.sol";
import { L1Block } from "../L2/L1Block.sol";
import { Lib_BedrockPredeployAddresses } from "../libraries/Lib_BedrockPredeployAddresses.sol";
import { console } from "forge-std/console.sol";
contract GasPriceOracle_Test is CommonTest {
event OverheadUpdated(uint256);
event ScalarUpdated(uint256);
event DecimalsUpdated(uint256);
GasPriceOracle gasOracle;
L1Block l1Block;
address depositor;
function setUp() external {
// place the L1Block contract at the predeploy address
vm.etch(
Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES,
address(new L1Block()).code
);
l1Block = L1Block(Lib_BedrockPredeployAddresses.L1_BLOCK_ATTRIBUTES);
depositor = l1Block.DEPOSITOR_ACCOUNT();
// We are not setting the gas oracle at its predeploy
// address for simplicity purposes. Nothing in this test
// requires it to be at a particular address
gasOracle = new GasPriceOracle(alice);
// set the initial L1 context values
uint64 number = 10;
uint64 timestamp = 11;
uint256 basefee = 100;
bytes32 hash = bytes32(uint256(64));
uint64 sequenceNumber = 0;
vm.prank(depositor);
l1Block.setL1BlockValues(
number,
timestamp,
basefee,
hash,
sequenceNumber
);
}
function test_owner() external {
// alice is passed into the constructor of the gasOracle
assertEq(gasOracle.owner(), alice);
}
function test_storageLayout() external {
// the overhead is at slot 3
vm.prank(gasOracle.owner());
gasOracle.setOverhead(456);
assertEq(
456,
uint256(vm.load(address(gasOracle), bytes32(uint256(3))))
);
// scalar is at slot 4
vm.prank(gasOracle.owner());
gasOracle.setScalar(333);
assertEq(
333,
uint256(vm.load(address(gasOracle), bytes32(uint256(4))))
);
// decimals is at slot 5
vm.prank(gasOracle.owner());
gasOracle.setDecimals(222);
assertEq(
222,
uint256(vm.load(address(gasOracle), bytes32(uint256(5))))
);
}
function test_l1BaseFee() external {
uint256 l1BaseFee = gasOracle.l1BaseFee();
assertEq(l1BaseFee, 100);
}
function test_gasPrice() external {
vm.fee(100);
uint256 gasPrice = gasOracle.gasPrice();
console.log(gasPrice);
assertEq(gasPrice, 100);
}
function test_baseFee() external {
vm.fee(64);
uint256 gasPrice = gasOracle.baseFee();
console.log(gasPrice);
assertEq(gasPrice, 64);
}
function test_setGasPriceReverts() external {
vm.prank(gasOracle.owner());
(bool success, bytes memory returndata) = address(gasOracle).call(
abi.encodeWithSignature(
"setGasPrice(uint256)",
1
)
);
assertEq(success, false);
assertEq(returndata, hex"");
}
function test_setL1BaseFeeReverts() external {
vm.prank(gasOracle.owner());
(bool success, bytes memory returndata) = address(gasOracle).call(
abi.encodeWithSignature(
"setL1BaseFee(uint256)",
1
)
);
assertEq(success, false);
assertEq(returndata, hex"");
}
function test_setOverhead() external {
vm.expectEmit(true, true, true, true);
emit OverheadUpdated(1234);
vm.prank(gasOracle.owner());
gasOracle.setOverhead(1234);
assertEq(gasOracle.overhead(), 1234);
}
function test_onlyOwnerSetOverhead() external {
vm.expectRevert("Ownable: caller is not the owner");
gasOracle.setOverhead(0);
}
function test_setScalar() external {
vm.expectEmit(true, true, true, true);
emit ScalarUpdated(666);
vm.prank(gasOracle.owner());
gasOracle.setScalar(666);
assertEq(gasOracle.scalar(), 666);
}
function test_onlyOwnerSetScalar() external {
vm.expectRevert("Ownable: caller is not the owner");
gasOracle.setScalar(0);
}
function test_setDecimals() external {
vm.expectEmit(true, true, true, true);
emit DecimalsUpdated(18);
vm.prank(gasOracle.owner());
gasOracle.setDecimals(18);
assertEq(gasOracle.decimals(), 18);
}
function test_onlyOwnerSetDecimals() external {
vm.expectRevert("Ownable: caller is not the owner");
gasOracle.setDecimals(0);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment