Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat[contracts]: add sequencer fee wallet #1029

Merged
merged 16 commits into from
Jun 9, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions integration-tests/test/fee-payment.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
chai.use(chaiAsPromised)

/* Imports: External */
import { BigNumber, utils } from 'ethers'
import { OptimismEnv } from './shared/env'
import { TxGasLimit, TxGasPrice } from '@eth-optimism/core-utils'
import { predeploys } from '@eth-optimism/contracts'

/* Imports: Internal */
import { OptimismEnv } from './shared/env'

describe('Fee Payment Integration Tests', async () => {
let env: OptimismEnv
Expand Down Expand Up @@ -36,17 +41,30 @@ describe('Fee Payment Integration Tests', async () => {
it('Paying a nonzero but acceptable gasPrice fee', async () => {
const amount = utils.parseEther('0.5')
const balanceBefore = await env.l2Wallet.getBalance()
const feeVaultBalanceBefore = await env.l2Wallet.provider.getBalance(
predeploys.OVM_SequencerFeeVault
)
expect(balanceBefore.gt(amount))

const tx = await env.ovmEth.transfer(other, amount)
const receipt = await tx.wait()
expect(receipt.status).to.eq(1)

const balanceAfter = await env.l2Wallet.getBalance()
const feeVaultBalanceAfter = await env.l2Wallet.provider.getBalance(
predeploys.OVM_SequencerFeeVault
tynes marked this conversation as resolved.
Show resolved Hide resolved
)
const expectedFeePaid = tx.gasPrice.mul(tx.gasLimit)

// The fee paid MUST be the receipt.gasUsed, and not the tx.gasLimit
// https://github.com/ethereum-optimism/optimism/blob/0de7a2f9c96a7c4860658822231b2d6da0fefb1d/packages/contracts/contracts/optimistic-ethereum/OVM/accounts/OVM_ECDSAContractAccount.sol#L103
expect(balanceBefore.sub(balanceAfter)).to.be.deep.eq(
tx.gasPrice.mul(tx.gasLimit).add(amount)
expect(balanceBefore.sub(balanceAfter)).to.deep.equal(
expectedFeePaid.add(amount)
)

// Make sure the fee was transferred to the vault.
expect(feeVaultBalanceAfter.sub(feeVaultBalanceBefore)).to.deep.equal(
expectedFeePaid
smartcontracts marked this conversation as resolved.
Show resolved Hide resolved
)
})
})
1 change: 1 addition & 0 deletions l2geth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ $ USING_OVM=true ./build/bin/geth \
--eth1.chainid $LAYER1_CHAIN_ID \
--eth1.l1gatewayaddress $ETH1_L1_GATEWAY_ADDRESS \
--eth1.l1crossdomainmessengeraddress $ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS \
--eth1.l1feewalletaddress $ETH1_L1_FEE_WALLET_ADDRESS \
--eth1.addressresolveraddress $ETH1_ADDRESS_RESOLVER_ADDRESS \
--eth1.ctcdeploymentheight $CTC_DEPLOY_HEIGHT \
--eth1.syncservice \
Expand Down
1 change: 1 addition & 0 deletions l2geth/cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ var (
utils.Eth1SyncServiceEnable,
utils.Eth1CanonicalTransactionChainDeployHeightFlag,
utils.Eth1L1CrossDomainMessengerAddressFlag,
utils.Eth1L1FeeWalletAddressFlag,
tynes marked this conversation as resolved.
Show resolved Hide resolved
utils.Eth1ETHGatewayAddressFlag,
utils.Eth1ChainIdFlag,
utils.RollupClientHttpFlag,
Expand Down
1 change: 1 addition & 0 deletions l2geth/cmd/geth/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.Eth1SyncServiceEnable,
utils.Eth1CanonicalTransactionChainDeployHeightFlag,
utils.Eth1L1CrossDomainMessengerAddressFlag,
utils.Eth1L1FeeWalletAddressFlag,
utils.Eth1ETHGatewayAddressFlag,
utils.Eth1ChainIdFlag,
utils.RollupClientHttpFlag,
Expand Down
13 changes: 12 additions & 1 deletion l2geth/cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,12 @@ var (
Value: "0x0000000000000000000000000000000000000000",
EnvVar: "ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS",
}
Eth1L1FeeWalletAddressFlag = cli.StringFlag{
Name: "eth1.l1feewalletaddress",
Usage: "Address of the L1 wallet that will collect fees",
Value: "0x0000000000000000000000000000000000000000",
EnvVar: "ETH1_L1_FEE_WALLET_ADDRESS",
}
Eth1ETHGatewayAddressFlag = cli.StringFlag{
Name: "eth1.l1ethgatewayaddress",
Usage: "Deployment address of the Ethereum gateway",
Expand Down Expand Up @@ -1148,6 +1154,10 @@ func setEth1(ctx *cli.Context, cfg *rollup.Config) {
addr := ctx.GlobalString(Eth1L1CrossDomainMessengerAddressFlag.Name)
cfg.L1CrossDomainMessengerAddress = common.HexToAddress(addr)
}
if ctx.GlobalIsSet(Eth1L1FeeWalletAddressFlag.Name) {
addr := ctx.GlobalString(Eth1L1FeeWalletAddressFlag.Name)
cfg.L1FeeWalletAddress = common.HexToAddress(addr)
}
if ctx.GlobalIsSet(Eth1ETHGatewayAddressFlag.Name) {
addr := ctx.GlobalString(Eth1ETHGatewayAddressFlag.Name)
cfg.L1ETHGatewayAddress = common.HexToAddress(addr)
Expand Down Expand Up @@ -1777,10 +1787,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
gasLimit = params.GenesisGasLimit
}
xdomainAddress := cfg.Rollup.L1CrossDomainMessengerAddress
l1FeeWalletAddress := cfg.Rollup.L1FeeWalletAddress
addrManagerOwnerAddress := cfg.Rollup.AddressManagerOwnerAddress
l1ETHGatewayAddress := cfg.Rollup.L1ETHGatewayAddress
stateDumpPath := cfg.Rollup.StateDumpPath
cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address, xdomainAddress, l1ETHGatewayAddress, addrManagerOwnerAddress, stateDumpPath, chainID, gasLimit)
cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address, xdomainAddress, l1ETHGatewayAddress, addrManagerOwnerAddress, l1FeeWalletAddress, stateDumpPath, chainID, gasLimit)
smartcontracts marked this conversation as resolved.
Show resolved Hide resolved
if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
cfg.Miner.GasPrice = big.NewInt(1)
}
Expand Down
2 changes: 1 addition & 1 deletion l2geth/console/console_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create node: %v", err)
}
ethConf := &eth.Config{
Genesis: core.DeveloperGenesisBlock(15, common.Address{}, common.Address{}, common.Address{}, common.Address{}, "", nil, 12000000),
Genesis: core.DeveloperGenesisBlock(15, common.Address{}, common.Address{}, common.Address{}, common.Address{}, common.Address{}, "", nil, 12000000),
Miner: miner.Config{
Etherbase: common.HexToAddress(testAddress),
},
Expand Down
15 changes: 12 additions & 3 deletions l2geth/core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ type Genesis struct {

// OVM Specific, used to initialize the l1XDomainMessengerAddress
// in the genesis state
L1FeeWalletAddress common.Address `json:"-"`
L1CrossDomainMessengerAddress common.Address `json:"-"`
AddressManagerOwnerAddress common.Address `json:"-"`
L1ETHGatewayAddress common.Address `json:"-"`
Expand Down Expand Up @@ -266,7 +267,7 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
}

// ApplyOvmStateToState applies the initial OVM state to a state object.
func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDomainMessengerAddress common.Address, l1ETHGatewayAddress common.Address, addrManagerOwnerAddress common.Address, chainID *big.Int, gasLimit uint64) {
func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDomainMessengerAddress common.Address, l1ETHGatewayAddress common.Address, addrManagerOwnerAddress common.Address, l1FeeWalletAddress common.Address, chainID *big.Int, gasLimit uint64) {
if len(stateDump.Accounts) == 0 {
return
}
Expand Down Expand Up @@ -330,6 +331,13 @@ func ApplyOvmStateToState(statedb *state.StateDB, stateDump *dump.OvmDump, l1XDo
maxTxGasLimitValue := common.BytesToHash(new(big.Int).SetUint64(gasLimit).Bytes())
statedb.SetState(ExecutionManager.Address, maxTxGasLimitSlot, maxTxGasLimitValue)
}
OVM_SequencerFeeVault, ok := stateDump.Accounts["OVM_SequencerFeeVault"]
if ok {
log.Info("Setting l1FeeWallet in OVM_SequencerFeeVault", "wallet", l1FeeWalletAddress.Hex())
l1FeeWalletSlot := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000")
tynes marked this conversation as resolved.
Show resolved Hide resolved
l1FeeWalletValue := common.BytesToHash(l1FeeWalletAddress.Bytes())
statedb.SetState(OVM_SequencerFeeVault.Address, l1FeeWalletSlot, l1FeeWalletValue)
}
}

// ToBlock creates the genesis block and writes state of a genesis specification
Expand All @@ -342,7 +350,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {

if vm.UsingOVM {
// OVM_ENABLED
ApplyOvmStateToState(statedb, g.Config.StateDump, g.L1CrossDomainMessengerAddress, g.L1ETHGatewayAddress, g.AddressManagerOwnerAddress, g.ChainID, g.GasLimit)
ApplyOvmStateToState(statedb, g.Config.StateDump, g.L1CrossDomainMessengerAddress, g.L1ETHGatewayAddress, g.AddressManagerOwnerAddress, g.L1FeeWalletAddress, g.ChainID, g.GasLimit)
}

for addr, account := range g.Alloc {
Expand Down Expand Up @@ -469,7 +477,7 @@ func DefaultGoerliGenesisBlock() *Genesis {
}

// DeveloperGenesisBlock returns the 'geth --dev' genesis block.
func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress common.Address, l1ETHGatewayAddress common.Address, addrManagerOwnerAddress common.Address, stateDumpPath string, chainID *big.Int, gasLimit uint64) *Genesis {
func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress common.Address, l1ETHGatewayAddress common.Address, addrManagerOwnerAddress common.Address, l1FeeWalletAddress common.Address, stateDumpPath string, chainID *big.Int, gasLimit uint64) *Genesis {
// Override the default period to the user requested one
config := *params.AllCliqueProtocolChanges
config.Clique.Period = period
Expand Down Expand Up @@ -525,6 +533,7 @@ func DeveloperGenesisBlock(period uint64, faucet, l1XDomainMessengerAddress comm
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
},
L1CrossDomainMessengerAddress: l1XDomainMessengerAddress,
L1FeeWalletAddress: l1FeeWalletAddress,
AddressManagerOwnerAddress: addrManagerOwnerAddress,
L1ETHGatewayAddress: l1ETHGatewayAddress,
ChainID: config.ChainID,
Expand Down
1 change: 1 addition & 0 deletions l2geth/rollup/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Config struct {
// HTTP endpoint of the data transport layer
RollupClientHttp string
L1CrossDomainMessengerAddress common.Address
L1FeeWalletAddress common.Address
AddressManagerOwnerAddress common.Address
L1ETHGatewayAddress common.Address
GasPriceOracleAddress common.Address
Expand Down
11 changes: 11 additions & 0 deletions l2geth/scripts/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ CLI Arguments:
--eth1.chainid - eth1 chain id
--eth1.ctcdeploymentheight - eth1 ctc deploy height
--eth1.l1crossdomainmessengeraddress - eth1 l1 xdomain messenger address
--eth1.l1feewalletaddress - eth l1 fee wallet address
--rollup.statedumppath - http path to the initial state dump
--rollup.clienthttp - rollup client http
--rollup.pollinterval - polling interval for the rollup client
Expand Down Expand Up @@ -127,6 +128,15 @@ while (( "$#" )); do
exit 1
fi
;;
--eth1.l1feewalletaddress)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
ETH1_L1_FEE_WALLET_ADDRESS="$2"
shift 2
else
echo "Error: Argument for $1 is missing" >&2
exit 1
fi
;;
--eth1.l1ethgatewayaddress)
if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then
ETH1_L1_ETH_GATEWAY_ADDRESS="$2"
Expand Down Expand Up @@ -230,6 +240,7 @@ if [[ ! -z "$ROLLUP_SYNC_SERVICE_ENABLE" ]]; then
fi
cmd="$cmd --datadir $DATADIR"
cmd="$cmd --eth1.l1crossdomainmessengeraddress $ETH1_L1_CROSS_DOMAIN_MESSENGER_ADDRESS"
cmd="$cmd --eth1.l1feewalletaddress $ETH1_L1_FEE_WALLET_ADDRESS"
cmd="$cmd --rollup.addressmanagerowneraddress $ADDRESS_MANAGER_OWNER_ADDRESS"
cmd="$cmd --rollup.statedumppath $ROLLUP_STATE_DUMP_PATH"
cmd="$cmd --eth1.ctcdeploymentheight $ETH1_CTC_DEPLOYMENT_HEIGHT"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { iOVM_ECDSAContractAccount } from "../../iOVM/accounts/iOVM_ECDSAContrac
/* Library Imports */
import { Lib_EIP155Tx } from "../../libraries/codec/Lib_EIP155Tx.sol";
import { Lib_ExecutionManagerWrapper } from "../../libraries/wrappers/Lib_ExecutionManagerWrapper.sol";
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";

/* Contract Imports */
import { OVM_ETH } from "../predeploys/OVM_ETH.sol";
Expand Down Expand Up @@ -40,7 +41,6 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
// TODO: should be the amount sufficient to cover the gas costs of all of the transactions up
// to and including the CALL/CREATE which forms the entrypoint of the transaction.
uint256 constant EXECUTION_VALIDATION_GAS_OVERHEAD = 25000;
OVM_ETH constant ovmETH = OVM_ETH(0x4200000000000000000000000000000000000006);


/********************
Expand Down Expand Up @@ -92,8 +92,8 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {

// Transfer fee to relayer.
require(
ovmETH.transfer(
msg.sender,
OVM_ETH(Lib_PredeployAddresses.OVM_ETH).transfer(
Lib_PredeployAddresses.SEQUENCER_FEE_WALLET,
SafeMath.mul(transaction.gasLimit, transaction.gasPrice)
),
"Fee was not transferred to relayer."
Expand Down Expand Up @@ -131,7 +131,7 @@ contract OVM_ECDSAContractAccount is iOVM_ECDSAContractAccount {
);

require(
ovmETH.transfer(
OVM_ETH(Lib_PredeployAddresses.OVM_ETH).transfer(
transaction.to,
transaction.value
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;

/* Library Imports */
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";

/* Contract Imports */
import { OVM_ETH } from "../predeploys/OVM_ETH.sol";

/**
* @title OVM_SequencerFeeVault
* @dev Simple holding contract for fees paid to the Sequencer. Likely to be replaced in the future
* but "good enough for now".
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_SequencerFeeVault {

/*************
* Constants *
*************/

// Minimum ETH balance that can be withdrawn in a single withdrawal.
uint256 public constant MIN_WITHDRAWAL_AMOUNT = 10 ether;
smartcontracts marked this conversation as resolved.
Show resolved Hide resolved


/*************
* Variables *
*************/

// Address on L1 that will hold the fees once withdrawn. Dynamically initialized within l2geth.
address l1FeeWallet;


/***************
* Constructor *
***************/

/**
* @param _l1FeeWallet Initial address for the L1 wallet that will hold fees once withdrawn.
* Currently HAS NO EFFECT in production because l2geth will mutate this storage slot during
* the genesis block. This is ONLY for testing purposes.
*/
constructor(
address _l1FeeWallet
) {
l1FeeWallet = _l1FeeWallet;
}


/********************
* Public Functions *
********************/

function withdraw()
public
{
uint256 balance = OVM_ETH(Lib_PredeployAddresses.OVM_ETH).balanceOf(address(this));

require(
balance >= MIN_WITHDRAWAL_AMOUNT,
"OVM_SequencerFeeVault: withdrawal amount must be greater than minimum withdrawal amount"
);

OVM_ETH(Lib_PredeployAddresses.OVM_ETH).withdrawTo(
l1FeeWallet,
balance,
0,
bytes("")
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ library Lib_PredeployAddresses {
address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007;
address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008;
address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009;
address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011;
address internal constant ERC1820_REGISTRY = 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24;
}
6 changes: 5 additions & 1 deletion packages/contracts/src/contract-deployment/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* External Imports */
import { Signer, ContractFactory, Contract } from 'ethers'
import { Signer, ContractFactory, Contract, ethers } from 'ethers'
import { TransactionResponse } from '@ethersproject/abstract-provider'
import { Overrides } from '@ethersproject/contracts'

Expand Down Expand Up @@ -275,5 +275,9 @@ export const makeContractDeployConfig = async (
config.gasPriceOracleConfig.initialGasPrice,
],
},
OVM_SequencerFeeVault: {
factory: getContractFactory('OVM_SequencerFeeVault'),
params: [ethers.constants.AddressZero],
},
}
}
1 change: 1 addition & 0 deletions packages/contracts/src/predeploys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ export const predeploys = {
OVM_ProxyEOA: '0x4200000000000000000000000000000000000009',
OVM_ExecutionManagerWrapper: '0x420000000000000000000000000000000000000B',
OVM_GasPriceOracle: '0x420000000000000000000000000000000000000F',
OVM_SequencerFeeVault: '0x4200000000000000000000000000000000000011',
smartcontracts marked this conversation as resolved.
Show resolved Hide resolved
ERC1820Registry: '0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24',
}
2 changes: 2 additions & 0 deletions packages/contracts/src/state-dump/make-dump.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
'OVM_ETH',
'OVM_ExecutionManagerWrapper',
'OVM_GasPriceOracle',
'OVM_SequencerFeeVault',
],
deployOverrides: {},
waitForReceipts: false,
Expand All @@ -159,6 +160,7 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
'OVM_ProxyEOA',
'OVM_ExecutionManagerWrapper',
'OVM_GasPriceOracle',
'OVM_SequencerFeeVault',
]

const deploymentResult = await deploy(config)
Expand Down
Loading