Skip to content

Commit

Permalink
feat: configurable transact gas limits (#61)
Browse files Browse the repository at this point in the history
* feat: move Transact to its own contract

* feat: non-configurable gas limits

* feat: configurable gas limits
  • Loading branch information
anna-carroll authored Jul 15, 2024
1 parent a24ddde commit 9e8e460
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 106 deletions.
31 changes: 18 additions & 13 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,28 @@ OrdersTest:test_sweepERC20() (gas: 60446)
OrdersTest:test_sweepETH() (gas: 81940)
OrdersTest:test_underflowETH() (gas: 63528)
PassageTest:test_configureEnter() (gas: 82311)
PassageTest:test_disallowedEnter() (gas: 17916)
PassageTest:test_enter() (gas: 25563)
PassageTest:test_enterToken() (gas: 64332)
PassageTest:test_enterToken_defaultChain() (gas: 62915)
PassageTest:test_enterTransact() (gas: 60890)
PassageTest:test_enter_defaultChain() (gas: 24033)
PassageTest:test_fallback() (gas: 21534)
PassageTest:test_onlyTokenAdmin() (gas: 16926)
PassageTest:test_receive() (gas: 21384)
PassageTest:test_setUp() (gas: 16968)
PassageTest:test_transact() (gas: 58562)
PassageTest:test_transact_defaultChain() (gas: 57475)
PassageTest:test_withdraw() (gas: 59166)
PassageTest:test_disallowedEnter() (gas: 17938)
PassageTest:test_enter() (gas: 25507)
PassageTest:test_enterToken() (gas: 64354)
PassageTest:test_enterToken_defaultChain() (gas: 62870)
PassageTest:test_enter_defaultChain() (gas: 24011)
PassageTest:test_fallback() (gas: 21445)
PassageTest:test_onlyTokenAdmin() (gas: 16881)
PassageTest:test_receive() (gas: 21339)
PassageTest:test_setUp() (gas: 16901)
PassageTest:test_withdraw() (gas: 59188)
RollupPassageTest:test_exit() (gas: 22347)
RollupPassageTest:test_exitToken() (gas: 50183)
RollupPassageTest:test_fallback() (gas: 19883)
RollupPassageTest:test_receive() (gas: 19844)
TransactTest:test_configureGas() (gas: 22828)
TransactTest:test_enterTransact() (gas: 103961)
TransactTest:test_onlyGasAdmin() (gas: 8810)
TransactTest:test_setUp() (gas: 17494)
TransactTest:test_transact() (gas: 101431)
TransactTest:test_transact_defaultChain() (gas: 100544)
TransactTest:test_transact_globalGasLimit() (gas: 105063)
TransactTest:test_transact_perTransactGasLimit() (gas: 32774)
ZenithTest:test_addSequencer() (gas: 88121)
ZenithTest:test_badSignature() (gas: 37241)
ZenithTest:test_incorrectHostBlock() (gas: 35086)
Expand Down
10 changes: 6 additions & 4 deletions script/Zenith.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ pragma solidity ^0.8.24;
import {Script} from "forge-std/Script.sol";
import {Zenith} from "../src/Zenith.sol";
import {Passage, RollupPassage} from "../src/Passage.sol";
import {Transactor} from "../src/Transact.sol";
import {HostOrders, RollupOrders} from "../src/Orders.sol";

contract ZenithScript is Script {
// deploy:
// forge script ZenithScript --sig "deploy(uint256,address,address)" --rpc-url $RPC_URL --etherscan-api-key $ETHERSCAN_API_KEY --private-key $PRIVATE_KEY --broadcast --verify $ROLLUP_CHAIN_ID $WITHDRAWAL_ADMIN_ADDRESS $INITIAL_ENTER_TOKENS_ARRAY $SEQUENCER_ADMIN_ADDRESS
// forge script ZenithScript --sig "deploy(uint256,address,address)" --rpc-url $RPC_URL --etherscan-api-key $ETHERSCAN_API_KEY --private-key $PRIVATE_KEY --broadcast --verify $ROLLUP_CHAIN_ID $WITHDRAWAL_ADMIN_ADDRESS $INITIAL_ENTER_TOKENS_ARRAY $SEQUENCER_AND_GAS_ADMIN_ADDRESS
function deploy(
uint256 defaultRollupChainId,
address withdrawalAdmin,
address[] memory initialEnterTokens,
address sequencerAdmin
) public returns (Zenith z, Passage p, HostOrders m) {
address sequencerAndGasAdmin
) public returns (Zenith z, Passage p, Transactor t, HostOrders m) {
vm.startBroadcast();
z = new Zenith(sequencerAdmin);
z = new Zenith(sequencerAndGasAdmin);
p = new Passage(defaultRollupChainId, withdrawalAdmin, initialEnterTokens);
t = new Transactor(defaultRollupChainId, sequencerAndGasAdmin, p, 30_000_000, 5_000_000);
m = new HostOrders();
}

Expand Down
59 changes: 0 additions & 59 deletions src/Passage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,6 @@ contract Passage {
uint256 indexed rollupChainId, address indexed rollupRecipient, address indexed token, uint256 amount
);

/// @notice Emitted to send a special transaction to the rollup.
event Transact(
uint256 indexed rollupChainId,
address indexed sender,
address indexed to,
bytes data,
uint256 value,
uint256 gas,
uint256 maxFeePerGas
);

/// @notice Emitted when the admin withdraws tokens from the contract.
event Withdrawal(address indexed token, address indexed recipient, uint256 amount);

Expand Down Expand Up @@ -106,54 +95,6 @@ contract Passage {
enterToken(defaultRollupChainId, rollupRecipient, token, amount);
}

/// @notice Allows a special transaction to be sent to the rollup with sender == L1 msg.sender.
/// @dev Transaction is processed after normal rollup block execution.
/// @dev See `enterTransact` for docs.
function transact(
uint256 rollupChainId,
address to,
bytes calldata data,
uint256 value,
uint256 gas,
uint256 maxFeePerGas
) public payable {
enterTransact(rollupChainId, msg.sender, to, data, value, gas, maxFeePerGas);
}

/// @dev See `transact` for docs.
function transact(address to, bytes calldata data, uint256 value, uint256 gas, uint256 maxFeePerGas)
external
payable
{
enterTransact(defaultRollupChainId, msg.sender, to, data, value, gas, maxFeePerGas);
}

/// @notice Send Ether on the rollup, send a special transaction to be sent to the rollup with sender == L1 msg.sender.
/// @dev Enter and Transact are processed after normal rollup block execution.
/// @dev See `enter` for Enter docs.
/// @param rollupChainId - The rollup chain to send the transaction to.
/// @param etherRecipient - The recipient of the ether.
/// @param to - The address to call on the rollup.
/// @param data - The data to send to the rollup.
/// @param value - The amount of Ether to send on the rollup.
/// @param gas - The gas limit for the transaction.
/// @param maxFeePerGas - The maximum fee per gas for the transaction (per EIP-1559).
/// @custom:emits Transact indicating the transaction to mine on the rollup.
function enterTransact(
uint256 rollupChainId,
address etherRecipient,
address to,
bytes calldata data,
uint256 value,
uint256 gas,
uint256 maxFeePerGas
) public payable {
// if msg.value is attached, Enter
enter(rollupChainId, etherRecipient);
// emit Transact event
emit Transact(rollupChainId, msg.sender, to, data, value, gas, maxFeePerGas);
}

/// @notice Alow/Disallow a given ERC20 token to enter the rollup.
function configureEnter(address token, bool _canEnter) external {
if (msg.sender != tokenAdmin) revert OnlyTokenAdmin();
Expand Down
136 changes: 136 additions & 0 deletions src/Transact.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {Passage} from "./Passage.sol";

/// @notice A contract deployed to Host chain that enables transactions from L1 to be sent on an L2.
contract Transactor {
/// @notice The chainId of rollup that Ether will be sent to by default when entering the rollup via fallback() or receive().
uint256 public immutable defaultRollupChainId;

/// @notice The address that is allowed to configure `transact` gas limits.
address public immutable gasAdmin;

/// @notice The address of the Passage contract, to enable transact + enter.
Passage public immutable passage;

/// @notice The sum of `transact` calls in a block cannot use more than this limit.
uint256 public perBlockGasLimit;

/// @notice Each `transact` call cannot use more than this limit.
uint256 public perTransactGasLimit;

/// @notice The total gas used by `transact` so far in this block.
/// rollupChainId => block number => `transasct` gasLimit used so far.
mapping(uint256 => mapping(uint256 => uint256)) public transactGasUsed;

/// @notice Emitted to send a special transaction to the rollup.
event Transact(
uint256 indexed rollupChainId,
address indexed sender,
address indexed to,
bytes data,
uint256 value,
uint256 gas,
uint256 maxFeePerGas
);

/// @notice Emitted when the admin configures gas limits.
event GasConfigured(uint256 perBlock, uint256 perTransact);

/// @notice Thrown when attempting to use more then the current global `transact` gasLimit for the block.
error PerBlockTransactGasLimit();

/// @notice Thrown when attempting to use too much gas per single `transact` call.
error PerTransactGasLimit();

/// @notice Thrown when attempting to configure gas if not the admin.
error OnlyGasAdmin();

/// @param _defaultRollupChainId - the chainId of the rollup that Ether will be sent to by default
/// when entering the rollup via fallback() or receive() fns.
constructor(
uint256 _defaultRollupChainId,
address _gasAdmin,
Passage _passage,
uint256 _perBlockGasLimit,
uint256 _perTransactGasLimit
) {
defaultRollupChainId = _defaultRollupChainId;
gasAdmin = _gasAdmin;
passage = _passage;
_configureGas(_perBlockGasLimit, _perTransactGasLimit);
}

/// @notice Configure the `transact` gas limits.
function configureGas(uint256 perBlock, uint256 perTransact) external {
if (msg.sender != gasAdmin) revert OnlyGasAdmin();
_configureGas(perBlock, perTransact);
}

/// @notice Allows a special transaction to be sent to the rollup with sender == L1 msg.sender.
/// @dev Transaction is processed after normal rollup block execution.
/// @dev See `enterTransact` for docs.
function transact(
uint256 rollupChainId,
address to,
bytes calldata data,
uint256 value,
uint256 gas,
uint256 maxFeePerGas
) public payable {
enterTransact(rollupChainId, msg.sender, to, data, value, gas, maxFeePerGas);
}

/// @dev See `transact` for docs.
function transact(address to, bytes calldata data, uint256 value, uint256 gas, uint256 maxFeePerGas)
external
payable
{
enterTransact(defaultRollupChainId, msg.sender, to, data, value, gas, maxFeePerGas);
}

/// @notice Send Ether on the rollup, send a special transaction to be sent to the rollup with sender == L1 msg.sender.
/// @dev Enter and Transact are processed after normal rollup block execution.
/// @dev See `enter` for Enter docs.
/// @param rollupChainId - The rollup chain to send the transaction to.
/// @param etherRecipient - The recipient of the ether.
/// @param to - The address to call on the rollup.
/// @param data - The data to send to the rollup.
/// @param value - The amount of Ether to send on the rollup.
/// @param gas - The gas limit for the transaction.
/// @param maxFeePerGas - The maximum fee per gas for the transaction (per EIP-1559).
/// @custom:emits Transact indicating the transaction to mine on the rollup.
function enterTransact(
uint256 rollupChainId,
address etherRecipient,
address to,
bytes calldata data,
uint256 value,
uint256 gas,
uint256 maxFeePerGas
) public payable {
// if msg.value is attached, Enter
if (msg.value > 0) {
passage.enter{value: msg.value}(rollupChainId, etherRecipient);
}

// ensure per-transact gas limit is respected
if (gas > perTransactGasLimit) revert PerTransactGasLimit();

// ensure global transact gas limit is respected
uint256 gasUsed = transactGasUsed[rollupChainId][block.number];
if (gasUsed + gas > perBlockGasLimit) revert PerBlockTransactGasLimit();
transactGasUsed[rollupChainId][block.number] = gasUsed + gas;

// emit Transact event
emit Transact(rollupChainId, msg.sender, to, data, value, gas, maxFeePerGas);
}

/// @notice Helper to configure gas limits on deploy & via admin function
function _configureGas(uint256 perBlock, uint256 perTransact) internal {
perBlockGasLimit = perBlock;
perTransactGasLimit = perTransact;
emit GasConfigured(perBlock, perTransact);
}
}
30 changes: 0 additions & 30 deletions test/Passage.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -151,36 +151,6 @@ contract PassageTest is Test {
target.enterToken(recipient, token, amount);
}

function test_transact() public {
vm.expectEmit();
emit Transact(chainId, address(this), to, data, value, gas, maxFeePerGas);
target.transact(chainId, to, data, value, gas, maxFeePerGas);

vm.expectEmit();
emit Enter(chainId, address(this), amount);
target.transact{value: amount}(chainId, to, data, value, gas, maxFeePerGas);
}

function test_transact_defaultChain() public {
vm.expectEmit();
emit Transact(target.defaultRollupChainId(), address(this), to, data, value, gas, maxFeePerGas);
target.transact(to, data, value, gas, maxFeePerGas);

vm.expectEmit();
emit Enter(target.defaultRollupChainId(), address(this), amount);
target.transact{value: amount}(to, data, value, gas, maxFeePerGas);
}

function test_enterTransact() public {
vm.expectEmit();
emit Transact(chainId, address(this), to, data, value, gas, maxFeePerGas);
target.enterTransact(chainId, recipient, to, data, value, gas, maxFeePerGas);

vm.expectEmit();
emit Enter(chainId, recipient, amount);
target.enterTransact{value: amount}(chainId, recipient, to, data, value, gas, maxFeePerGas);
}

function test_withdraw() public {
TestERC20(token).mint(address(target), amount);

Expand Down
Loading

0 comments on commit 9e8e460

Please sign in to comment.