Skip to content

Commit

Permalink
Merge pull request #424 from FastLane-Labs/l2-gas-calc
Browse files Browse the repository at this point in the history
feat: base L2 gas calculator contract
  • Loading branch information
BenSparksCode authored Oct 14, 2024
2 parents 52cfec4 + c560ce5 commit 1744cef
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/solady
Submodule solady updated 120 files
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
"solver-deposit": "source .env && forge script script/solver-deposit.s.sol:SolverAtlasDepositScript --fork-url http://localhost:8545 --broadcast --non-interactive",
"setup-demo": "npm run deploy-atlas-swap-intent-tx-builder && npm run deploy-solver && npm run solver-deposit",

"deploy-gas-calculator-base": "source .env && forge script script/deploy-gas-calculator.s.sol:DeployGasCalculatorScript --rpc-url ${BASE_RPC_URL} --broadcast --etherscan-api-key ${ETHERSCAN_API_KEY} --verify",

"atlas-addr": "echo 'ATLAS:' && jq -r '.ATLAS' deployments.json",
"swap-intent-addr": "echo 'SWAP INTENT DAPP CONTROL:' && jq -r '.SWAP_INTENT_DAPP_CONTROL' deployments.json",
"tx-builder-addr": "echo 'TX BUILDER:' && jq -r '.TX_BUILDER' deployments.json",
Expand Down
57 changes: 57 additions & 0 deletions script/deploy-gas-calculator.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.25;

import "forge-std/Test.sol";

import { DeployBaseScript } from "script/base/deploy-base.s.sol";
import { BaseGasCalculator } from "src/contracts/gasCalculator/BaseGasCalculator.sol";

contract DeployGasCalculatorScript is DeployBaseScript {
// NOTE: Adjust the constructor parameters as needed here:
// - BASE_GAS_PRICE_ORACLE: The address of the gas price oracle contract
// - BASE_CALLDATA_LENGTH_OFFSET: The offset to be applied to the calldata length (can be negative or positive)
// -----------------------------------------------------------------------------------------------
address constant BASE_GAS_PRICE_ORACLE = address(0x420000000000000000000000000000000000000F);
int256 constant BASE_CALLDATA_LENGTH_OFFSET = 0; // can be negative or positive
// -----------------------------------------------------------------------------------------------

function run() external {
console.log("\n=== DEPLOYING GasCalculator ===\n");

console.log("Deploying to chain: \t\t", _getDeployChain());

uint256 deployerPrivateKey = vm.envUint("GOV_PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);

console.log("Deployer address: \t\t", deployer);

uint256 chainId = block.chainid;
address deploymentAddr;

vm.startBroadcast(deployerPrivateKey);

if (chainId == 8453 || chainId == 84_532) {
// Base or Base Sepolia
BaseGasCalculator gasCalculator = new BaseGasCalculator({
gasPriceOracle: BASE_GAS_PRICE_ORACLE,
calldataLenOffset: BASE_CALLDATA_LENGTH_OFFSET
});
deploymentAddr = address(gasCalculator);
} else {
revert("Error: Chain ID not supported");
}

vm.stopBroadcast();

_writeAddressToDeploymentsJson("L2_GAS_CALCULATOR", deploymentAddr);

console.log("\n");
console.log("-------------------------------------------------------------------------------");
console.log("| Contract | Address |");
console.log("-------------------------------------------------------------------------------");
console.log("| L2_GAS_CALCULATOR (Base) | ", address(deploymentAddr), " |");
console.log("-------------------------------------------------------------------------------");
console.log("\n");
console.log("You can find a list of contract addresses from the latest deployment in deployments.json");
}
}
66 changes: 66 additions & 0 deletions src/contracts/gasCalculator/BaseGasCalculator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.25;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IL2GasCalculator } from "src/contracts/interfaces/IL2GasCalculator.sol";

