Commit 63ec5881 authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into jg/txmgr_cleanup_pt1

parents d0c22cf5 bb4b84c0
......@@ -846,9 +846,9 @@ workflows:
requires:
- yarn-monorepo
- js-lint-test:
name: drippie-mon-tests
coverage_flag: drippie-mon-tests
package_name: drippie-mon
name: chain-mon-tests
coverage_flag: chain-mon-tests
package_name: chain-mon
dependencies: "(common-ts|contracts-periphery|core-utils|sdk)"
requires:
- yarn-monorepo
......
.github
.vscode
node_modules
**/node_modules
.env
**/.env
......
......@@ -12,7 +12,7 @@
/packages/contracts-periphery @ethereum-optimism/contract-reviewers
/packages/core-utils @ethereum-optimism/legacy-reviewers
/packages/data-transport-layer @ethereum-optimism/legacy-reviewers
/packages/drippie-mon @smartcontracts
/packages/chain-mon @smartcontracts
/packages/fault-detector @ethereum-optimism/legacy-reviewers
/packages/hardhat-deploy-config @ethereum-optimism/legacy-reviewers
/packages/message-relayer @ethereum-optimism/legacy-reviewers
......
......@@ -25,7 +25,7 @@
"changeProcessCWD": true
},
{
"directory": "packages/drippie-mon",
"directory": "packages/chain-mon",
"changeProcessCWD": true
},
{
......@@ -45,4 +45,4 @@
"eslint.format.enable": true,
"editorconfig.generateAuto": false,
"files.trimTrailingWhitespace": true
}
\ No newline at end of file
}
......@@ -57,7 +57,7 @@ Refer to the Directory Structure section below to understand which packages are
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/data-transport-layer">data-transport-layer</a>: Service for indexing Optimism-related L1 data
│ ├── <a href="./packages/drippie-mon">drippie-mon</a>: Service for monitoring Drippie instances
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
│ ├── <a href="./packages/message-relayer">message-relayer</a>: Tool for automatically relaying L1<>L2 messages in development
│ ├── <a href="./packages/replica-healthcheck">replica-healthcheck</a>: Service for monitoring the health of a replica node
......
......@@ -37,7 +37,7 @@ flag_management:
- name: actor-tests-tests
- name: contracts-periphery-tests
- name: dtl-tests
- name: drippie-mon-tests
- name: chain-mon-tests
- name: fault-detector-tests
- name: message-relayer-tests
- name: replica-healthcheck-tests
......
This diff is collapsed.
This diff is collapsed.
......@@ -10,4 +10,11 @@ var AllowedVersions = map[string]bool{
"": true,
"v0.1.0-beta.1": true,
"v0.1.0-goerli-rehearsal.1": true,
"v0.10.9": true,
"v0.10.10": true,
"v0.10.11": true,
"v0.10.12": true,
"v0.10.13": true,
"v0.10.14": true,
"v0.11.0": true,
}
......@@ -15,7 +15,7 @@ import (
type StorageProofEntry struct {
Key common.Hash `json:"key"`
Value hexutil.Bytes `json:"value"`
Value hexutil.Big `json:"value"`
Proof []hexutil.Bytes `json:"proof"`
}
......
......@@ -13,7 +13,7 @@ import (
// Channel In Reader reads a batch from the channel
// This does decompression and limits the max RLP size
// This is a pure function from the channel, but each channel (or channel fragment)
// must be tagged with an L1 inclusion block to be passed to the the batch queue.
// must be tagged with an L1 inclusion block to be passed to the batch queue.
type ChannelInReader struct {
log log.Logger
......
......@@ -359,7 +359,8 @@ func (s *EthClient) ReadStorageAt(ctx context.Context, address common.Address, s
if err := result.Verify(block.Root()); err != nil {
return common.Hash{}, fmt.Errorf("failed to verify retrieved proof against state root: %w", err)
}
return common.BytesToHash(result.StorageProof[0].Value), nil
value := result.StorageProof[0].Value.ToInt()
return common.BytesToHash(value.Bytes()), nil
}
func (s *EthClient) Close() {
......
......@@ -46,7 +46,7 @@ COPY packages/hardhat-deploy-config/package.json ./packages/hardhat-deploy-confi
COPY packages/message-relayer/package.json ./packages/message-relayer/package.json
COPY packages/fault-detector/package.json ./packages/fault-detector/package.json
COPY packages/replica-healthcheck/package.json ./packages/replica-healthcheck/package.json
COPY packages/drippie-mon/package.json ./packages/drippie-mon/package.json
COPY packages/chain-mon/package.json ./packages/chain-mon/package.json
COPY packages/balance-monitor/package.json ./packages/balance-monitor/package.json
COPY packages/two-step-monitor/package.json ./packages/two-step-monitor/package.json
COPY integration-tests/package.json ./integration-tests/package.json
......@@ -106,8 +106,8 @@ WORKDIR /opt/optimism/packages/replica-healthcheck
ENTRYPOINT ["npm", "run", "start"]
FROM base as drippie-mon
WORKDIR /opt/optimism/packages/drippie-mon
ENTRYPOINT ["npm", "run", "start"]
WORKDIR /opt/optimism/packages/chain-mon
ENTRYPOINT ["npm", "run", "start:drippie-mon"]
FROM base as balance-monitor
WORKDIR /opt/optimism/packages/balance-monitor
......
###############################################################################
# ↓ drippie-mon ↓ #
###############################################################################
# RPC pointing to network where Drippie is deployed
DRIPPIE_MON__RPC=
......
# @eth-optimism/drippie-mon
# @eth-optimism/chain-mon
[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/develop/graph/badge.svg?token=0VTG7PG7YR&flag=drippie-mon-tests)](https://codecov.io/gh/ethereum-optimism/optimism)
[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/develop/graph/badge.svg?token=0VTG7PG7YR&flag=chain-mon-tests)](https://codecov.io/gh/ethereum-optimism/optimism)
`drippie-mon` is a simple service for monitoring Drippie contracts.
`chain-mon` is a collection of chain monitoring services.
## Installation
......@@ -14,11 +14,17 @@ yarn install
yarn build
```
## Running the service
## Running a service
Copy `.env.example` into a new file named `.env`, then set the environment variables listed there.
Copy `.env.example` into a new file named `.env`, then set the environment variables listed there depending on the service you want to run.
Once your environment variables have been set, run via:
```
yarn start
yarn start:<service name>
```
For example, to run `drippie-mon`, execute:
```
yarn start:drippie-mon
```
{
"private": true,
"name": "@eth-optimism/drippie-mon",
"version": "0.4.3",
"description": "[Optimism] Service for monitoring Drippie instances",
"name": "@eth-optimism/chain-mon",
"version": "0.1.0",
"description": "[Optimism] Chain monitoring services",
"main": "dist/index",
"types": "dist/index",
"files": [
"dist/*"
],
"scripts": {
"start": "ts-node ./src/service.ts",
"start:drippie-mon": "ts-node ./src/drippie-mon/service.ts",
"test:coverage": "echo 'No tests defined.'",
"build": "tsc -p ./tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
......@@ -21,10 +21,9 @@
"keywords": [
"optimism",
"ethereum",
"drippie",
"monitoring"
],
"homepage": "https://github.com/ethereum-optimism/optimism/tree/develop/packages/drippie-mon#readme",
"homepage": "https://github.com/ethereum-optimism/optimism/tree/develop/packages/chain-mon#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
......
......@@ -9,7 +9,7 @@ import { Provider } from '@ethersproject/abstract-provider'
import { ethers } from 'ethers'
import * as DrippieArtifact from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/drippie/Drippie.sol/Drippie.json'
import { version } from '../package.json'
import { version } from '../../package.json'
type DrippieMonOptions = {
rpc: Provider
......
export * from './drippie-mon/service'
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 261344)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 75851)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 348207)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 112639)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348229)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112660)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40502)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 348296)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 112728)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 348318)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 112749)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 40853)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 88513)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 74998)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 36156)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 167187)
Bytes_Test:test_slice_acrossMultipleWords_works() (gas: 9391)
Bytes_Test:test_slice_acrossWords_works() (gas: 1397)
Bytes_Test:test_slice_fromNonZeroIdx_works() (gas: 17218)
Bytes_Test:test_slice_fromZeroIdx_works() (gas: 20826)
Bytes_Test:test_toNibbles_expectedResult128Bytes_works() (gas: 129885)
Bytes_Test:test_toNibbles_expectedResult5Bytes_works() (gas: 6132)
Bytes_Test:test_toNibbles_zeroLengthInput_works() (gas: 966)
Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9357)
Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1396)
Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17154)
Bytes_slice_Test:test_slice_fromZeroIdx_works() (gas: 20671)
Bytes_toNibbles_Test:test_toNibbles_expectedResult128Bytes_works() (gas: 129830)
Bytes_toNibbles_Test:test_toNibbles_expectedResult5Bytes_works() (gas: 6088)
Bytes_toNibbles_Test:test_toNibbles_zeroLengthInput_works() (gas: 944)
CrossDomainMessenger_BaseGas_Test:test_baseGas_succeeds() (gas: 20120)
CrossDomainOwnableThroughPortal_Test:test_depositTransaction_crossDomainOwner_succeeds() (gas: 61882)
CrossDomainOwnable_Test:test_onlyOwner_notOwner_reverts() (gas: 10530)
......@@ -92,23 +92,25 @@ L1ERC721Bridge_Test:test_finalizeBridgeERC721_notFromRemoteMessenger_reverts() (
L1ERC721Bridge_Test:test_finalizeBridgeERC721_notViaLocalMessenger_reverts() (gas: 16093)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_selfToken_reverts() (gas: 17593)
L1ERC721Bridge_Test:test_finalizeBridgeERC721_succeeds() (gas: 323814)
L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 624908)
L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 622587)
L1StandardBridge_BridgeETHTo_Test:test_bridgeETHTo_succeeds() (gas: 419609)
L1StandardBridge_BridgeETH_Test:test_bridgeETH_succeeds() (gas: 406785)
L1StandardBridge_DepositERC20To_Test:test_depositERC20To_succeeds() (gas: 625056)
L1StandardBridge_DepositERC20_Test:test_depositERC20_succeeds() (gas: 622735)
L1StandardBridge_DepositERC20_TestFail:test_depositERC20_notEoa_reverts() (gas: 22320)
L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 359219)
L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 405236)
L1StandardBridge_DepositETHTo_Test:test_depositETHTo_succeeds() (gas: 419642)
L1StandardBridge_DepositETH_Test:test_depositETH_succeeds() (gas: 406880)
L1StandardBridge_DepositETH_TestFail:test_depositETH_notEoa_reverts() (gas: 40780)
L1StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 48788)
L1StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 51674)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 34207)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 34288)
L1StandardBridge_FinalizeBridgeETH_TestFail:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 34257)
L1StandardBridge_FinalizeERC20Withdrawal_Test:test_finalizeERC20Withdrawal_succeeds() (gas: 496088)
L1StandardBridge_FinalizeERC20Withdrawal_Test:test_finalizeERC20Withdrawal_succeeds() (gas: 496417)
L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notMessenger_reverts() (gas: 31148)
L1StandardBridge_FinalizeERC20Withdrawal_TestFail:test_finalizeERC20Withdrawal_notOtherBridge_reverts() (gas: 31504)
L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 61815)
L1StandardBridge_FinalizeETHWithdrawal_Test:test_finalizeETHWithdrawal_succeeds() (gas: 62166)
L1StandardBridge_Getter_Test:test_getters_succeeds() (gas: 32151)
L1StandardBridge_Initialize_Test:test_initialize_succeeds() (gas: 22005)
L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 520249)
L1StandardBridge_Receive_Test:test_receive_succeeds() (gas: 520338)
L2CrossDomainMessenger_Test:test_messageVersion_succeeds() (gas: 8389)
L2CrossDomainMessenger_Test:test_pause_notOwner_reverts() (gas: 10837)
L2CrossDomainMessenger_Test:test_pause_succeeds() (gas: 31846)
......@@ -164,18 +166,20 @@ L2OutputOracleUpgradeable_Test:test_initValuesOnProxy_succeeds() (gas: 26093)
L2OutputOracleUpgradeable_Test:test_initializeImpl_alreadyInitialized_reverts() (gas: 15149)
L2OutputOracleUpgradeable_Test:test_initializeProxy_alreadyInitialized_reverts() (gas: 20131)
L2OutputOracleUpgradeable_Test:test_upgrading_succeeds() (gas: 180413)
L2StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 36076)
L2StandardBridge_Test:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 23865)
L2StandardBridge_Test:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 23960)
L2StandardBridge_Test:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 23826)
L2StandardBridge_Test:test_finalizeDeposit_depositingERC20_succeeds() (gas: 90619)
L2StandardBridge_Test:test_finalizeDeposit_depositingETH_succeeds() (gas: 89451)
L2StandardBridge_Test:test_initialize_succeeds() (gas: 24270)
L2StandardBridge_Test:test_receive_succeeds() (gas: 177206)
L2StandardBridge_Test:test_withdrawTo_withdrawingERC20_succeeds() (gas: 386492)
L2StandardBridge_Test:test_withdraw_insufficientValue_reverts() (gas: 19649)
L2StandardBridge_Test:test_withdraw_notEOA_reverts() (gas: 251799)
L2StandardBridge_Test:test_withdraw_withdrawingERC20_succeeds() (gas: 384536)
L2StandardBridge_BridgeERC20To_Test:test_bridgeERC20To_succeeds() (gas: 387969)
L2StandardBridge_BridgeERC20To_Test:test_withdrawTo_withdrawingERC20_succeeds() (gas: 388200)
L2StandardBridge_BridgeERC20_Test:test_bridgeERC20_succeeds() (gas: 383692)
L2StandardBridge_BridgeERC20_Test:test_withdraw_notEOA_reverts() (gas: 251790)
L2StandardBridge_BridgeERC20_Test:test_withdraw_withdrawingERC20_succeeds() (gas: 383877)
L2StandardBridge_Bridge_Test:test_finalizeBridgeETH_incorrectValue_reverts() (gas: 23798)
L2StandardBridge_Bridge_Test:test_finalizeBridgeETH_sendToMessenger_reverts() (gas: 23960)
L2StandardBridge_Bridge_Test:test_finalizeBridgeETH_sendToSelf_reverts() (gas: 23848)
L2StandardBridge_Bridge_Test:test_finalizeDeposit_depositingERC20_succeeds() (gas: 90989)
L2StandardBridge_Bridge_Test:test_finalizeDeposit_depositingETH_succeeds() (gas: 89821)
L2StandardBridge_FinalizeBridgeETH_Test:test_finalizeBridgeETH_succeeds() (gas: 43155)
L2StandardBridge_Test:test_initialize_succeeds() (gas: 24247)
L2StandardBridge_Test:test_receive_succeeds() (gas: 177145)
L2StandardBridge_Test:test_withdraw_insufficientValue_reverts() (gas: 19615)
L2ToL1MessagePasserTest:test_burn_succeeds() (gas: 112572)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromContract_succeeds() (gas: 70423)
L2ToL1MessagePasserTest:test_initiateWithdrawal_fromEOA_succeeds() (gas: 75874)
......@@ -385,7 +389,7 @@ SequencerFeeVault_Test:test_constructor_succeeds() (gas: 5504)
SequencerFeeVault_Test:test_minWithdrawalAmount_succeeds() (gas: 5420)
SequencerFeeVault_Test:test_receive_succeeds() (gas: 17336)
SequencerFeeVault_Test:test_withdraw_notEnough_reverts() (gas: 9309)
SequencerFeeVault_Test:test_withdraw_succeeds() (gas: 159816)
SequencerFeeVault_Test:test_withdraw_succeeds() (gas: 163169)
SystemConfig_Initialize_TestFail:test_initialize_lowGasLimit_reverts() (gas: 61966)
SystemConfig_Setters_TestFail:test_setBatcherHash_notOwner_reverts() (gas: 10545)
SystemConfig_Setters_TestFail:test_setGasConfig_notOwner_reverts() (gas: 10532)
......
......@@ -126,7 +126,6 @@ contract L1StandardBridge is StandardBridge, Semver {
uint256 _amount,
bytes calldata _extraData
) external onlyOtherBridge {
emit ERC20WithdrawalFinalized(_l1Token, _l2Token, _from, _to, _amount, _extraData);
finalizeBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _extraData);
}
......@@ -242,7 +241,6 @@ contract L1StandardBridge is StandardBridge, Semver {
uint256 _amount,
bytes calldata _extraData
) external payable onlyOtherBridge {
emit ETHWithdrawalFinalized(_from, _to, _amount, _extraData);
finalizeBridgeETH(_from, _to, _amount, _extraData);
}
......@@ -270,7 +268,6 @@ contract L1StandardBridge is StandardBridge, Semver {
uint32 _minGasLimit,
bytes memory _extraData
) internal {
emit ETHDepositInitiated(_from, _to, msg.value, _extraData);
_initiateBridgeETH(_from, _to, msg.value, _minGasLimit, _extraData);
}
......@@ -294,7 +291,74 @@ contract L1StandardBridge is StandardBridge, Semver {
uint32 _minGasLimit,
bytes memory _extraData
) internal {
emit ERC20DepositInitiated(_l1Token, _l2Token, _from, _to, _amount, _extraData);
_initiateBridgeERC20(_l1Token, _l2Token, _from, _to, _amount, _minGasLimit, _extraData);
}
/**
* @notice Emits the legacy ETHDepositInitiated event followed by the ETHBridgeInitiated event.
* This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitETHBridgeInitiated(
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit ETHDepositInitiated(_from, _to, _amount, _extraData);
super._emitETHBridgeInitiated(_from, _to, _amount, _extraData);
}
/**
* @notice Emits the legacy ETHWithdrawalFinalized event followed by the ETHBridgeFinalized
* event. This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitETHBridgeFinalized(
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit ETHWithdrawalFinalized(_from, _to, _amount, _extraData);
super._emitETHBridgeFinalized(_from, _to, _amount, _extraData);
}
/**
* @notice Emits the legacy ERC20DepositInitiated event followed by the ERC20BridgeInitiated
* event. This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitERC20BridgeInitiated(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit ERC20DepositInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
/**
* @notice Emits the legacy ERC20WithdrawalFinalized event followed by the ERC20BridgeFinalized
* event. This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitERC20BridgeFinalized(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit ERC20WithdrawalFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
}
......@@ -148,8 +148,6 @@ contract L2StandardBridge is StandardBridge, Semver {
} else {
finalizeBridgeERC20(_l2Token, _l1Token, _from, _to, _amount, _extraData);
}
emit DepositFinalized(_l1Token, _l2Token, _from, _to, _amount, _extraData);
}
/**
......@@ -187,7 +185,87 @@ contract L2StandardBridge is StandardBridge, Semver {
} else {
_initiateBridgeERC20(_l2Token, l1Token, _from, _to, _amount, _minGasLimit, _extraData);
}
}
/**
* @notice Emits the legacy WithdrawalInitiated event followed by the ETHBridgeInitiated event.
* This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitETHBridgeInitiated(
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit WithdrawalInitiated(
address(0),
Predeploys.LEGACY_ERC20_ETH,
_from,
_to,
_amount,
_extraData
);
super._emitETHBridgeInitiated(_from, _to, _amount, _extraData);
}
/**
* @notice Emits the legacy DepositFinalized event followed by the ETHBridgeFinalized event.
* This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitETHBridgeFinalized(
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit DepositFinalized(
address(0),
Predeploys.LEGACY_ERC20_ETH,
_from,
_to,
_amount,
_extraData
);
super._emitETHBridgeFinalized(_from, _to, _amount, _extraData);
}
/**
* @notice Emits the legacy WithdrawalInitiated event followed by the ERC20BridgeInitiated
* event. This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitERC20BridgeInitiated(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit WithdrawalInitiated(_remoteToken, _localToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
emit WithdrawalInitiated(l1Token, _l2Token, _from, _to, _amount, _extraData);
/**
* @notice Emits the legacy DepositFinalized event followed by the ERC20BridgeFinalized event.
* This is necessary for backwards compatibility with the legacy bridge.
*
* @inheritdoc StandardBridge
*/
function _emitERC20BridgeFinalized(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal override {
emit DepositFinalized(_remoteToken, _localToken, _from, _to, _amount, _extraData);
super._emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
}
......@@ -4,7 +4,10 @@ pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol";
import { AddressAliasHelper } from "../vendor/AddressAliasHelper.sol";
contract AddressAliasHelper_Test is Test {
contract AddressAliasHelper_applyAndUndo_Test is Test {
/**
* @notice Tests that applying and then undoing an alias results in the original address.
*/
function testFuzz_applyAndUndo_succeeds(address _address) external {
address aliased = AddressAliasHelper.applyL1ToL2Alias(_address);
address unaliased = AddressAliasHelper.undoL1ToL2Alias(aliased);
......
......@@ -71,34 +71,37 @@ contract L1StandardBridge_Receive_Test is Bridge_Initializer {
contract L1StandardBridge_Receive_TestFail {}
contract L1StandardBridge_DepositETH_Test is Bridge_Initializer {
// depositETH
// - emits ETHDepositInitiated
// - calls optimismPortal.depositTransaction
// - only EOA
// - ETH ends up in the optimismPortal
function test_depositETH_succeeds() external {
contract PreBridgeETH is Bridge_Initializer {
function _preBridgeETH(bool isLegacy) internal {
assertEq(address(op).balance, 0);
uint256 nonce = L1Messenger.messageNonce();
uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION
address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(L1Messenger));
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHDepositInitiated(alice, alice, 500, hex"ff");
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHBridgeInitiated(alice, alice, 500, hex"ff");
bytes memory message = abi.encodeWithSelector(
StandardBridge.finalizeBridgeETH.selector,
alice,
alice,
500,
hex"ff"
hex"dead"
);
if (isLegacy) {
vm.expectCall(
address(L1Bridge),
500,
abi.encodeWithSelector(L1Bridge.depositETH.selector, 50000, hex"dead")
);
} else {
vm.expectCall(
address(L1Bridge),
500,
abi.encodeWithSelector(L1Bridge.bridgeETH.selector, 50000, hex"dead")
);
}
vm.expectCall(
address(L1Messenger),
500,
abi.encodeWithSelector(
CrossDomainMessenger.sendMessage.selector,
address(L2Bridge),
......@@ -120,6 +123,7 @@ contract L1StandardBridge_DepositETH_Test is Bridge_Initializer {
uint64 baseGas = L1Messenger.baseGas(message, 50000);
vm.expectCall(
address(op),
500,
abi.encodeWithSelector(
OptimismPortal.depositTransaction.selector,
address(L2Messenger),
......@@ -138,6 +142,12 @@ contract L1StandardBridge_DepositETH_Test is Bridge_Initializer {
innerMessage
);
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHDepositInitiated(alice, alice, 500, hex"dead");
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHBridgeInitiated(alice, alice, 500, hex"dead");
// OptimismPortal emits a TransactionDeposited event on `depositTransaction` call
vm.expectEmit(true, true, true, true, address(op));
emit TransactionDeposited(l1MessengerAliased, address(L2Messenger), version, opaqueData);
......@@ -151,7 +161,33 @@ contract L1StandardBridge_DepositETH_Test is Bridge_Initializer {
emit SentMessageExtension1(address(L1Bridge), 500);
vm.prank(alice, alice);
L1Bridge.depositETH{ value: 500 }(50000, hex"ff");
}
}
contract L1StandardBridge_DepositETH_Test is PreBridgeETH {
// depositETH
// - emits ETHDepositInitiated
// - emits ETHBridgeInitiated
// - calls optimismPortal.depositTransaction
// - only EOA
// - ETH ends up in the optimismPortal
function test_depositETH_succeeds() external {
_preBridgeETH({ isLegacy: true });
L1Bridge.depositETH{ value: 500 }(50000, hex"dead");
assertEq(address(op).balance, 500);
}
}
contract L1StandardBridge_BridgeETH_Test is PreBridgeETH {
// BridgeETH
// - emits ETHDepositInitiated
// - emits ETHBridgeInitiated
// - calls optimismPortal.depositTransaction
// - only EOA
// - ETH ends up in the optimismPortal
function test_bridgeETH_succeeds() external {
_preBridgeETH({ isLegacy: false });
L1Bridge.bridgeETH{ value: 500 }(50000, hex"dead");
assertEq(address(op).balance, 500);
}
}
......@@ -167,29 +203,26 @@ contract L1StandardBridge_DepositETH_TestFail is Bridge_Initializer {
}
}
contract L1StandardBridge_DepositETHTo_Test is Bridge_Initializer {
// depositETHTo
// - emits ETHDepositInitiated
// - calls optimismPortal.depositTransaction
// - EOA or contract can call
// - ETH ends up in the optimismPortal
function test_depositETHTo_succeeds() external {
contract PreBridgeETHTo is Bridge_Initializer {
function _preBridgeETHTo(bool isLegacy) internal {
assertEq(address(op).balance, 0);
uint256 nonce = L1Messenger.messageNonce();
uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION
address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(L1Messenger));
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHDepositInitiated(alice, bob, 600, hex"dead");
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHBridgeInitiated(alice, bob, 600, hex"dead");
// depositETHTo on the L1 bridge should be called
vm.expectCall(
address(L1Bridge),
abi.encodeWithSelector(L1Bridge.depositETHTo.selector, bob, 1000, hex"dead")
);
if (isLegacy) {
vm.expectCall(
address(L1Bridge),
600,
abi.encodeWithSelector(L1Bridge.depositETHTo.selector, bob, 60000, hex"dead")
);
} else {
vm.expectCall(
address(L1Bridge),
600,
abi.encodeWithSelector(L1Bridge.bridgeETHTo.selector, bob, 60000, hex"dead")
);
}
bytes memory message = abi.encodeWithSelector(
StandardBridge.finalizeBridgeETH.selector,
......@@ -207,7 +240,7 @@ contract L1StandardBridge_DepositETHTo_Test is Bridge_Initializer {
CrossDomainMessenger.sendMessage.selector,
address(L2Bridge),
message,
1000
60000
)
);
......@@ -217,11 +250,11 @@ contract L1StandardBridge_DepositETHTo_Test is Bridge_Initializer {
address(L1Bridge),
address(L2Bridge),
600,
1000,
60000,
message
);
uint64 baseGas = L1Messenger.baseGas(message, 1000);
uint64 baseGas = L1Messenger.baseGas(message, 60000);
vm.expectCall(
address(op),
abi.encodeWithSelector(
......@@ -242,13 +275,19 @@ contract L1StandardBridge_DepositETHTo_Test is Bridge_Initializer {
innerMessage
);
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHDepositInitiated(alice, bob, 600, hex"dead");
vm.expectEmit(true, true, true, true, address(L1Bridge));
emit ETHBridgeInitiated(alice, bob, 600, hex"dead");
// OptimismPortal emits a TransactionDeposited event on `depositTransaction` call
vm.expectEmit(true, true, true, true, address(op));
emit TransactionDeposited(l1MessengerAliased, address(L2Messenger), version, opaqueData);
// SentMessage event emitted by the CrossDomainMessenger
vm.expectEmit(true, true, true, true, address(L1Messenger));
emit SentMessage(address(L2Bridge), address(L1Bridge), message, nonce, 1000);
emit SentMessage(address(L2Bridge), address(L1Bridge), message, nonce, 60000);
// SentMessageExtension1 event emitted by the CrossDomainMessenger
vm.expectEmit(true, true, true, true, address(L1Messenger));
......@@ -256,7 +295,33 @@ contract L1StandardBridge_DepositETHTo_Test is Bridge_Initializer {
// deposit eth to bob
vm.prank(alice, alice);
L1Bridge.depositETHTo{ value: 600 }(bob, 1000, hex"dead");
}
}
contract L1StandardBridge_DepositETHTo_Test is PreBridgeETHTo {
// depositETHTo
// - emits ETHDepositInitiated
// - calls optimismPortal.depositTransaction
// - EOA or contract can call
// - ETH ends up in the optimismPortal
function test_depositETHTo_succeeds() external {
_preBridgeETHTo({ isLegacy: true });
L1Bridge.depositETHTo{ value: 600 }(bob, 60000, hex"dead");
assertEq(address(op).balance, 600);
}
}
contract L1StandardBridge_BridgeETHTo_Test is PreBridgeETHTo {
// BridgeETHTo
// - emits ETHDepositInitiated
// - emits ETHBridgeInitiated
// - calls optimismPortal.depositTransaction
// - only EOA
// - ETH ends up in the optimismPortal
function test_bridgeETHTo_succeeds() external {
_preBridgeETHTo({ isLegacy: false });
L1Bridge.bridgeETHTo{ value: 600 }(bob, 60000, hex"dead");
assertEq(address(op).balance, 600);
}
}
......
......@@ -301,7 +301,9 @@ abstract contract StandardBridge {
require(_to != address(this), "StandardBridge: cannot send to self");
require(_to != address(MESSENGER), "StandardBridge: cannot send to messenger");
emit ETHBridgeFinalized(_from, _to, _amount, _extraData);
// Emit the correct events. By default this will be _amount, but child
// contracts may override this function in order to emit legacy events as well.
_emitETHBridgeFinalized(_from, _to, _amount, _extraData);
bool success = SafeCall.call(_to, gasleft(), _amount, hex"");
require(success, "StandardBridge: ETH transfer failed");
......@@ -340,7 +342,9 @@ abstract contract StandardBridge {
IERC20(_localToken).safeTransfer(_to, _amount);
}
emit ERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
// Emit the correct events. By default this will be ERC20BridgeFinalized, but child
// contracts may override this function in order to emit legacy events as well.
_emitERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
/**
......@@ -366,7 +370,9 @@ abstract contract StandardBridge {
"StandardBridge: bridging ETH must include sufficient ETH value"
);
emit ETHBridgeInitiated(_from, _to, _amount, _extraData);
// Emit the correct events. By default this will be _amount, but child
// contracts may override this function in order to emit legacy events as well.
_emitETHBridgeInitiated(_from, _to, _amount, _extraData);
MESSENGER.sendMessage{ value: _amount }(
address(OTHER_BRIDGE),
......@@ -414,7 +420,9 @@ abstract contract StandardBridge {
deposits[_localToken][_remoteToken] = deposits[_localToken][_remoteToken] + _amount;
}
emit ERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
// Emit the correct events. By default this will be ERC20BridgeInitiated, but child
// contracts may override this function in order to emit legacy events as well.
_emitERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
MESSENGER.sendMessage(
address(OTHER_BRIDGE),
......@@ -463,4 +471,83 @@ abstract contract StandardBridge {
{
return _otherToken == OptimismMintableERC20(_mintableToken).l1Token();
}
/** @notice Emits the ETHBridgeInitiated event and if necessary the appropriate legacy event
* when an ETH bridge is finalized on this chain.
*
* @param _from Address of the sender.
* @param _to Address of the receiver.
* @param _amount Amount of ETH sent.
* @param _extraData Extra data sent with the transaction.
*/
function _emitETHBridgeInitiated(
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal virtual {
emit ETHBridgeInitiated(_from, _to, _amount, _extraData);
}
/**
* @notice Emits the ETHBridgeFinalized and if necessary the appropriate legacy event when an
* ETH bridge is finalized on this chain.
*
* @param _from Address of the sender.
* @param _to Address of the receiver.
* @param _amount Amount of ETH sent.
* @param _extraData Extra data sent with the transaction.
*/
function _emitETHBridgeFinalized(
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal virtual {
emit ETHBridgeFinalized(_from, _to, _amount, _extraData);
}
/**
* @notice Emits the ERC20BridgeInitiated event and if necessary the appropriate legacy
* event when an ERC20 bridge is initiated to the other chain.
*
* @param _localToken Address of the ERC20 on this chain.
* @param _remoteToken Address of the ERC20 on the remote chain.
* @param _from Address of the sender.
* @param _to Address of the receiver.
* @param _amount Amount of the ERC20 sent.
* @param _extraData Extra data sent with the transaction.
*/
function _emitERC20BridgeInitiated(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal virtual {
emit ERC20BridgeInitiated(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
/**
* @notice Emits the ERC20BridgeFinalized event and if necessary the appropriate legacy
* event when an ERC20 bridge is initiated to the other chain.
*
* @param _localToken Address of the ERC20 on this chain.
* @param _remoteToken Address of the ERC20 on the remote chain.
* @param _from Address of the sender.
* @param _to Address of the receiver.
* @param _amount Amount of the ERC20 sent.
* @param _extraData Extra data sent with the transaction.
*/
function _emitERC20BridgeFinalized(
address _localToken,
address _remoteToken,
address _from,
address _to,
uint256 _amount,
bytes memory _extraData
) internal virtual {
emit ERC20BridgeFinalized(_localToken, _remoteToken, _from, _to, _amount, _extraData);
}
}
......@@ -4,15 +4,15 @@ AssetReceiverTest:testFail_withdrawERC721() (gas: 55908)
AssetReceiverTest:testFail_withdrawETH() (gas: 10457)
AssetReceiverTest:testFail_withdrawETHwithAmount() (gas: 10594)
AssetReceiverTest:test_constructor() (gas: 9794)
AssetReceiverTest:test_receive() (gas: 18860)
AssetReceiverTest:test_withdrawERC20() (gas: 183064)
AssetReceiverTest:test_withdrawERC20withAmount() (gas: 182146)
AssetReceiverTest:test_withdrawERC721() (gas: 49097)
AssetReceiverTest:test_withdrawETH() (gas: 26179)
AssetReceiverTest:test_withdrawETHwithAmount() (gas: 26108)
AssetReceiverTest:test_attest_bulk() (gas: 611440)
AssetReceiverTest:test_attest_individual() (gas: 538514)
AssetReceiverTest:test_attest_single() (gas: 558962)
AssetReceiverTest:test_receive() (gas: 21010)
AssetReceiverTest:test_withdrawERC20() (gas: 185529)
AssetReceiverTest:test_withdrawERC20withAmount() (gas: 184609)
AssetReceiverTest:test_withdrawERC721() (gas: 51565)
AssetReceiverTest:test_withdrawETH() (gas: 28774)
AssetReceiverTest:test_withdrawETHwithAmount() (gas: 28703)
AssetReceiverTest:test_attest_bulk() (gas: 611417)
AssetReceiverTest:test_attest_individual() (gas: 538536)
AssetReceiverTest:test_attest_single() (gas: 558939)
CheckBalanceHighTest:testFuzz_check_fails(address,uint256) (runs: 256, μ: 12352, ~: 12382)
CheckBalanceHighTest:testFuzz_check_succeeds(address,uint256) (runs: 256, μ: 10284, ~: 10284)
CheckBalanceLowTest:testFuzz_check_fails(address,uint256) (runs: 256, μ: 10262, ~: 10262)
......@@ -45,7 +45,7 @@ OptimistTest:test_optimist_baseURI() (gas: 116809)
OptimistTest:test_optimist_burn() (gas: 77526)
OptimistTest:test_optimist_initialize() (gas: 23095)
OptimistTest:test_optimist_is_on_allow_list() (gas: 52616)
OptimistTest:test_optimist_mint_already_minted() (gas: 98911)
OptimistTest:test_optimist_mint_already_minted() (gas: 98823)
OptimistTest:test_optimist_mint_happy_path() (gas: 99175)
OptimistTest:test_optimist_mint_no_attestation() (gas: 15897)
OptimistTest:test_optimist_mint_secondary_minter() (gas: 100576)
......@@ -54,9 +54,9 @@ OptimistTest:test_optimist_sbt_transfer() (gas: 102331)
OptimistTest:test_optimist_set_approval_for_all() (gas: 100907)
OptimistTest:test_optimist_supports_interface() (gas: 5797)
OptimistTest:test_optimist_token_id_of_owner() (gas: 95045)
OptimistTest:test_optimist_token_uri() (gas: 213950)
TransactorTest:testFail_CALL() (gas: 15658)
OptimistTest:test_optimist_token_uri() (gas: 213972)
TransactorTest:testFail_CALL() (gas: 15636)
TransactorTest:testFail_DELEGATECALLL() (gas: 15632)
TransactorTest:test_CALL() (gas: 26977)
TransactorTest:test_DELEGATECALL() (gas: 21122)
TransactorTest:test_constructor() (gas: 9782)
TransactorTest:test_CALL() (gas: 26969)
TransactorTest:test_DELEGATECALL() (gas: 21189)
TransactorTest:test_constructor() (gas: 9772)
......@@ -17,7 +17,22 @@ contract AssetReceiver_Initializer is Test {
TestERC721 testERC721;
AssetReceiver assetReceiver;
function _setUp() public {
event ReceivedETH(address indexed from, uint256 amount);
event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);
event WithdrewERC20(
address indexed withdrawer,
address indexed recipient,
address indexed asset,
uint256 amount
);
event WithdrewERC721(
address indexed withdrawer,
address indexed recipient,
address indexed asset,
uint256 id
);
function setUp() public {
// Deploy ERC20 and ERC721 tokens
testERC20 = new TestERC20();
testERC721 = new TestERC721();
......@@ -38,10 +53,6 @@ contract AssetReceiver_Initializer is Test {
}
contract AssetReceiverTest is AssetReceiver_Initializer {
function setUp() public {
super._setUp();
}
// Tests if the owner was set correctly during deploy
function test_constructor() external {
assertEq(address(alice), assetReceiver.owner());
......@@ -52,6 +63,8 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
// Check that contract balance is 0 initially
assertEq(address(assetReceiver).balance, 0);
vm.expectEmit(true, true, true, true, address(assetReceiver));
emit ReceivedETH(alice, 100);
// Send funds
vm.prank(alice);
(bool success, ) = address(assetReceiver).call{ value: 100 }(hex"");
......@@ -71,6 +84,9 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(address(alice).balance, 1 ether);
vm.expectEmit(true, true, true, true, address(assetReceiver));
emit WithdrewETH(alice, alice, 1 ether);
// call withdrawETH
vm.prank(alice);
assetReceiver.withdrawETH(payable(alice));
......@@ -96,6 +112,9 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(address(alice).balance, 1 ether);
vm.expectEmit(true, true, true, true, address(assetReceiver));
emit WithdrewETH(alice, alice, 0.5 ether);
// call withdrawETH
vm.prank(alice);
assetReceiver.withdrawETH(payable(alice), 0.5 ether);
......@@ -121,6 +140,9 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(testERC20.balanceOf(address(assetReceiver)), 100_000);
assertEq(testERC20.balanceOf(alice), 0);
vm.expectEmit(true, true, true, true, address(assetReceiver));
emit WithdrewERC20(alice, alice, address(testERC20), 100_000);
// call withdrawERC20
vm.prank(alice);
assetReceiver.withdrawERC20(testERC20, alice);
......@@ -146,6 +168,9 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
assertEq(testERC20.balanceOf(address(assetReceiver)), 100_000);
assertEq(testERC20.balanceOf(alice), 0);
vm.expectEmit(true, true, true, true, address(assetReceiver));
emit WithdrewERC20(alice, alice, address(testERC20), 50_000);
// call withdrawERC20
vm.prank(alice);
assetReceiver.withdrawERC20(testERC20, alice, 50_000);
......@@ -172,6 +197,9 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID);
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), address(assetReceiver));
vm.expectEmit(true, true, true, true, address(assetReceiver));
emit WithdrewERC721(alice, alice, address(testERC721), DEFAULT_TOKEN_ID);
// Call withdrawERC721
vm.prank(alice);
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID);
......
......@@ -11,7 +11,7 @@ contract AssetReceiver_Initializer is Test {
address bob = address(256);
address sally = address(512);
function _setUp() public {
function setUp() public {
// Give alice and bob some ETH
vm.deal(alice_attestor, 1 ether);
......@@ -22,10 +22,6 @@ contract AssetReceiver_Initializer is Test {
}
contract AssetReceiverTest is AssetReceiver_Initializer {
function setUp() public {
super._setUp();
}
event AttestationCreated(
address indexed creator,
address indexed about,
......
......@@ -47,7 +47,7 @@ contract Optimist_Initializer is Test {
attestationStation.attest(attestationData);
}
function _setUp() public {
function setUp() public {
// Give alice and bob and sally some ETH
vm.deal(alice_admin, 1 ether);
vm.deal(bob, 1 ether);
......@@ -68,11 +68,6 @@ contract Optimist_Initializer is Test {
}
contract OptimistTest is Optimist_Initializer {
function setUp() public {
super._setUp();
_initializeContracts();
}
function test_optimist_initialize() external {
// expect name to be set
assertEq(optimist.name(), name);
......
......@@ -15,7 +15,7 @@ contract Transactor_Initializer is Test {
Reverter reverter;
CallRecorder callRecorded;
function _setUp() public {
function setUp() public {
// Deploy Reverter and CallRecorder helper contracts
reverter = new Reverter();
callRecorded = new CallRecorder();
......@@ -34,10 +34,6 @@ contract Transactor_Initializer is Test {
}
contract TransactorTest is Transactor_Initializer {
function setUp() public {
super._setUp();
}
// Tests if the owner was set correctly during deploy
function test_constructor() external {
assertEq(address(alice), transactor.owner());
......@@ -49,7 +45,7 @@ contract TransactorTest is Transactor_Initializer {
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
// Run CALL
vm.prank(alice);
vm.expectCall(address(callRecorded), data);
vm.expectCall(address(callRecorded), 200_000 wei, data);
transactor.CALL(address(callRecorded), data, 200_000 wei);
}
......
......@@ -16,10 +16,9 @@
"build": "yarn build:hh",
"build:hh": "hardhat compile --show-stack-traces",
"build:forge": "forge build",
"test": "yarn test:contracts",
"test:contracts": "hardhat test --show-stack-traces",
"test": "yarn test:forge",
"test:forge": "forge test",
"test:coverage": "NODE_OPTIONS=--max_old_space_size=8192 hardhat coverage && yarn test:coverage:forge",
"test:coverage": "yarn test:coverage:forge",
"test:coverage:forge": "forge coverage",
"test:slither": "slither .",
"gas-snapshot": "forge snapshot",
......@@ -54,7 +53,6 @@
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"devDependencies": {
"@defi-wonderland/smock": "^2.0.7",
"@eth-optimism/contracts-bedrock": "0.11.3",
"@eth-optimism/core-utils": "^0.12.0",
"@eth-optimism/hardhat-deploy-config": "^0.2.5",
......@@ -65,8 +63,6 @@
"@rari-capital/solmate": "7.0.0-alpha.3",
"@openzeppelin/contracts": "4.7.3",
"@openzeppelin/contracts-upgradeable": "4.7.3",
"@types/chai": "^4.2.18",
"@types/mocha": "^8.2.2",
"@types/node": "^17.0.21",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
......@@ -82,7 +78,6 @@
"hardhat-deploy": "^0.11.10",
"hardhat-gas-reporter": "^1.0.8",
"lint-staged": "11.0.0",
"mocha": "^10.0.0",
"mkdirp": "^1.0.4",
"node-fetch": "^2.6.7",
"prettier": "^2.8.0",
......
import hre from 'hardhat'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { Contract } from 'ethers'
import { expect } from '../../setup'
import { deploy } from '../../helpers'
describe('AssetReceiver', () => {
const DEFAULT_TOKEN_ID = 0
const DEFAULT_AMOUNT = hre.ethers.constants.WeiPerEther
const DEFAULT_RECIPIENT = '0x' + '11'.repeat(20)
let signer1: SignerWithAddress
let signer2: SignerWithAddress
before('signer setup', async () => {
;[signer1, signer2] = await hre.ethers.getSigners()
})
let TestERC20: Contract
let TestERC721: Contract
let AssetReceiver: Contract
beforeEach('deploy contracts', async () => {
TestERC20 = await deploy('TestERC20', { signer: signer1 })
TestERC721 = await deploy('TestERC721', { signer: signer1 })
AssetReceiver = await deploy('AssetReceiver', {
signer: signer1,
args: [signer1.address],
})
})
beforeEach('balance setup', async () => {
await TestERC20.mint(signer1.address, hre.ethers.constants.MaxUint256)
await TestERC721.mint(signer1.address, DEFAULT_TOKEN_ID)
await hre.ethers.provider.send('hardhat_setBalance', [
DEFAULT_RECIPIENT,
'0x0',
])
})
describe('receive', () => {
it('should be able to receive ETH', async () => {
await expect(
signer1.sendTransaction({
to: AssetReceiver.address,
value: DEFAULT_AMOUNT,
})
).to.not.be.reverted
expect(
await hre.ethers.provider.getBalance(AssetReceiver.address)
).to.equal(DEFAULT_AMOUNT)
})
})
describe('withdrawETH(address)', () => {
describe('when called by authorized address', () => {
it('should withdraw all ETH in the contract', async () => {
await signer1.sendTransaction({
to: AssetReceiver.address,
value: DEFAULT_AMOUNT,
})
await expect(AssetReceiver['withdrawETH(address)'](DEFAULT_RECIPIENT))
.to.emit(AssetReceiver, 'WithdrewETH')
.withArgs(signer1.address, DEFAULT_RECIPIENT, DEFAULT_AMOUNT)
expect(
await hre.ethers.provider.getBalance(AssetReceiver.address)
).to.equal(0)
expect(
await hre.ethers.provider.getBalance(DEFAULT_RECIPIENT)
).to.equal(DEFAULT_AMOUNT)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
AssetReceiver.connect(signer2)['withdrawETH(address)'](
signer2.address
)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('withdrawETH(address,uint256)', () => {
describe('when called by authorized address', () => {
it('should withdraw the given amount of ETH', async () => {
await signer1.sendTransaction({
to: AssetReceiver.address,
value: DEFAULT_AMOUNT.mul(2),
})
await expect(
AssetReceiver['withdrawETH(address,uint256)'](
DEFAULT_RECIPIENT,
DEFAULT_AMOUNT
)
)
.to.emit(AssetReceiver, 'WithdrewETH')
.withArgs(signer1.address, DEFAULT_RECIPIENT, DEFAULT_AMOUNT)
expect(
await hre.ethers.provider.getBalance(AssetReceiver.address)
).to.equal(DEFAULT_AMOUNT)
expect(
await hre.ethers.provider.getBalance(DEFAULT_RECIPIENT)
).to.equal(DEFAULT_AMOUNT)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
AssetReceiver.connect(signer2)['withdrawETH(address,uint256)'](
DEFAULT_RECIPIENT,
DEFAULT_AMOUNT
)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('withdrawERC20(address,address)', () => {
describe('when called by authorized address', () => {
it('should withdraw all ERC20 balance held by the contract', async () => {
await TestERC20.transfer(AssetReceiver.address, DEFAULT_AMOUNT)
await expect(
AssetReceiver['withdrawERC20(address,address)'](
TestERC20.address,
DEFAULT_RECIPIENT
)
)
.to.emit(AssetReceiver, 'WithdrewERC20')
.withArgs(
signer1.address,
DEFAULT_RECIPIENT,
TestERC20.address,
DEFAULT_AMOUNT
)
expect(await TestERC20.balanceOf(DEFAULT_RECIPIENT)).to.equal(
DEFAULT_AMOUNT
)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
AssetReceiver.connect(signer2)['withdrawERC20(address,address)'](
TestERC20.address,
DEFAULT_RECIPIENT
)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('withdrawERC20(address,address,uint256)', () => {
describe('when called by authorized address', () => {
it('should withdraw the given ERC20 amount', async () => {
await TestERC20.transfer(AssetReceiver.address, DEFAULT_AMOUNT.mul(2))
await expect(
AssetReceiver['withdrawERC20(address,address,uint256)'](
TestERC20.address,
DEFAULT_RECIPIENT,
DEFAULT_AMOUNT
)
)
.to.emit(AssetReceiver, 'WithdrewERC20')
.withArgs(
signer1.address,
DEFAULT_RECIPIENT,
TestERC20.address,
DEFAULT_AMOUNT
)
expect(await TestERC20.balanceOf(DEFAULT_RECIPIENT)).to.equal(
DEFAULT_AMOUNT
)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
AssetReceiver.connect(signer2)[
'withdrawERC20(address,address,uint256)'
](TestERC20.address, DEFAULT_RECIPIENT, DEFAULT_AMOUNT)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('withdrawERC721', () => {
describe('when called by authorized address', () => {
it('should withdraw the token', async () => {
await TestERC721.transferFrom(
signer1.address,
AssetReceiver.address,
DEFAULT_TOKEN_ID
)
await expect(
AssetReceiver.withdrawERC721(
TestERC721.address,
DEFAULT_RECIPIENT,
DEFAULT_TOKEN_ID
)
)
.to.emit(AssetReceiver, 'WithdrewERC721')
.withArgs(
signer1.address,
DEFAULT_RECIPIENT,
TestERC721.address,
DEFAULT_TOKEN_ID
)
expect(await TestERC721.ownerOf(DEFAULT_TOKEN_ID)).to.equal(
DEFAULT_RECIPIENT
)
})
})
describe('when called by not authorized address', () => {
it('should revert', async () => {
await expect(
AssetReceiver.connect(signer2).withdrawERC721(
TestERC721.address,
DEFAULT_RECIPIENT,
DEFAULT_TOKEN_ID
)
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
})
import hre from 'hardhat'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { Contract } from 'ethers'
import { expect } from '../../setup'
import { decodeSolidityRevert, deploy } from '../../helpers'
describe('Transactor', () => {
let signer1: SignerWithAddress
let signer2: SignerWithAddress
before('signer setup', async () => {
;[signer1, signer2] = await hre.ethers.getSigners()
})
let CallRecorder: Contract
let Reverter: Contract
let Transactor: Contract
beforeEach('deploy contracts', async () => {
CallRecorder = await deploy('CallRecorder')
Reverter = await deploy('Reverter')
Transactor = await deploy('Transactor', {
signer: signer1,
args: [signer1.address],
})
})
describe('CALL', () => {
describe('when called by authorized address', () => {
it('should do a call to the target contract', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
await Transactor.CALL(CallRecorder.address, data, 0, {
gasLimit: 2_000_000,
})
const call = await CallRecorder.lastCall()
expect(call.data).to.equal(data)
expect(call.sender).to.equal(Transactor.address)
})
it('should be able to call with value', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
const value = 69
await Transactor.CALL(CallRecorder.address, data, value, {
gasLimit: 2_000_000,
value,
})
const call = await CallRecorder.lastCall()
expect(call.value).to.equal(value)
})
})
describe('when called by not authorized address', () => {
it('should be reverted', async () => {
const data = CallRecorder.interface.encodeFunctionData('record')
await expect(
Transactor.connect(signer2).CALL(CallRecorder.address, data, 0, {
gasLimit: 2_000_000,
})
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
describe('DELEGATECALL', () => {
describe('when called by authorized address', () => {
it('should do a delegatecall to the target contract', async () => {
const data = Reverter.interface.encodeFunctionData('doRevert')
const ret = await Transactor.callStatic.DELEGATECALL(
Reverter.address,
data,
{
gasLimit: 2_000_000,
}
)
expect(ret[0]).to.equal(false)
expect(decodeSolidityRevert(ret[1])).to.deep.equal('Reverter reverted')
})
})
describe('when called by not authorized address', () => {
it('should be reverted', async () => {
const data = Reverter.interface.encodeFunctionData('doRevert')
await expect(
Transactor.connect(signer2).DELEGATECALL(Reverter.address, data, {
gasLimit: 2_000_000,
})
).to.be.revertedWith('UNAUTHORIZED')
})
})
})
})
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckBalanceHigh', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckBalanceHigh: Contract
before(async () => {
CheckBalanceHigh = await deploy('CheckBalanceHigh')
})
describe('check', () => {
it('should return true when balance is above threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD + 1),
])
expect(
await CheckBalanceHigh.check(
encodeDripCheckParams(CheckBalanceHigh.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(true)
})
it('should return false when balance is below threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD - 1),
])
expect(
await CheckBalanceHigh.check(
encodeDripCheckParams(CheckBalanceHigh.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(false)
})
})
})
import hre from 'hardhat'
import { Contract } from 'ethers'
import { toRpcHexString } from '@eth-optimism/core-utils'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckBalanceLow', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckBalanceLow: Contract
before(async () => {
CheckBalanceLow = await deploy('CheckBalanceLow')
})
describe('check', () => {
it('should return true when balance is below threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD - 1),
])
expect(
await CheckBalanceLow.check(
encodeDripCheckParams(CheckBalanceLow.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(true)
})
it('should return false when balance is above threshold', async () => {
await hre.ethers.provider.send('hardhat_setBalance', [
RECIPIENT,
toRpcHexString(THRESHOLD + 1),
])
expect(
await CheckBalanceLow.check(
encodeDripCheckParams(CheckBalanceLow.interface, {
target: RECIPIENT,
threshold: THRESHOLD,
})
)
).to.equal(false)
})
})
})
import { Contract } from 'ethers'
import { smock, FakeContract } from '@defi-wonderland/smock'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
import { encodeDripCheckParams } from '../../../../../src'
describe('CheckGelatoLow', () => {
const RECIPIENT = '0x' + '11'.repeat(20)
const THRESHOLD = 100
let CheckGelatoLow: Contract
let FakeGelatoTresury: FakeContract<Contract>
before(async () => {
CheckGelatoLow = await deploy('CheckGelatoLow')
FakeGelatoTresury = await smock.fake('IGelatoTreasury')
})
describe('check', () => {
it('should return true when balance is below threshold', async () => {
FakeGelatoTresury.userTokenBalance.returns(THRESHOLD - 1)
expect(
await CheckGelatoLow.check(
encodeDripCheckParams(CheckGelatoLow.interface, {
treasury: FakeGelatoTresury.address,
threshold: THRESHOLD,
recipient: RECIPIENT,
})
)
).to.equal(true)
})
it('should return false when balance is above threshold', async () => {
FakeGelatoTresury.userTokenBalance.returns(THRESHOLD + 1)
expect(
await CheckGelatoLow.check(
encodeDripCheckParams(CheckGelatoLow.interface, {
treasury: FakeGelatoTresury.address,
threshold: THRESHOLD,
recipient: RECIPIENT,
})
)
).to.equal(false)
})
})
})
import { Contract } from 'ethers'
import { expect } from '../../../../setup'
import { deploy } from '../../../../helpers'
describe('CheckTrue', () => {
let CheckTrue: Contract
before(async () => {
CheckTrue = await deploy('CheckTrue')
})
describe('check', () => {
it('should return true', async () => {
expect(await CheckTrue.check('0x')).to.equal(true)
})
})
})
export const NON_NULL_BYTES32 = '0x' + '11'.repeat(32)
export const NON_ZERO_ADDRESS = '0x' + '11'.repeat(20)
import hre from 'hardhat'
export const deploy = async (
name: string,
opts?: {
args?: any[]
signer?: any
}
) => {
const factory = await hre.ethers.getContractFactory(name, opts?.signer)
return factory.deploy(...(opts?.args || []))
}
export * from './deploy'
export * from './solidity'
export * from './constants'
import { ethers } from 'ethers'
export const decodeSolidityRevert = (revert: string) => {
const iface = new ethers.utils.Interface([
{
inputs: [
{
internalType: 'string',
name: 'message',
type: 'string',
},
],
name: 'Error',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
])
return iface.decodeFunctionData('Error', revert)[0]
}
/* External Imports */
import chai = require('chai')
import Mocha from 'mocha'
import { solidity } from 'ethereum-waffle'
chai.use(solidity)
const should = chai.should()
const expect = chai.expect
export { should, expect, Mocha }
......@@ -340,29 +340,44 @@ task('deposit-erc20', 'Deposits WETH9 onto L2.')
)
console.log('Finalizing withdrawal...')
const finalize = await messenger.finalizeMessage(withdraw)
// TODO: Update SDK to properly estimate gas
const finalize = await messenger.finalizeMessage(withdraw, {
overrides: { gasLimit: 500_000 },
})
const finalizeReceipt = await finalize.wait()
console.log('finalizeReceipt:', finalizeReceipt)
console.log(`Took ${Math.floor(Date.now() / 1000) - now} seconds`)
for (const log of finalizeReceipt.logs) {
switch (log.address) {
case OptimismPortal.address: {
const parsed = OptimismPortal.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(`Log ${parsed.name} from OptimismPortal (${log.address})`)
console.log(parsed.args)
console.log()
break
}
case L1CrossDomainMessenger.address: {
const parsed = L1CrossDomainMessenger.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(
`Log ${parsed.name} from L1CrossDomainMessenger (${log.address})`
)
console.log(parsed.args)
console.log()
break
}
case L1StandardBridge.address: {
const parsed = L1StandardBridge.interface.parseLog(log)
console.log(`Log ${parsed.name} from ${log.address}`)
console.log(
`Log ${parsed.name} from L1StandardBridge (${log.address})`
)
console.log(parsed.args)
console.log()
break
}
case WETH9.address: {
const parsed = WETH9.interface.parseLog(log)
console.log(`Log ${parsed.name} from WETH9 (${log.address})`)
console.log(parsed.args)
console.log()
break
......@@ -378,7 +393,9 @@ task('deposit-erc20', 'Deposits WETH9 onto L2.')
const expectedBalance = preBalance.add(utils.parseEther('1'))
if (!expectedBalance.eq(postBalance)) {
throw new Error('Balance mismatch')
throw new Error(
`Balance mismatch, expected: ${expectedBalance}, actual: ${postBalance}`
)
}
console.log('Withdrawal success')
})
......@@ -374,7 +374,10 @@ task('deposit-eth', 'Deposits ether to L2.')
console.log(parsed.name)
console.log(parsed.args)
console.log()
if (parsed.name !== 'ETHBridgeFinalized') {
if (
parsed.name !== 'ETHBridgeFinalized' &&
parsed.name !== 'ETHWithdrawalFinalized'
) {
throw new Error('Wrong event name from L1StandardBridge')
}
if (!parsed.args.amount.eq(withdrawAmount)) {
......
......@@ -27,9 +27,10 @@ Our aim is to design a protocol specification that is:
- **Fast:** When users send transactions, they get reliable confirmations with low-latency.
For example when swapping on Uniswap you should see that your transaction succeed in less than 2
seconds.
- **Scalable:** It should be possible to handle an enormous number of transactions per second which
will enable us to charge low fees. V1.0 will enable us to scale up to and even past the gas limit
on L1. Later iterations will scale much further.
- **Scalable:** It should be possible to handle an enormous number of transactions
per second which will enable the system to charge low fees.
V1.0 will enable Optimism to scale up to and even past the gas limit on L1.
Later iterations should scale much further.
- **Modular:** Our designs will use modularity to reduce complexity and enable parallel
contributions. Coming up with good conceptual frameworks & composable atoms of software enables us
to build extremely complex software even when any one person cannot hold that much in their brain.
......@@ -41,8 +42,9 @@ Our aim is to design a protocol specification that is:
our software to avoid creating a system no one wants to use.
- **Clear and Readable:** The specs we write are written to be read. So tight feedback loop with the
systems team consuming the spec is also key!
- **Secure:** This is self-evident. We cannot lose money and in a system where even a bit of
downtime can result in loss of funds this means everything we build must be incredibly secure.
- **Decentralizable:** Everything we build must have a clear path towards decentralization. Today
Optimism relies on OptimismPBC to function, but eventually it will be managed by a DAO and even in
that decentralized future our system must thrive.
- **Secure:** This is self-evident.
User’s assets are at stake. Every component of the system must be incredibly secure.
- **Decentralizable:** Optimism must be designed to avail itself of the security and
censorship-resistant guarantees achieved by a decentralized system.
Currently centralized components of the system should have a clear path towards decentralization.
Already decentralized components of the system should be protected and preserved.
......@@ -48,8 +48,10 @@ Deposited transactions MUST never be consumed from the transaction pool.
## Engine API
<!--
*Note: the [Engine API][l1-api-spec] is in alpha, `v1.0.0-alpha.5`.
There may be subtle tweaks, beta starts in a few weeks*
-->
### `engine_forkchoiceUpdatedV1`
......
......@@ -91,9 +91,11 @@ At the heart of the network are users (us!). Users can:
### Sequencers
The sequencer is the primary block producer. There may be one sequencer **or** many using a consensus protocol. For
1.0.0, there is just one sequencer. In general, specifications may use "the sequencer" to be a stand-in term for the
consensus protocol operated by multiple sequencers.
The sequencer is the primary block producer.
There may be one sequencer **or** many using a consensus protocol.
For 1.0.0, there is just one sequencer (currently operated under the oversight of the Optimism Foundation).
In general, specifications may use "the sequencer" to be a stand-in term
for the consensus protocol operated by multiple sequencers.
The sequencer:
......@@ -125,21 +127,21 @@ provide context when diving into any particular component specification.
### Depositing and Sending Transactions
Users will often begin their L2 journey by depositing ETH from L1. Once they have ETH to pay fees, they'll start
sending transactions on L2. The following diagram demonstrates this interaction and all key Optimism
components which are utilized:
Users will often begin their L2 journey by depositing ETH from L1.
Once they have ETH to pay fees, they'll start sending transactions on L2.
The following diagram demonstrates this interaction and all key Optimism components which are or should be utilized:
![Diagram of Depositing and Sending Transactions](./assets/sequencer-handling-deposits-and-transactions.svg)
Links to components mentioned in this diagram:
- Batch Inbox (WIP)
<!-- - Batch Inbox (WIP) -->
- [Rollup Node](./rollup-node.md)
- [Execution Engine](./exec-engine.md)
- Sequencer Batch Submitter (WIP)
<!-- - Sequencer Batch Submitter (WIP) -->
- [L2 Output Oracle](./proposals.md#l2-output-oracle-smart-contract)
- [L2 Output Submitter](./proposals.md#proposing-l2-output-commitments)
- Fault Proof VM (WIP)
<!-- - Fault Proof VM (WIP) -->
### Withdrawing
......
......@@ -108,12 +108,11 @@ permissionlessly removed from the L2 supply by calling the `burn()` function.
Address: `0x4200000000000000000000000000000000000002`
The `DeployerWhitelist` is a predeploy that was used to provide additional
safety during the initial phases of Optimism. It is owned by the
Optimism foundation and defines the accounts that are allowed to deploy contracts to the
network.
The `DeployerWhitelist` is a predeploy that was used to provide additional safety
during the initial phases of Optimism.
It previously defined the accounts that are allowed to deploy contracts to the network.
Arbitrary contract deployment has been enabled and it is not possible to turn
Arbitrary contract deployment was subsequently enabled and it is not possible to turn
off. In the legacy system, this contract was hooked into `CREATE` and
`CREATE2` to ensure that the deployer was allowlisted.
......@@ -263,9 +262,9 @@ have the ability to upgrade any of the other predeploy contracts.
Address: `0x4200000000000000000000000000000000000011`
The `SequencerFeeVault` accumulates any transaction tips and is the value of
`block.coinbase`. When enough fees accumulate in this account, they can be
permissionlessly withdrawn to an immutable L1 address.
The `SequencerFeeVault` accumulates any transaction priority fee and is the value of
`block.coinbase`.
When enough fees accumulate in this account, they can be withdrawn to an immutable L1 address.
To change the L1 address that fees are withdrawn to, the contract must be
upgraded by changing its proxy's implementation key.
......@@ -300,7 +299,7 @@ Address: `0x4200000000000000000000000000000000000019`
The `BaseFeeVault` predeploy receives the basefees on L2. The basefee is not
burnt on L2 like it is on L1. Once the contract has received a certain amount
of fees, the ETH can be permissionlessly withdrawn to an immutable address on
of fees, the ETH can be withdrawn to an immutable address on
L1.
## L1FeeVault
......@@ -311,4 +310,4 @@ Address: `0x420000000000000000000000000000000000001a`
The `L1FeeVault` predeploy receives the L1 portion of the transaction fees.
Once the contract has received a certain amount of fees, the ETH can be
permissionlessly withdrawn to an immutable address on L1.
withdrawn to an immutable address on L1.
......@@ -26,7 +26,8 @@ proving any piece of data captured by the outputs.
Proposers submit the output roots to L1 and can be contested with a fault proof,
with a bond at stake if the proof is wrong.
_Note_: Although fault proof construction and verification [is implemented in Cannon][cannon],
_Note_: Fault proofs on Optimism are not fully specified at this time. Although fault proof
construction and verification [is implemented in Cannon][cannon],
the fault proof game specification and integration of a output-root challenger into the [rollup-node][g-rollup-node]
are part of later specification milestones.
......@@ -50,7 +51,7 @@ The proposer may also delete multiple output roots by calling the `deleteL2Outpu
index of the first output to delete, this will also delete all subsequent outputs.
> **Note regarding future work:** In the initial version of the system, the proposer will be the same entity as the
> sequencer, which is a trusted role. In the future proposers will need to submit a bond in order to post L2 output
> sequencer, which is a trusted role. In the future proposers may need to submit a bond in order to post L2 output
> roots, and some or all of this bond may be taken in the event of a faulty proposal.
## L2 Output Commitment Construction
......
......@@ -55,8 +55,8 @@ For a complete specification of the L2 block derivation, refer to the [L2 block
## L2 Output RPC method
The Rollup node has its own RPC method, `optimism_outputAtBlock` which returns the
a 32 byte hash corresponding to the [L2 output root](./proposals.md#l2-output-commitment-construction).
The Rollup node has its own RPC method, `optimism_outputAtBlock` which returns a 32
byte hash corresponding to the [L2 output root](./proposals.md#l2-output-commitment-construction).
[SSZ]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md
......
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