/// @notice Implementation:
/// https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts-bedrock/src/L2/GasPriceOracle.sol
/// @notice Deployment on Base: https://basescan.org/address/0x420000000000000000000000000000000000000f
interface IGasPriceOracle {
function getL1FeeUpperBound(uint256 _unsignedTxSize) external view returns (uint256);
}

contract BaseGasCalculator is IL2GasCalculator, Ownable {
uint256 internal constant _CALLDATA_LENGTH_PREMIUM = 16;
uint256 internal constant _BASE_TRANSACTION_GAS_USED = 21_000;

address public immutable GAS_PRICE_ORACLE;
int256 public calldataLengthOffset;

constructor(address gasPriceOracle, int256 calldataLenOffset) Ownable(msg.sender) {
GAS_PRICE_ORACLE = gasPriceOracle;
calldataLengthOffset = calldataLenOffset;
}

/// @notice Calculate the cost of calldata in ETH on a L2 with a different fee structure than mainnet
/// @param calldataLength The length of the calldata in bytes
/// @return calldataCost The cost of the calldata in ETH
function getCalldataCost(uint256 calldataLength) external view override returns (uint256 calldataCost) {
// `getL1FeeUpperBound` returns the upper bound of the L1 fee in wei. It expects an unsigned transaction size in
// bytes, *not calldata length only*, which makes this function a rough estimate.

// Base execution cost.
calldataCost = calldataLength * _CALLDATA_LENGTH_PREMIUM * tx.gasprice;

// L1 data cost.
// `getL1FeeUpperBound` adds 68 to the size because it expects an unsigned transaction size.
// Remove 68 to the length to account for this.
if (calldataLength < 68) {
calldataLength = 0;
} else {
calldataLength -= 68;
}

int256 _calldataLenOffset = calldataLengthOffset;

if (_calldataLenOffset < 0 && calldataLength < uint256(-_calldataLenOffset)) {
return calldataCost;
}

calldataLength += uint256(_calldataLenOffset);
calldataCost += IGasPriceOracle(GAS_PRICE_ORACLE).getL1FeeUpperBound(calldataLength);
}

/// @notice Gets the cost of initial gas used for a transaction with a different calldata fee than mainnet
/// @param calldataLength The length of the calldata in bytes
function initialGasUsed(uint256 calldataLength) external pure override returns (uint256 gasUsed) {
return _BASE_TRANSACTION_GAS_USED + (calldataLength * _CALLDATA_LENGTH_PREMIUM);
}

/// @notice Sets the calldata length offset
/// @param calldataLenOffset The new calldata length offset
function setCalldataLengthOffset(int256 calldataLenOffset) external onlyOwner {
calldataLengthOffset = calldataLenOffset;
}
}
2 changes: 1 addition & 1 deletion src/contracts/interfaces/IL2GasCalculator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity 0.8.25;

interface IL2GasCalculator {
/// @notice Calculate the cost of calldata in ETH on a L2 with a different fee structure than mainnet
function getCalldataCost(uint256 length) external view returns (uint256 calldataCostETH);
function getCalldataCost(uint256 calldataLength) external view returns (uint256 calldataCost);
/// @notice Gets the cost of initial gas used for a transaction with a different calldata fee than mainnet
function initialGasUsed(uint256 calldataLength) external view returns (uint256 gasUsed);
}
4 changes: 2 additions & 2 deletions src/contracts/types/SolverOperation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ bytes32 constant SOLVER_TYPEHASH = keccak256(
);

// NOTE: The calldata length of this SolverOperation struct is 608 bytes when the `data` field is excluded. This value
// is stored in the `_SOLVER_OP_BASE_CALLDATA` constant in Storage.sol and must be kept up-to-date with any changes to
// this struct.
// is stored in the `_SOLVER_OP_BASE_CALLDATA` constant in AtlasConstants.sol and must be kept up-to-date with any
// changes to this struct.
struct SolverOperation {
address from; // Solver address
address to; // Atlas address
Expand Down

0 comments on commit 1744cef

Please sign in to comment.