Commit 0ad9adbc authored by Liam Horne's avatar Liam Horne Committed by GitHub

Merge pull request #1207 from ethereum-optimism/develop

Merge develop into master
parents dc4bd538 e6151443
---
'@eth-optimism/contracts': patch
---
Add a factory contract we can whitelist for the community phase which will be used by the Gateway to create standard ERC20 tokens on L2
---
'@eth-optimism/batch-submitter': patch
---
Prevent batch submitter from submitting batches if low on ETH
---
'@eth-optimism/message-relayer': patch
---
Adds a new l2 to l1 message relaying utility within the message relayer package
---
'@eth-optimism/integration-tests': patch
---
Make expectApprox more readable by passing optional args as an object with well named keys
---
'@eth-optimism/l2geth': patch
---
Handle errors correctly in the RollupClient and retry in the SyncService when initially attempting to connect to the DTL
---
'@eth-optimism/contracts': patch
---
A small change to the L1 Messenger, which prevents an L2 to L1 call from send calling the CTC.
This diff is collapsed.
......@@ -32,7 +32,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.14.x
go-version: 1.15.x
- name: Checkout code
uses: actions/checkout@v2
......@@ -47,7 +47,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.14.x
go-version: 1.15.x
- name: Checkout code
uses: actions/checkout@v2
......
......@@ -85,7 +85,7 @@ jobs:
yarn compile:ovm
yarn test:integration:ovm
yarn deploy:ovm
# - name: Test l1-l2-deposit-withdrawal example on Optimistic Ethereum with cross-domain message passing
# working-directory: ./examples/l1-l2-deposit-withdrawal
# run: |
......
......@@ -46,7 +46,7 @@ jobs:
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install Dependencies
run: yarn
......
......@@ -55,6 +55,7 @@ jobs:
run: cat packages/contracts/gas-report.txt
- name: Run codechecks
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
working-directory: ./packages/contracts
run: yarn codechecks
env:
......
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn lint:check
yarn lerna run --concurrency 1 --stream pre-commit --since HEAD --exclude-dependents
module.exports = {
"$schema": "http://json.schemastore.org/prettierrc",
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"arrowParens": "always"
};
......@@ -3,6 +3,16 @@
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"editor.formatOnSave": true,
},
"eslint.workingDirectories": [
{"directory": "packages/core-utils", "changeProcessCWD": true },
{"directory": "packages/common-ts", "changeProcessCWD": true },
{"directory": "packages/hardhat-ovm", "changeProcessCWD": true },
{"directory": "packages/smock", "changeProcessCWD": true },
{"directory": "packages/contracts", "changeProcessCWD": true },
{"directory": "packages/data-transport-layer", "changeProcessCWD": true },
{"directory": "packages/batch-submitter", "changeProcessCWD": true },
{"directory": "packages/message-relayer", "changeProcessCWD": true },
],
"eslint.nodePath": "./node_modules/eslint/bin/",
"eslint.format.enable": true,
"editorconfig.generateAuto": false,
......
......@@ -37,6 +37,29 @@ Extensive documentation is available [here](http://community.optimism.io/docs/).
* [`ops`](./ops): Contains Dockerfiles for containerizing each service involved in the protocol,
as well as a docker-compose file for bringing up local testnets easily
## Contributing
Read through [CONTRIBUTING.md](./CONTRIBUTING.md) for a general overview of our contribution process.
### Good First Issues
You can find good first issues by filtering for the ["good first issue" tag on our issues page](https://github.com/ethereum-optimism/optimism/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) or alternatively by taking a look at our [Good First Issues project board](https://github.com/orgs/ethereum-optimism/projects/23).
If you'd like to tackle one of these issues, please leave a comment and [assign yourself to the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/assigning-issues-and-pull-requests-to-other-github-users#assigning-an-individual-issue-or-pull-request).
This helps prevent two people accidentally working on the same task at the same time.
### Changesets
We use [changesets](https://github.com/atlassian/changesets) to manage releases of our various packages.
You *must* include a `changeset` file in your PR when making a change that would require a new package release.
Adding a `changeset` file is easy:
1. Navigate to the root of the monorepo.
2. Run `yarn changeset`. You'll be prompted to select packages to include in the changeset. Use the arrow keys to move the cursor up and down, hit the `spacebar` to select a package, and hit `enter` to confirm your selection. Select *all* packages that require a new release as a result of your PR.
4. Once you hit `enter` you'll be prompted to decide whether your selected packages need a `major`, `minor`, or `patch` release. We follow the [Semantic Versioning](https://semver.org/) scheme. Please avoid using `major` releases for any packages that are still in version `0.y.z`.
5. Commit your changeset and push it into your PR. The changeset bot will notice your changeset file and leave a little comment to this effect on GitHub.
6. Voilà, c'est fini!
## Development Quick Start
### Dependencies
......
module.exports = {
"extends": "../.eslintrc.js"
extends: '../.eslintrc.js',
}
......@@ -7,8 +7,8 @@
"license": "MIT",
"scripts": {
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "prettier --config ./.prettierrc.json --write 'test/**/*.ts'",
"lint:check": "eslint -c .eslintrc.js --ext .ts --format stylish .",
"lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .",
"build:integration": "./scripts/build.sh",
"build:contracts": "hardhat compile",
"build:contracts:ovm": "hardhat compile --network optimism",
......@@ -34,7 +34,9 @@
"chai-as-promised": "^7.1.1",
"docker-compose": "^0.23.8",
"envalid": "^7.1.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
......@@ -48,6 +50,7 @@
"hardhat-gas-reporter": "^1.0.4",
"mocha": "^8.3.1",
"rimraf": "^3.0.2",
"shelljs": "^0.8.4"
"shelljs": "^0.8.4",
"typescript": "^4.2.3"
}
}
......@@ -64,7 +64,8 @@ describe('Syncing a verifier', () => {
})
it('should sync dummy transaction', async () => {
const totalElementsBefore = (await env.ctc.getTotalElements()) as BigNumber
const totalElementsBefore =
(await env.ctc.getTotalElements()) as BigNumber
const tx = {
to: '0x' + '1234'.repeat(10),
......
......@@ -133,9 +133,10 @@ describe('Basic L1<>L2 Communication', async () => {
// This call is fine but will give a status of 0.
const transaction = await env.l1Messenger.sendMessage(
predeploys.Lib_AddressManager,
getContractInterface(
'Lib_AddressManager'
).encodeFunctionData('getAddress', ['whatever']),
getContractInterface('Lib_AddressManager').encodeFunctionData(
'getAddress',
['whatever']
),
5000000
)
......
......@@ -42,8 +42,10 @@ describe('Fee Payment Integration Tests', async () => {
other,
utils.parseEther('0.5')
)
const executionGas = await (env.ovmEth
.provider as any).send('eth_estimateExecutionGas', [tx, true])
const executionGas = await (env.ovmEth.provider as any).send(
'eth_estimateExecutionGas',
[tx, true]
)
const decoded = TxGasLimit.decode(gas)
expect(BigNumber.from(executionGas)).deep.eq(decoded)
})
......
......@@ -118,8 +118,10 @@ describe('Native ETH value integration tests', () => {
'geth RPC does not match OVM_ETH.balanceOf'
)
// query address(this).balance solidity via eth_call as final check
const ovmAddressThisBalance0 = await ValueCalls0.callStatic.getAddressThisBalance()
const ovmAddressThisBalance01 = await ValueCalls1.callStatic.getAddressThisBalance()
const ovmAddressThisBalance0 =
await ValueCalls0.callStatic.getAddressThisBalance()
const ovmAddressThisBalance01 =
await ValueCalls1.callStatic.getAddressThisBalance()
expect(ovmAddressThisBalance0).to.deep.eq(
BigNumber.from(expectedBalances[0]),
'geth RPC does not match address(this).balance'
......@@ -251,23 +253,19 @@ describe('Native ETH value integration tests', () => {
const sendAmount = 10
const [
outerSuccess,
outerReturndata,
] = await ValueCalls0.callStatic.sendWithData(
ValueCalls1.address,
sendAmount,
ValueCalls1.interface.encodeFunctionData('delegateCallToCallValue', [
ValueContext.address,
])
)
const [
innerSuccess,
innerReturndata,
] = ValueCalls1.interface.decodeFunctionResult(
'delegateCallToCallValue',
outerReturndata
)
const [outerSuccess, outerReturndata] =
await ValueCalls0.callStatic.sendWithData(
ValueCalls1.address,
sendAmount,
ValueCalls1.interface.encodeFunctionData('delegateCallToCallValue', [
ValueContext.address,
])
)
const [innerSuccess, innerReturndata] =
ValueCalls1.interface.decodeFunctionResult(
'delegateCallToCallValue',
outerReturndata
)
const delegatedOvmCALLVALUE = ValueContext.interface.decodeFunctionResult(
'getCallValue',
innerReturndata
......@@ -286,48 +284,41 @@ describe('Native ETH value integration tests', () => {
const ValueContext = await Factory__ValueContext.deploy()
await ValueContext.deployTransaction.wait()
const [
delegatedSuccess,
delegatedReturndata,
] = await ValueCalls0.callStatic.delegateCallToAddressThisBalance(
ValueContext.address
)
const [delegatedSuccess, delegatedReturndata] =
await ValueCalls0.callStatic.delegateCallToAddressThisBalance(
ValueContext.address
)
expect(delegatedSuccess).to.be.true
expect(delegatedReturndata).to.deep.eq(BigNumber.from(initialBalance0))
})
it('should have correct address(this).balance through ovmDELEGATECALLs to same account', async () => {
const [
delegatedSuccess,
delegatedReturndata,
] = await ValueCalls0.callStatic.delegateCallToAddressThisBalance(
ValueCalls0.address
)
const [delegatedSuccess, delegatedReturndata] =
await ValueCalls0.callStatic.delegateCallToAddressThisBalance(
ValueCalls0.address
)
expect(delegatedSuccess).to.be.true
expect(delegatedReturndata).to.deep.eq(BigNumber.from(initialBalance0))
})
it('should allow delegate calls which preserve msg.value even with no balance going into the inner call', async () => {
const Factory__SendETHAwayAndDelegateCall: ContractFactory = await ethers.getContractFactory(
'SendETHAwayAndDelegateCall',
wallet
)
const SendETHAwayAndDelegateCall: Contract = await Factory__SendETHAwayAndDelegateCall.deploy()
const Factory__SendETHAwayAndDelegateCall: ContractFactory =
await ethers.getContractFactory('SendETHAwayAndDelegateCall', wallet)
const SendETHAwayAndDelegateCall: Contract =
await Factory__SendETHAwayAndDelegateCall.deploy()
await SendETHAwayAndDelegateCall.deployTransaction.wait()
const value = 17
const [
delegatedSuccess,
delegatedReturndata,
] = await SendETHAwayAndDelegateCall.callStatic.emptySelfAndDelegateCall(
ValueCalls0.address,
ValueCalls0.interface.encodeFunctionData('getCallValue'),
{
value,
}
)
const [delegatedSuccess, delegatedReturndata] =
await SendETHAwayAndDelegateCall.callStatic.emptySelfAndDelegateCall(
ValueCalls0.address,
ValueCalls0.interface.encodeFunctionData('getCallValue'),
{
value,
}
)
expect(delegatedSuccess).to.be.true
expect(delegatedReturndata).to.deep.eq(BigNumber.from(value))
......@@ -343,8 +334,10 @@ describe('Native ETH value integration tests', () => {
getContractInterface('OVM_ExecutionManager', false),
env.l1Wallet.provider
)
const CALL_WITH_VALUE_INTRINSIC_GAS_BIGNUM = await OVM_ExecutionManager.CALL_WITH_VALUE_INTRINSIC_GAS()
CALL_WITH_VALUE_INTRINSIC_GAS = CALL_WITH_VALUE_INTRINSIC_GAS_BIGNUM.toNumber()
const CALL_WITH_VALUE_INTRINSIC_GAS_BIGNUM =
await OVM_ExecutionManager.CALL_WITH_VALUE_INTRINSIC_GAS()
CALL_WITH_VALUE_INTRINSIC_GAS =
CALL_WITH_VALUE_INTRINSIC_GAS_BIGNUM.toNumber()
const Factory__ValueGasMeasurer = await ethers.getContractFactory(
'ValueGasMeasurer',
......@@ -357,14 +350,15 @@ describe('Native ETH value integration tests', () => {
it('a call with value to an empty account consumes <= the intrinsic gas including a buffer', async () => {
const value = 1
const gasLimit = 1_000_000
const minimalSendGas = await ValueGasMeasurer.callStatic.measureGasOfTransferingEthViaCall(
ethers.constants.AddressZero,
value,
gasLimit,
{
gasLimit: 2_000_000,
}
)
const minimalSendGas =
await ValueGasMeasurer.callStatic.measureGasOfTransferingEthViaCall(
ethers.constants.AddressZero,
value,
gasLimit,
{
gasLimit: 2_000_000,
}
)
const buffer = 1.2
expect(minimalSendGas * buffer).to.be.lte(CALL_WITH_VALUE_INTRINSIC_GAS)
......@@ -384,67 +378,61 @@ describe('Native ETH value integration tests', () => {
const value = 1
const gasLimit = 1_000_000
// A revert, causing the ETH to be sent back, should consume the minimal possible gas for a nonzero ETH send
const minimalSendGas = await ValueGasMeasurer.callStatic.measureGasOfTransferingEthViaCall(
AutoRevert.address,
value,
gasLimit,
{
gasLimit: 2_000_000,
}
)
const minimalSendGas =
await ValueGasMeasurer.callStatic.measureGasOfTransferingEthViaCall(
AutoRevert.address,
value,
gasLimit,
{
gasLimit: 2_000_000,
}
)
const buffer = 1.2
expect(minimalSendGas * buffer).to.be.lte(CALL_WITH_VALUE_INTRINSIC_GAS)
})
it('a value call passing less than the intrinsic gas should appear to revert', async () => {
const Factory__PayableConstant: ContractFactory = await ethers.getContractFactory(
'PayableConstant',
wallet
)
const PayableConstant: Contract = await Factory__PayableConstant.deploy()
const Factory__PayableConstant: ContractFactory =
await ethers.getContractFactory('PayableConstant', wallet)
const PayableConstant: Contract =
await Factory__PayableConstant.deploy()
await PayableConstant.deployTransaction.wait()
const sendAmount = 15
const [
success,
returndata,
] = await ValueCalls0.callStatic.sendWithDataAndGas(
PayableConstant.address,
sendAmount,
PayableConstant.interface.encodeFunctionData('returnValue'),
CALL_WITH_VALUE_INTRINSIC_GAS - 1,
{
gasLimit: 2_000_000,
}
)
const [success, returndata] =
await ValueCalls0.callStatic.sendWithDataAndGas(
PayableConstant.address,
sendAmount,
PayableConstant.interface.encodeFunctionData('returnValue'),
CALL_WITH_VALUE_INTRINSIC_GAS - 1,
{
gasLimit: 2_000_000,
}
)
expect(success).to.eq(false)
expect(returndata).to.eq('0x')
})
it('a value call which runs out of gas does not out-of-gas the parent', async () => {
const Factory__TestOOG: ContractFactory = await ethers.getContractFactory(
'TestOOG',
wallet
)
const Factory__TestOOG: ContractFactory =
await ethers.getContractFactory('TestOOG', wallet)
const TestOOG: Contract = await Factory__TestOOG.deploy()
await TestOOG.deployTransaction.wait()
const sendAmount = 15
// Implicitly test that this call is not rejected
const [
success,
returndata,
] = await ValueCalls0.callStatic.sendWithDataAndGas(
TestOOG.address,
sendAmount,
TestOOG.interface.encodeFunctionData('runOutOfGas'),
CALL_WITH_VALUE_INTRINSIC_GAS * 2,
{
gasLimit: 2_000_000,
}
)
const [success, returndata] =
await ValueCalls0.callStatic.sendWithDataAndGas(
TestOOG.address,
sendAmount,
TestOOG.interface.encodeFunctionData('runOutOfGas'),
CALL_WITH_VALUE_INTRINSIC_GAS * 2,
{
gasLimit: 2_000_000,
}
)
expect(success).to.eq(false)
expect(returndata).to.eq('0x')
......
......@@ -57,7 +57,7 @@ describe('Native ETH Integration Tests', async () => {
const addr = '0x' + '1234'.repeat(10)
const gas = await env.ovmEth.estimateGas.transfer(addr, amount)
// Expect gas to be less than or equal to the target plus 1%
expectApprox(gas, 6430020, 1)
expectApprox(gas, 6430020, { upperPercentDeviation: 1 })
})
it('Should estimate gas for ETH withdraw', async () => {
......@@ -69,7 +69,7 @@ describe('Native ETH Integration Tests', async () => {
'0xFFFF'
)
// Expect gas to be less than or equal to the target plus 1%
expectApprox(gas, 6700060, 1)
expectApprox(gas, 6700060, { upperPercentDeviation: 1 })
})
})
......@@ -325,12 +325,8 @@ describe('Native ETH Integration Tests', async () => {
expect(receipt.events.length).to.equal(4)
// The first transfer event is fee payment
const [
,
firstTransferEvent,
secondTransferEvent,
depositEvent,
] = receipt.events
const [, firstTransferEvent, secondTransferEvent, depositEvent] =
receipt.events
expect(firstTransferEvent.event).to.equal('Transfer')
expect(firstTransferEvent.args.from).to.equal(env.l2Wallet.address)
......
......@@ -49,9 +49,8 @@ describe('OVM Context: Layer 2 EVM Context', () => {
'OVM_CanonicalTransactionChain'
)
CanonicalTransactionChain = CanonicalTransactionChainFactory.connect(
l1Wallet
).attach(ctcAddress)
CanonicalTransactionChain =
CanonicalTransactionChainFactory.connect(l1Wallet).attach(ctcAddress)
const OVMMulticallFactory = await ethers.getContractFactory(
'OVMMulticall',
......
......@@ -208,10 +208,8 @@ describe('Basic RPC tests', () => {
it('should allow eth_calls with nonzero value', async () => {
// Deploy a contract to check msg.value of the call
const Factory__ValueContext: ContractFactory = await ethers.getContractFactory(
'ValueContext',
wallet
)
const Factory__ValueContext: ContractFactory =
await ethers.getContractFactory('ValueContext', wallet)
const ValueContext: Contract = await Factory__ValueContext.deploy()
await ValueContext.deployTransaction.wait()
......@@ -378,7 +376,7 @@ describe('Basic RPC tests', () => {
value: 0,
})
// Expect gas to be less than or equal to the target plus 1%
expectApprox(estimate, 5920012, 1)
expectApprox(estimate, 5920012, { upperPercentDeviation: 1 })
})
it('should return a gas estimate that grows with the size of data', async () => {
......@@ -429,12 +427,12 @@ describe('Basic RPC tests', () => {
describe('rollup_gasPrices', () => {
it('should return the L1 and L2 gas prices', async () => {
const result = await provider.send('rollup_gasPrices', []);
const result = await provider.send('rollup_gasPrices', [])
const l1GasPrice = await env.l1Wallet.provider.getGasPrice()
const l2GasPrice = await env.gasPriceOracle.gasPrice()
expect(BigNumber.from(result.l1GasPrice)).to.deep.eq(l1GasPrice)
expect((BigNumber.from(result.l2GasPrice))).to.deep.eq(l2GasPrice)
expect(BigNumber.from(result.l2GasPrice)).to.deep.eq(l2GasPrice)
})
})
})
const { DockerComposeNetwork } = require("./shared/docker-compose")
const { DockerComposeNetwork } = require('./shared/docker-compose')
before(async () => {
if (!process.env.NO_NETWORK) {
......
......@@ -142,35 +142,39 @@ export const DEFAULT_TRANSACTION = {
value: 0,
}
interface percentDeviationRange {
upperPercentDeviation: number
lowerPercentDeviation?: number
}
export const expectApprox = (
actual: BigNumber | number,
target: BigNumber | number,
upperDeviation: number,
lowerDeviation: number = 100
{ upperPercentDeviation, lowerPercentDeviation = 100 }: percentDeviationRange
) => {
actual = BigNumber.from(actual)
target = BigNumber.from(target)
const validDeviations =
upperDeviation >= 0 &&
upperDeviation <= 100 &&
lowerDeviation >= 0 &&
lowerDeviation <= 100
upperPercentDeviation >= 0 &&
upperPercentDeviation <= 100 &&
lowerPercentDeviation >= 0 &&
lowerPercentDeviation <= 100
if (!validDeviations) {
throw new Error(
'Upper and lower deviation percentage arguments should be between 0 and 100'
)
}
const upper = target.mul(100 + upperDeviation).div(100)
const lower = target.mul(100 - lowerDeviation).div(100)
const upper = target.mul(100 + upperPercentDeviation).div(100)
const lower = target.mul(100 - lowerPercentDeviation).div(100)
expect(
actual.lte(upper),
`Actual value is more than ${upperDeviation}% greater than target`
`Actual value is more than ${upperPercentDeviation}% greater than target`
).to.be.true
expect(
actual.gte(lower),
`Actual value is more than ${lowerDeviation}% less than target`
`Actual value is more than ${lowerPercentDeviation}% less than target`
).to.be.true
}
......
......@@ -24,6 +24,10 @@ const (
// found. It applies to transactions, queue elements and batches
var errElementNotFound = errors.New("element not found")
// errHttpError represents the error case of when the remote server
// returns a 400 or greater error
var errHTTPError = errors.New("http error")
// Batch represents the data structure that is submitted with
// a series of transactions to layer one
type Batch struct {
......@@ -154,6 +158,15 @@ func NewClient(url string, chainID *big.Int) *Client {
client := resty.New()
client.SetHostURL(url)
client.SetHeader("User-Agent", "sequencer")
client.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
statusCode := r.StatusCode()
if statusCode >= 400 {
method := r.Request.Method
url := r.Request.URL
return fmt.Errorf("%d cannot %s %s: %w", statusCode, method, url, errHTTPError)
}
return nil
})
signer := types.NewEIP155Signer(chainID)
return &Client{
......
package rollup
import (
"errors"
"fmt"
"math/big"
"testing"
......@@ -8,8 +9,9 @@ import (
"github.com/jarcoal/httpmock"
)
const url = "http://localhost:9999"
func TestRollupClientGetL1GasPrice(t *testing.T) {
url := "http://localhost:9999"
endpoint := fmt.Sprintf("%s/eth/gasprice", url)
// url/chain-id does not matter, we'll mock the responses
client := NewClient(url, big.NewInt(1))
......@@ -41,3 +43,28 @@ func TestRollupClientGetL1GasPrice(t *testing.T) {
t.Fatal("gasPrice is not parsed properly in the client")
}
}
func TestRollupClientCannotConnect(t *testing.T) {
endpoint := fmt.Sprintf("%s/eth/context/latest", url)
client := NewClient(url, big.NewInt(1))
httpmock.ActivateNonDefault(client.client.GetClient())
response, _ := httpmock.NewJsonResponder(
400,
map[string]interface{}{},
)
httpmock.RegisterResponder(
"GET",
endpoint,
response,
)
context, err := client.GetLatestEthContext()
if context != nil {
t.Fatal("returned value is not nil")
}
if !errors.Is(err, errHTTPError) {
t.Fatalf("Incorrect error returned: %s", err)
}
}
......@@ -128,22 +128,29 @@ func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *co
// requirement of the remote server being up.
if service.enable {
// Ensure that the rollup client can connect to a remote server
// before starting.
err := service.ensureClient()
if err != nil {
return nil, fmt.Errorf("Rollup client unable to connect: %w", err)
// before starting. Retry until it can connect.
tEnsure := time.NewTicker(10 * time.Second)
for ; true; <-tEnsure.C {
err := service.ensureClient()
if err != nil {
log.Info("Cannot connect to upstream service", "msg", err)
} else {
log.Info("Connected to upstream service")
tEnsure.Stop()
break
}
}
// Wait until the remote service is done syncing
t := time.NewTicker(10 * time.Second)
for ; true; <-t.C {
tStatus := time.NewTicker(10 * time.Second)
for ; true; <-tStatus.C {
status, err := service.client.SyncStatus(service.backend)
if err != nil {
log.Error("Cannot get sync status")
continue
}
if !status.Syncing {
t.Stop()
tStatus.Stop()
break
}
log.Info("Still syncing", "index", status.CurrentTransactionIndex, "tip", status.HighestKnownTransactionIndex)
......@@ -153,7 +160,7 @@ func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *co
// it happens before the RPC endpoints open up
// Only do it if the sync service is enabled so that this
// can be ran without needing to have a configured RollupClient.
err = service.initializeLatestL1(cfg.CanonicalTransactionChainDeployHeight)
err := service.initializeLatestL1(cfg.CanonicalTransactionChainDeployHeight)
if err != nil {
return nil, fmt.Errorf("Cannot initialize latest L1 data: %w", err)
}
......
# Build Geth in a stock Go builder container
FROM golang:1.15-alpine as builder
FROM golang:1.15-alpine3.13 as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git
......@@ -7,7 +7,7 @@ ADD ./l2geth /go-ethereum
RUN cd /go-ethereum && make geth
# Pull Geth into a second stage deploy alpine container
FROM alpine:latest
FROM alpine:3.13
RUN apk add --no-cache ca-certificates jq curl
COPY --from=builder /go-ethereum/build/bin/geth /usr/local/bin/
......
module.exports = {
"extends": "../../.eslintrc.js"
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
../../.prettierrc.json
\ No newline at end of file
#!/usr/bin/env node
const batchSubmitter = require("../dist/src/exec/run-batch-submitter")
const batchSubmitter = require('../dist/src/exec/run-batch-submitter')
batchSubmitter.run()
......@@ -13,8 +13,9 @@
"build": "tsc -p ./tsconfig.build.json",
"clean": "rimraf cache/ dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "prettier --config .prettierrc.json --write \"hardhat.config.ts\" \"{src,exec,test}/**/*.ts\"",
"lint:check": "eslint -c .eslintrc.js --ext .ts --format stylish .",
"pre-commit": "lint-staged",
"lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .",
"test": "hardhat test --show-stack-traces"
},
"keywords": [
......@@ -60,7 +61,9 @@
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"chai": "^4.2.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
......@@ -73,6 +76,7 @@
"hardhat": "^2.2.1",
"mocha": "^6.1.4",
"prettier": "^2.2.1",
"lint-staged": "11.0.0",
"rimraf": "^2.6.3",
"sinon": "^9.2.4",
"sinon-chai": "^3.5.0",
......
......@@ -3,11 +3,11 @@ import { Contract, Signer, utils, providers } from 'ethers'
import { TransactionReceipt } from '@ethersproject/abstract-provider'
import { Gauge, Histogram, Counter } from 'prom-client'
import * as ynatm from '@eth-optimism/ynatm'
import { RollupInfo } from '@eth-optimism/core-utils'
import { RollupInfo, sleep } from '@eth-optimism/core-utils'
import { Logger, Metrics } from '@eth-optimism/common-ts'
import { getContractFactory } from 'old-contracts'
export interface Range {
export interface BlockRange {
start: number
end: number
}
......@@ -65,7 +65,7 @@ export abstract class BatchSubmitter {
endBlock: number
): Promise<TransactionReceipt>
public abstract _onSync(): Promise<TransactionReceipt>
public abstract _getBatchStartAndEnd(): Promise<Range>
public abstract _getBatchStartAndEnd(): Promise<BlockRange>
public abstract _updateChainInfo(): Promise<void>
public async submitNextBatch(): Promise<TransactionReceipt> {
......@@ -73,7 +73,11 @@ export abstract class BatchSubmitter {
this.l2ChainId = await this._getL2ChainId()
}
await this._updateChainInfo()
await this._checkBalance()
if (!(await this._hasEnoughETHToCoverGasCosts())) {
await sleep(this.resubmissionTimeout)
return
}
this.logger.info('Readying to submit next batch...', {
l2ChainId: this.l2ChainId,
......@@ -94,7 +98,7 @@ export abstract class BatchSubmitter {
return this._submitBatch(range.start, range.end)
}
protected async _checkBalance(): Promise<void> {
protected async _hasEnoughETHToCoverGasCosts(): Promise<boolean> {
const address = await this.signer.getAddress()
const balance = await this.signer.getBalance()
const ether = utils.formatEther(balance)
......@@ -104,6 +108,7 @@ export abstract class BatchSubmitter {
address,
ether,
})
this.metrics.batchSubmitterETHBalance.set(num)
if (num < this.minBalanceEther) {
......@@ -111,7 +116,10 @@ export abstract class BatchSubmitter {
current: num,
safeBalance: this.minBalanceEther,
})
return false
}
return true
}
protected async _getRollupInfo(): Promise<RollupInfo> {
......
......@@ -12,7 +12,7 @@ import {
import { Logger, Metrics } from '@eth-optimism/common-ts'
/* Internal Imports */
import { Range, BatchSubmitter } from '.'
import { BlockRange, BatchSubmitter } from '.'
export class StateBatchSubmitter extends BatchSubmitter {
// TODO: Change this so that we calculate start = scc.totalElements() and end = ctc.totalElements()!
......@@ -116,7 +116,7 @@ export class StateBatchSubmitter extends BatchSubmitter {
return
}
public async _getBatchStartAndEnd(): Promise<Range> {
public async _getBatchStartAndEnd(): Promise<BlockRange> {
this.logger.info('Getting batch start and end for state batch submitter...')
const startBlock: number =
(await this.chainContract.getTotalElements()).toNumber() +
......
......@@ -21,7 +21,7 @@ import {
AppendSequencerBatchParams,
} from '../transaction-chain-contract'
import { Range, BatchSubmitter } from '.'
import { BlockRange, BatchSubmitter } from '.'
export interface AutoFixBatchOptions {
fixDoublePlayedDeposits: boolean
......@@ -127,7 +127,8 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
}
public async _onSync(): Promise<TransactionReceipt> {
const pendingQueueElements = await this.chainContract.getNumPendingQueueElements()
const pendingQueueElements =
await this.chainContract.getNumPendingQueueElements()
this.logger.debug('Got number of pending queue elements', {
pendingQueueElements,
})
......@@ -173,7 +174,7 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return
}
public async _getBatchStartAndEnd(): Promise<Range> {
public async _getBatchStartAndEnd(): Promise<BlockRange> {
this.logger.info(
'Getting batch start and end for transaction batch submitter...'
)
......@@ -228,10 +229,8 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
return
}
const [
batchParams,
wasBatchTruncated,
] = await this._generateSequencerBatchParams(startBlock, endBlock)
const [batchParams, wasBatchTruncated] =
await this._generateSequencerBatchParams(startBlock, endBlock)
const batchSizeInBytes = encodeAppendSequencerBatch(batchParams).length / 2
this.logger.debug('Sequencer batch generated', {
batchSizeInBytes,
......@@ -390,11 +389,8 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
}
let isEqual = true
const [
queueEleHash,
timestamp,
blockNumber,
] = await this.chainContract.getQueueElement(queueIndex)
const [queueEleHash, timestamp, blockNumber] =
await this.chainContract.getQueueElement(queueIndex)
// TODO: Verify queue element hash equality. The queue element hash can be computed with:
// keccak256( abi.encode( msg.sender, _target, _gasLimit, _data))
......@@ -458,19 +454,18 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
for (const ele of b) {
// Look for skipped deposits
while (true) {
const pendingQueueElements = await this.chainContract.getNumPendingQueueElements()
const nextRemoteQueueElements = await this.chainContract.getNextQueueIndex()
const pendingQueueElements =
await this.chainContract.getNumPendingQueueElements()
const nextRemoteQueueElements =
await this.chainContract.getNextQueueIndex()
const totalQueueElements =
pendingQueueElements + nextRemoteQueueElements
// No more queue elements so we clearly haven't skipped anything
if (nextQueueIndex >= totalQueueElements) {
break
}
const [
queueEleHash,
timestamp,
blockNumber,
] = await this.chainContract.getQueueElement(nextQueueIndex)
const [queueEleHash, timestamp, blockNumber] =
await this.chainContract.getQueueElement(nextQueueIndex)
if (timestamp < ele.timestamp || blockNumber < ele.blockNumber) {
this.logger.warn('Fixing skipped deposit', {
......@@ -506,10 +501,8 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
const fixMonotonicity = async (b: Batch): Promise<Batch> => {
this.logger.debug('Fixing monotonicity...')
// The earliest allowed timestamp/blockNumber is the last timestamp submitted on chain.
const {
lastTimestamp,
lastBlockNumber,
} = await this._getLastTimestampAndBlockNumber()
const { lastTimestamp, lastBlockNumber } =
await this._getLastTimestampAndBlockNumber()
let earliestTimestamp = lastTimestamp
let earliestBlockNumber = lastBlockNumber
this.logger.debug('Determined earliest timestamp and blockNumber', {
......@@ -525,16 +518,15 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
// updateLatestTimestampAndBlockNumber is a helper which updates
// the latest timestamp and block number based on the pending queue elements.
const updateLatestTimestampAndBlockNumber = async () => {
const pendingQueueElements = await this.chainContract.getNumPendingQueueElements()
const nextRemoteQueueElements = await this.chainContract.getNextQueueIndex()
const pendingQueueElements =
await this.chainContract.getNumPendingQueueElements()
const nextRemoteQueueElements =
await this.chainContract.getNextQueueIndex()
const totalQueueElements =
pendingQueueElements + nextRemoteQueueElements
if (nextQueueIndex < totalQueueElements) {
const [
queueEleHash,
queueTimestamp,
queueBlockNumber,
] = await this.chainContract.getQueueElement(nextQueueIndex)
const [queueEleHash, queueTimestamp, queueBlockNumber] =
await this.chainContract.getQueueElement(nextQueueIndex)
latestTimestamp = queueTimestamp
latestBlockNumber = queueBlockNumber
} else {
......@@ -652,11 +644,8 @@ export class TransactionBatchSubmitter extends BatchSubmitter {
queueIndex: number,
queueElement: BatchElement
): Promise<BatchElement> {
const [
queueEleHash,
timestamp,
blockNumber,
] = await this.chainContract.getQueueElement(queueIndex)
const [queueEleHash, timestamp, blockNumber] =
await this.chainContract.getQueueElement(queueIndex)
if (
timestamp > queueElement.timestamp &&
......
......@@ -152,10 +152,11 @@ describe('BatchSubmitter', () => {
let OVM_StateCommitmentChain: Contract
let l2Provider: MockchainProvider
beforeEach(async () => {
const unwrapped_OVM_CanonicalTransactionChain = await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS
)
const unwrapped_OVM_CanonicalTransactionChain =
await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS
)
await unwrapped_OVM_CanonicalTransactionChain.init()
await AddressManager.setAddress(
......@@ -169,11 +170,12 @@ describe('BatchSubmitter', () => {
sequencer
)
const unwrapped_OVM_StateCommitmentChain = await Factory__OVM_StateCommitmentChain.deploy(
AddressManager.address,
0, // fraudProofWindowSeconds
0 // sequencerPublishWindowSeconds
)
const unwrapped_OVM_StateCommitmentChain =
await Factory__OVM_StateCommitmentChain.deploy(
AddressManager.address,
0, // fraudProofWindowSeconds
0 // sequencerPublishWindowSeconds
)
await unwrapped_OVM_StateCommitmentChain.init()
......
......@@ -4,4 +4,3 @@
"resolveJsonModule": true
}
}
\ No newline at end of file
module.exports = {
"extends": "../../.eslintrc.js"
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
../../.prettierrc.json
\ No newline at end of file
......@@ -12,9 +12,10 @@
"all": "yarn clean && yarn build && yarn test && yarn lint:fix && yarn lint",
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint:check": "eslint .",
"lint:fix": "yarn lint:check --fix",
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "prettier --config .prettierrc.json --write '{src,test}/**/*.ts'",
"lint:check": "eslint -c .eslintrc.js --ext .ts --format stylish .",
"pre-commit": "lint-staged",
"test": "ts-mocha test/*.spec.ts"
},
"devDependencies": {
......@@ -27,7 +28,9 @@
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"chai": "^4.3.4",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
......
......@@ -23,8 +23,8 @@ export class BaseService<T> {
protected options: T
protected logger: Logger
protected metrics: Metrics
protected initialized: boolean = false
protected running: boolean = false
protected initialized = false
protected running = false
constructor(
name: string,
......
module.exports = {
"extends": "../../.eslintrc.js",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
}
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
../../.prettierrc.json
\ No newline at end of file
......@@ -31,7 +31,10 @@ const parseEnv = () => {
return {
l1BlockTimeSeconds: ensure('BLOCK_TIME_SECONDS', 'number'),
ctcForceInclusionPeriodSeconds: ensure('FORCE_INCLUSION_PERIOD_SECONDS', 'number'),
ctcForceInclusionPeriodSeconds: ensure(
'FORCE_INCLUSION_PERIOD_SECONDS',
'number'
),
ctcMaxTransactionGasLimit: ensure('MAX_TRANSACTION_GAS_LIMIT', 'number'),
emMinTransactionGasLimit: ensure('MIN_TRANSACTION_GAS_LIMIT', 'number'),
emMaxtransactionGasLimit: ensure('MAX_TRANSACTION_GAS_LIMIT', 'number'),
......@@ -39,7 +42,10 @@ const parseEnv = () => {
emSecondsPerEpoch: ensure('ECONDS_PER_EPOCH', 'number'),
emOvmChainId: ensure('CHAIN_ID', 'number'),
sccFraudProofWindow: ensure('FRAUD_PROOF_WINDOW_SECONDS', 'number'),
sccSequencerPublishWindow: ensure('SEQUENCER_PUBLISH_WINDOW_SECONDS', 'number'),
sccSequencerPublishWindow: ensure(
'SEQUENCER_PUBLISH_WINDOW_SECONDS',
'number'
),
}
}
......@@ -68,27 +74,33 @@ const main = async () => {
// update our CI so this is no longer necessary. But I'm adding it for backwards compat so we can
// get the hardhat-deploy stuff merged. Woot.
const nicknames = {
'Lib_AddressManager': 'AddressManager',
'mockOVM_BondManager': 'OVM_BondManager'
Lib_AddressManager: 'AddressManager',
mockOVM_BondManager: 'OVM_BondManager',
}
const contracts: any = dirtree(
path.resolve(__dirname, `../deployments/custom`)
).children.filter((child) => {
return child.extension === '.json'
}).reduce((contractsAccumulator, child) => {
const contractName = child.name.replace('.json', '')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const artifact = require(path.resolve(__dirname, `../deployments/custom/${child.name}`))
contractsAccumulator[nicknames[contractName] || contractName] = artifact.address
return contractsAccumulator
}, {})
)
.children.filter((child) => {
return child.extension === '.json'
})
.reduce((contractsAccumulator, child) => {
const contractName = child.name.replace('.json', '')
// eslint-disable-next-line @typescript-eslint/no-var-requires
const artifact = require(path.resolve(
__dirname,
`../deployments/custom/${child.name}`
))
contractsAccumulator[nicknames[contractName] || contractName] =
artifact.address
return contractsAccumulator
}, {})
contracts.OVM_Sequencer = await sequencer.getAddress()
contracts.Deployer = await deployer.getAddress()
const addresses = JSON.stringify(contracts, null, 2)
const dumpsPath = path.resolve(__dirname, "../dist/dumps")
const dumpsPath = path.resolve(__dirname, '../dist/dumps')
if (!fs.existsSync(dumpsPath)) {
fs.mkdirSync(dumpsPath)
}
......
......@@ -5,7 +5,8 @@ import * as mkdirp from 'mkdirp'
const env = process.env
const CHAIN_ID = env.CHAIN_ID || '420'
const GAS_PRICE_ORACLE_OWNER = env.GAS_PRICE_ORACLE_OWNER || '0x' + 'FF'.repeat(20)
const GAS_PRICE_ORACLE_OWNER =
env.GAS_PRICE_ORACLE_OWNER || '0x' + 'FF'.repeat(20)
/* Internal Imports */
import { makeStateDump } from '../src/state-dump/make-dump'
......@@ -22,7 +23,7 @@ import { RollupDeployConfig } from '../src/contract-deployment'
gasPriceOracleConfig: {
owner: GAS_PRICE_ORACLE_OWNER,
initialGasPrice: 0,
}
},
}
const dump = await makeStateDump(config as RollupDeployConfig)
......
......@@ -252,6 +252,11 @@ contract OVM_L1CrossDomainMessenger is
"Provided message has been blocked."
);
require(
_target != resolve("OVM_CanonicalTransactionChain"),
"Cannot send L2->L1 messages to L1 system contracts."
);
xDomainMsgSender = _sender;
(bool success, ) = _target.call(_message);
xDomainMsgSender = DEFAULT_XDOMAIN_SENDER;
......
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Contract Imports */
import { L2StandardERC20 } from "../../../libraries/standards/L2StandardERC20.sol";
import { Lib_PredeployAddresses } from "../../../libraries/constants/Lib_PredeployAddresses.sol";
/**
* @title OVM_L2StandardTokenFactory
* @dev Factory contract for creating standard L2 token representations of L1 ERC20s
* compatible with and working on the standard bridge.
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract OVM_L2StandardTokenFactory {
event StandardL2TokenCreated(address indexed _l1Token, address indexed _l2Token);
/**
* @dev Creates an instance of the standard ERC20 token on L2.
* @param _l1Token Address of the corresponding L1 token.
* @param _name ERC20 name.
* @param _symbol ERC20 symbol.
*/
function createStandardL2Token(
address _l1Token,
string memory _name,
string memory _symbol
)
external
{
require (_l1Token != address(0), "Must provide L1 token address");
L2StandardERC20 l2Token = new L2StandardERC20(
Lib_PredeployAddresses.L2_STANDARD_BRIDGE,
_l1Token,
_name,
_symbol
);
emit StandardL2TokenCreated(_l1Token, address(l2Token));
}
}
......@@ -10,6 +10,7 @@ contract L2StandardERC20 is IL2StandardERC20, ERC20 {
address public l2Bridge;
/**
* @param _l2Bridge Address of the L2 standard bridge.
* @param _l1Token Address of the corresponding L1 token.
* @param _name ERC20 name.
* @param _symbol ERC20 symbol.
......
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
/* Imports: Internal */
import { getContractDefinition } from '../src'
const deployFn: DeployFunction = async (hre: any) => {
const { deployments, getNamedAccounts } = hre
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
const l2TokenFactory = getContractDefinition('OVM_L2StandardTokenFactory', true)
await deploy('OVM_L2StandardTokenFactory', {
contract: l2TokenFactory,
args: [],
from: deployer,
log: true,
});
}
deployFn.tags = ['OVM_L2StandardTokenFactory']
export default deployFn
......@@ -38,7 +38,8 @@ const deployFn: DeployFunction = async (hre) => {
await Proxy__OVM_L1CrossDomainMessenger.initialize(Lib_AddressManager.address)
const libAddressManager = await Proxy__OVM_L1CrossDomainMessenger.libAddressManager()
const libAddressManager =
await Proxy__OVM_L1CrossDomainMessenger.libAddressManager()
if (libAddressManager !== Lib_AddressManager.address) {
throw new Error(
`\n**FATAL ERROR. THIS SHOULD NEVER HAPPEN. CHECK YOUR DEPLOYMENT.**:\n` +
......
......@@ -65,7 +65,8 @@ const deployFn: DeployFunction = async (hre) => {
hre.ethers.utils.hexZeroPad(l1MessengerAddress, 32)
)
// Verify that the slot was set correctly
const l1MessengerStored = await Proxy__WithBridgeInterface.callStatic.messenger()
const l1MessengerStored =
await Proxy__WithBridgeInterface.callStatic.messenger()
console.log('l1MessengerStored:', l1MessengerStored)
if (l1MessengerStored !== l1MessengerAddress) {
throw new Error(
......@@ -79,7 +80,8 @@ const deployFn: DeployFunction = async (hre) => {
hre.ethers.utils.hexZeroPad(predeploys.OVM_L2StandardBridge, 32)
)
// Verify that the slot was set correctly
const l2TokenBridgeStored = await Proxy__WithBridgeInterface.callStatic.l2TokenBridge()
const l2TokenBridgeStored =
await Proxy__WithBridgeInterface.callStatic.l2TokenBridge()
console.log('l2TokenBridgeStored:', l2TokenBridgeStored)
if (l2TokenBridgeStored !== predeploys.OVM_L2StandardBridge) {
throw new Error(
......
......@@ -19,6 +19,7 @@
| OVM_ECDSAContractAccount: | `0x4200000000000000000000000000000000000003` |
| OVM_SequencerEntrypoint: | `0x4200000000000000000000000000000000000005` |
| Lib_AddressManager: | `0x4200000000000000000000000000000000000008` |
| OVM_SequencerFeeVault: | `0x4200000000000000000000000000000000000011` |
| ERC1820Registry: | `0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24` |
---
......@@ -65,8 +66,8 @@ Implementation addresses. DO NOT use these addresses directly.
Use their proxied counterparts seen above.
OVM_L1CrossDomainMessenger:
- 0x16393737D09d2722AD13DcA3cA8C3DB957699F1D
- https://etherscan.io/address/0x16393737D09d2722AD13DcA3cA8C3DB957699F1D
- 0xbfba066b5cA610Fe70AdCE45FcB622F945891bb0
- https://etherscan.io/address/0xbfba066b5cA610Fe70AdCE45FcB622F945891bb0)
OVM_L1ETHGateway:
- 0x40c9067ec8087EcF101FC10d2673636955b81A32
......@@ -99,8 +100,8 @@ Implementation addresses. DO NOT use these addresses directly.
Use their proxied counterparts seen above.
OVM_L1CrossDomainMessenger:
- 0xa172330C2E6Ec2bF04662Bb9b67ae857910b7f7f
- https://kovan.etherscan.io/address/0xa172330C2E6Ec2bF04662Bb9b67ae857910b7f7f)
- 0x333d2674E2D7e1e7327dc076030ce9615183709C
- https://kovan.etherscan.io/address/0x333d2674E2D7e1e7327dc076030ce9615183709C)
OVM_L1StandardBridge:
- 0x8293ab0dc701a1387031a13786276f1baa3fcd4e
- https://kovan.etherscan.io/address/0x8293ab0dc701a1387031a13786276f1baa3fcd4e)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -35,11 +35,8 @@
"test:slither": "slither .",
"pretest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat && ln -s ../../node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/@ens @ens && ln -s ../../node_modules/hardhat hardhat",
"posttest:slither": "rm -f @openzeppelin && rm -f @ens && rm -f hardhat",
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "yarn run lint:fix:typescript",
"lint:fix:typescript": "prettier --config .prettierrc.json --write \"hardhat.config.ts\" \"{src,test,deploy}/**/*.ts\"",
"lint:check": "yarn run lint:typescript",
"lint:typescript": "eslint -c .eslintrc.js --ext .ts --format stylish .",
"lint:check": "eslint .",
"lint:fix": "yarn lint:check --fix",
"clean": "rm -rf ./dist ./artifacts ./artifacts-ovm ./cache ./cache-ovm ./tsconfig.build.tsbuildinfo",
"deploy": "ts-node \"./bin/deploy.ts\" && yarn generate-markdown",
"serve": "./bin/serve_dump.sh",
......@@ -47,7 +44,8 @@
"postpublish": "rimraf OVM iOVM libraries mockOVM",
"prepack": "yarn prepublishOnly",
"postpack": "yarn postpublish",
"generate-markdown": "node \"./scripts/generate-markdown.js\""
"generate-markdown": "node \"./scripts/generate-markdown.js\"",
"pre-commit": "lint-staged"
},
"dependencies": {
"@eth-optimism/core-utils": "^0.4.6",
......@@ -82,7 +80,9 @@
"copyfiles": "^2.3.0",
"directory-tree": "^2.2.7",
"dotenv": "^8.2.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
......@@ -102,11 +102,13 @@
"mkdirp": "^1.0.4",
"mocha": "^8.3.0",
"prettier": "^2.2.1",
"lint-staged": "11.0.0",
"random-bytes-seed": "^1.0.3",
"rlp": "^2.2.6",
"solidity-coverage": "^0.7.16",
"ts-generator": "0.0.8",
"ts-node": "^9.1.1",
"typescript": "^4.2.3",
"typechain": "2.0.0",
"yargs": "^16.2.0"
},
......
......@@ -34,8 +34,8 @@ const argv = yargs(hideBin(process.argv)).argv
for (const name of Object.keys(addresses)) {
if (addresses[name] !== ethers.constants.AddressZero) {
table.push({
name: name,
address: addresses[name]
name,
address: addresses[name],
})
}
}
......
......@@ -77,10 +77,10 @@ const networks = {
proxiedContracts = []
for (let i = 0; i < contracts.length; i++) {
if (contracts[i] == 'OVM_L1CrossDomainMessenger') {
if (contracts[i] === 'OVM_L1CrossDomainMessenger') {
proxiedContracts.push(contracts.splice(i, 1)[0])
}
if (contracts[i] == 'OVM_L1ETHGateway') {
if (contracts[i] === 'OVM_L1ETHGateway') {
proxiedContracts.push(contracts.splice(i, 1)[0])
}
}
......
......@@ -6,7 +6,7 @@ const { hideBin } = require('yargs/helpers')
const argv = yargs(hideBin(process.argv)).argv
const nicknames = {
'mockOVM_BondManager': 'OVM_BondManager'
mockOVM_BondManager: 'OVM_BondManager',
}
;(async () => {
......@@ -27,17 +27,21 @@ const nicknames = {
throw new Error(`unable to get a reference to Lib_AddressManager`)
}
const contracts = dirtree(`./deployments/${argv.network}`).children.filter((child) => {
return child.extension === '.json'
}).map((child) => {
return child.name.replace('.json', '')
})
const contracts = dirtree(`./deployments/${argv.network}`)
.children.filter((child) => {
return child.extension === '.json'
})
.map((child) => {
return child.name.replace('.json', '')
})
for (const contract of contracts) {
const deployment = require(`../deployments/${argv.network}/${contract}.json`)
if (contract !== 'Lib_AddressManager') {
const address = await Lib_AddressManager.getAddress(nicknames[contract] || contract)
const address = await Lib_AddressManager.getAddress(
nicknames[contract] || contract
)
if (address !== deployment.address) {
console.log(`✖ ${contract} (ADDRESS MISMATCH DETECTED)`)
continue
......
......@@ -189,8 +189,10 @@ export const makeStateDump = async (cfg: RollupDeployConfig): Promise<any> => {
const contract = deploymentResult.contracts[name]
let code: string
if (ovmCompiled.includes(name)) {
const ovmDeployedBytecode = getContractDefinition(name, true)
.deployedBytecode
const ovmDeployedBytecode = getContractDefinition(
name,
true
).deployedBytecode
// TODO remove: deployedBytecode is missing the find and replace in solidity
code = ovmDeployedBytecode
.split(
......
......@@ -197,7 +197,9 @@ describe('OVM_L2StandardBridge', () => {
let SmoddedL2Token: ModifiableContract
beforeEach(async () => {
// Deploy a smodded gateway so we can give some balances to withdraw
SmoddedL2Token = await (await smoddit('L2StandardERC20', alice)).deploy(
SmoddedL2Token = await (
await smoddit('L2StandardERC20', alice)
).deploy(
OVM_L2StandardBridge.address,
DUMMY_L1TOKEN_ADDRESS,
'L2Token',
......
import { expect } from '../../../../setup'
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smoddit } from '@eth-optimism/smock'
import { getContractInterface } from '@eth-optimism/contracts'
/* Internal Imports */
import { predeploys } from '../../../../../src'
describe('OVM_L2StandardTokenFactory', () => {
let signer: Signer
let Factory__L1ERC20: ContractFactory
let L1ERC20: Contract
let OVM_L2StandardTokenFactory: Contract
before(async () => {
;[signer] = await ethers.getSigners()
// deploy an ERC20 contract on L1
Factory__L1ERC20 = await smoddit(
'@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20'
)
L1ERC20 = await Factory__L1ERC20.deploy('L1ERC20', 'ERC')
OVM_L2StandardTokenFactory = await (
await ethers.getContractFactory('OVM_L2StandardTokenFactory')
).deploy()
})
describe('Standard token factory', () => {
it('should be able to create a standard token', async () => {
const tx = await OVM_L2StandardTokenFactory.createStandardL2Token(
L1ERC20.address,
'L2ERC20',
'ERC'
)
const receipt = await tx.wait()
const [tokenCreatedEvent] = receipt.events
// Expect there to be an event emmited for the standard token creation
expect(tokenCreatedEvent.event).to.be.eq('StandardL2TokenCreated')
// Get the L2 token address from the emmited event and check it was created correctly
const l2TokenAddress = tokenCreatedEvent.args._l2Token
const l2Token = new Contract(
l2TokenAddress,
getContractInterface('L2StandardERC20'),
signer
)
expect(await l2Token.l2Bridge()).to.equal(predeploys.OVM_L2StandardBridge)
expect(await l2Token.l1Token()).to.equal(L1ERC20.address)
expect(await l2Token.name()).to.equal('L2ERC20')
expect(await l2Token.symbol()).to.equal('ERC')
})
it('should not be able to create a standard token with a 0 address for l1 token', async () => {
await expect(
OVM_L2StandardTokenFactory.createStandardL2Token(
ethers.constants.AddressZero,
'L2ERC20',
'ERC'
)
).to.be.revertedWith('Must provide L1 token address')
})
})
})
......@@ -93,12 +93,13 @@ describe('OVM_L1CrossDomainMessenger', () => {
Factory__OVM_L1CrossDomainMessenger = await ethers.getContractFactory(
'OVM_L1CrossDomainMessenger'
)
OVM_CanonicalTransactionChain = await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
OVM_CanonicalTransactionChain =
await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
const batches = await Factory__OVM_ChainStorageContainer.deploy(
AddressManager.address,
......@@ -127,7 +128,8 @@ describe('OVM_L1CrossDomainMessenger', () => {
let OVM_L1CrossDomainMessenger: Contract
beforeEach(async () => {
const xDomainMessengerImpl = await Factory__OVM_L1CrossDomainMessenger.deploy()
const xDomainMessengerImpl =
await Factory__OVM_L1CrossDomainMessenger.deploy()
// We use an upgradable proxy for the XDomainMessenger--deploy & set up the proxy.
OVM_L1CrossDomainMessenger = await deployProxyXDomainMessenger(
AddressManager,
......@@ -255,10 +257,71 @@ describe('OVM_L1CrossDomainMessenger', () => {
})
})
const generateMockRelayMessageProof = async (
target: string,
sender: string,
message: string,
messageNonce: number = 0
): Promise<{
calldata: string
proof: any
}> => {
const calldata = encodeXDomainCalldata(
target,
sender,
message,
messageNonce
)
const storageKey = keccak256(
keccak256(calldata + remove0x(Mock__OVM_L2CrossDomainMessenger.address)) +
'00'.repeat(32)
)
const storageGenerator = await TrieTestGenerator.fromNodes({
nodes: [
{
key: storageKey,
val: '0x' + '01'.padStart(2, '0'),
},
],
secure: true,
})
const generator = await TrieTestGenerator.fromAccounts({
accounts: [
{
address: predeploys.OVM_L2ToL1MessagePasser,
nonce: 0,
balance: 0,
codeHash: keccak256('0x1234'),
storageRoot: toHexString(storageGenerator._trie.root),
},
],
secure: true,
})
const proof = {
stateRoot: toHexString(generator._trie.root),
stateRootBatchHeader: DUMMY_BATCH_HEADERS[0],
stateRootProof: DUMMY_BATCH_PROOFS[0],
stateTrieWitness: (
await generator.makeAccountProofTest(predeploys.OVM_L2ToL1MessagePasser)
).accountTrieWitness,
storageTrieWitness: (
await storageGenerator.makeInclusionProofTest(storageKey)
).proof,
}
return {
calldata,
proof,
}
}
describe('relayMessage', () => {
let target: string
let message: string
let sender: string
let message: string
let proof: any
let calldata: string
before(async () => {
......@@ -268,49 +331,13 @@ describe('OVM_L1CrossDomainMessenger', () => {
])
sender = await signer.getAddress()
calldata = encodeXDomainCalldata(target, sender, message, 0)
const storageKey = keccak256(
keccak256(
calldata + remove0x(Mock__OVM_L2CrossDomainMessenger.address)
) + '00'.repeat(32)
const mockProof = await generateMockRelayMessageProof(
target,
sender,
message
)
const storageGenerator = await TrieTestGenerator.fromNodes({
nodes: [
{
key: storageKey,
val: '0x' + '01'.padStart(2, '0'),
},
],
secure: true,
})
const generator = await TrieTestGenerator.fromAccounts({
accounts: [
{
address: predeploys.OVM_L2ToL1MessagePasser,
nonce: 0,
balance: 0,
codeHash: keccak256('0x1234'),
storageRoot: toHexString(storageGenerator._trie.root),
},
],
secure: true,
})
proof = {
stateRoot: toHexString(generator._trie.root),
stateRootBatchHeader: DUMMY_BATCH_HEADERS[0],
stateRootProof: DUMMY_BATCH_PROOFS[0],
stateTrieWitness: (
await generator.makeAccountProofTest(
predeploys.OVM_L2ToL1MessagePasser
)
).accountTrieWitness,
storageTrieWitness: (
await storageGenerator.makeInclusionProofTest(storageKey)
).proof,
}
proof = mockProof.proof
calldata = mockProof.calldata
})
beforeEach(async () => {
......@@ -346,6 +373,26 @@ describe('OVM_L1CrossDomainMessenger', () => {
).to.be.revertedWith('Provided message could not be verified.')
})
it('should revert if attempting to relay a message sent to an L1 system contract', async () => {
const maliciousProof = await generateMockRelayMessageProof(
OVM_CanonicalTransactionChain.address,
sender,
message
)
await expect(
OVM_L1CrossDomainMessenger.relayMessage(
OVM_CanonicalTransactionChain.address,
sender,
message,
0,
maliciousProof.proof
)
).to.be.revertedWith(
'Cannot send L2->L1 messages to L1 system contracts.'
)
})
it('should revert if provided an invalid state root proof', async () => {
Mock__OVM_StateCommitmentChain.smocked.verifyStateCommitment.will.return.with(
false
......@@ -469,9 +516,8 @@ describe('OVM_L1CrossDomainMessenger', () => {
describe('blockMessage and allowMessage', () => {
it('should revert if called by an account other than the owner', async () => {
const OVM_L1CrossDomainMessenger2 = OVM_L1CrossDomainMessenger.connect(
signer2
)
const OVM_L1CrossDomainMessenger2 =
OVM_L1CrossDomainMessenger.connect(signer2)
await expect(
OVM_L1CrossDomainMessenger2.blockMessage(keccak256(calldata))
).to.be.revertedWith('Ownable: caller is not the owner')
......
......@@ -71,9 +71,8 @@ describe('OVM_L2CrossDomainMessenger', () => {
let OVM_L2CrossDomainMessenger: Contract
beforeEach(async () => {
OVM_L2CrossDomainMessenger = await Factory__OVM_L2CrossDomainMessenger.deploy(
AddressManager.address
)
OVM_L2CrossDomainMessenger =
await Factory__OVM_L2CrossDomainMessenger.deploy(AddressManager.address)
})
describe('sendMessage', () => {
......@@ -183,7 +182,9 @@ describe('OVM_L2CrossDomainMessenger', () => {
// There should be no 'relayedMessage' event logged in the receipt.
const logs = (
await Mock__OVM_L2ToL1MessagePasser.provider.getTransactionReceipt(
(await resProm).hash
(
await resProm
).hash
)
).logs
expect(logs).to.deep.equal([])
......@@ -204,10 +205,11 @@ describe('OVM_L2CrossDomainMessenger', () => {
Mock__OVM_L1CrossDomainMessenger.address
)
const reentrantMessage = OVM_L2CrossDomainMessenger.interface.encodeFunctionData(
'relayMessage',
[target, sender, message, 1]
)
const reentrantMessage =
OVM_L2CrossDomainMessenger.interface.encodeFunctionData(
'relayMessage',
[target, sender, message, 1]
)
// Calculate xDomainCallData used for indexing
// (within the first call to the L2 Messenger).
......
......@@ -98,12 +98,13 @@ describe('[GAS BENCHMARK] OVM_CanonicalTransactionChain', () => {
let OVM_CanonicalTransactionChain: Contract
beforeEach(async () => {
OVM_CanonicalTransactionChain = await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
OVM_CanonicalTransactionChain =
await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
const batches = await Factory__OVM_ChainStorageContainer.deploy(
AddressManager.address,
......@@ -132,9 +133,8 @@ describe('[GAS BENCHMARK] OVM_CanonicalTransactionChain', () => {
describe('appendSequencerBatch [ @skip-on-coverage ]', () => {
beforeEach(() => {
OVM_CanonicalTransactionChain = OVM_CanonicalTransactionChain.connect(
sequencer
)
OVM_CanonicalTransactionChain =
OVM_CanonicalTransactionChain.connect(sequencer)
})
it('200 transactions in a single context', async () => {
......
......@@ -147,12 +147,13 @@ describe('OVM_CanonicalTransactionChain', () => {
let OVM_CanonicalTransactionChain: Contract
beforeEach(async () => {
OVM_CanonicalTransactionChain = await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
OVM_CanonicalTransactionChain =
await Factory__OVM_CanonicalTransactionChain.deploy(
AddressManager.address,
FORCE_INCLUSION_PERIOD_SECONDS,
FORCE_INCLUSION_PERIOD_BLOCKS,
MAX_GAS_LIMIT
)
const batches = await Factory__OVM_ChainStorageContainer.deploy(
AddressManager.address,
......@@ -184,7 +185,8 @@ describe('OVM_CanonicalTransactionChain', () => {
const gasLimit = 500_000
it('should revert when trying to input more data than the max data size', async () => {
const MAX_ROLLUP_TX_SIZE = await OVM_CanonicalTransactionChain.MAX_ROLLUP_TX_SIZE()
const MAX_ROLLUP_TX_SIZE =
await OVM_CanonicalTransactionChain.MAX_ROLLUP_TX_SIZE()
const data = '0x' + '12'.repeat(MAX_ROLLUP_TX_SIZE + 1)
await expect(
......@@ -207,7 +209,8 @@ describe('OVM_CanonicalTransactionChain', () => {
})
it('should revert if gas limit parameter is not at least MIN_ROLLUP_TX_GAS', async () => {
const MIN_ROLLUP_TX_GAS = await OVM_CanonicalTransactionChain.MIN_ROLLUP_TX_GAS()
const MIN_ROLLUP_TX_GAS =
await OVM_CanonicalTransactionChain.MIN_ROLLUP_TX_GAS()
const customGasLimit = MIN_ROLLUP_TX_GAS / 2
const data = '0x' + '12'.repeat(1234)
......@@ -217,7 +220,8 @@ describe('OVM_CanonicalTransactionChain', () => {
})
it('should revert if transaction gas limit does not cover rollup burn', async () => {
const L2_GAS_DISCOUNT_DIVISOR = await OVM_CanonicalTransactionChain.L2_GAS_DISCOUNT_DIVISOR()
const L2_GAS_DISCOUNT_DIVISOR =
await OVM_CanonicalTransactionChain.L2_GAS_DISCOUNT_DIVISOR()
const data = '0x' + '12'.repeat(1234)
await expect(
......@@ -663,9 +667,8 @@ describe('OVM_CanonicalTransactionChain', () => {
describe('appendSequencerBatch', () => {
beforeEach(() => {
OVM_CanonicalTransactionChain = OVM_CanonicalTransactionChain.connect(
sequencer
)
OVM_CanonicalTransactionChain =
OVM_CanonicalTransactionChain.connect(sequencer)
})
it('should revert if expected start does not match current total batches', async () => {
......@@ -757,7 +760,8 @@ describe('OVM_CanonicalTransactionChain', () => {
})
it('should revert when trying to input more data than the max data size', async () => {
const MAX_ROLLUP_TX_SIZE = await OVM_CanonicalTransactionChain.MAX_ROLLUP_TX_SIZE()
const MAX_ROLLUP_TX_SIZE =
await OVM_CanonicalTransactionChain.MAX_ROLLUP_TX_SIZE()
const data = '0x' + '12'.repeat(MAX_ROLLUP_TX_SIZE + 1)
const timestamp = await getEthTime(ethers.provider)
......@@ -965,9 +969,8 @@ describe('OVM_CanonicalTransactionChain', () => {
gasLimit,
data
)
queueElements[
i
] = await OVM_CanonicalTransactionChain.getQueueElement(i)
queueElements[i] =
await OVM_CanonicalTransactionChain.getQueueElement(i)
// this is a valid context for this TX
validContexts[i] = {
numSequencedTransactions: 1,
......
......@@ -170,7 +170,8 @@ describe('OVM_StateCommitmentChain', () => {
describe('when outside sequencer publish window', () => {
beforeEach(async () => {
const SEQUENCER_PUBLISH_WINDOW = await OVM_StateCommitmentChain.SEQUENCER_PUBLISH_WINDOW()
const SEQUENCER_PUBLISH_WINDOW =
await OVM_StateCommitmentChain.SEQUENCER_PUBLISH_WINDOW()
await increaseEthTime(
ethers.provider,
SEQUENCER_PUBLISH_WINDOW.toNumber() + 1
......
......@@ -68,9 +68,9 @@ describe('OVM_ExecutionManager gas consumption', () => {
// deploy the state manager and mock it for the state transitioner
MOCK__STATE_MANAGER = await smockit(
await (await ethers.getContractFactory('OVM_StateManager')).deploy(
NON_ZERO_ADDRESS
)
await (
await ethers.getContractFactory('OVM_StateManager')
).deploy(NON_ZERO_ADDRESS)
)
// Setup the SM to satisfy all the checks executed during EM.run()
......
......@@ -51,8 +51,7 @@ const test_nuisanceGas: TestDefinition = {
},
subTests: [
{
name:
'ovmCALL consumes nuisance gas of CODESIZE * NUISANCE_GAS_PER_CONTRACT_BYTE',
name: 'ovmCALL consumes nuisance gas of CODESIZE * NUISANCE_GAS_PER_CONTRACT_BYTE',
postState: {
ExecutionManager: {
messageRecord: {
......@@ -88,8 +87,7 @@ const test_nuisanceGas: TestDefinition = {
],
},
{
name:
'ovmCALL consumes nuisance gas of CODESIZE * NUISANCE_GAS_PER_CONTRACT_BYTE twice for two unique ovmCALLS',
name: 'ovmCALL consumes nuisance gas of CODESIZE * NUISANCE_GAS_PER_CONTRACT_BYTE twice for two unique ovmCALLS',
postState: {
ExecutionManager: {
messageRecord: {
......@@ -140,8 +138,7 @@ const test_nuisanceGas: TestDefinition = {
],
},
{
name:
'ovmCALL consumes all allotted nuisance gas if code contract throws unknown exception',
name: 'ovmCALL consumes all allotted nuisance gas if code contract throws unknown exception',
postState: {
ExecutionManager: {
messageRecord: {
......@@ -178,8 +175,7 @@ const test_nuisanceGas: TestDefinition = {
],
},
{
name:
'ovmCREATE consumes all allotted nuisance gas if creation code throws data-less exception',
name: 'ovmCREATE consumes all allotted nuisance gas if creation code throws data-less exception',
parameters: [
{
name: 'give 1/2 gas to ovmCALL => ovmCREATE, evmINVALID',
......
......@@ -90,8 +90,7 @@ const test_ovmCALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmSSTORE + ovmSLOAD, ovmCALL(ADDRESS_1) => ovmSLOAD',
name: 'ovmCALL(ADDRESS_1) => ovmSSTORE + ovmSLOAD, ovmCALL(ADDRESS_1) => ovmSLOAD',
steps: [
{
functionName: 'ovmCALL',
......@@ -140,8 +139,7 @@ const test_ovmCALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmADDRESS + ovmCALLER',
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmADDRESS + ovmCALLER',
steps: [
{
functionName: 'ovmCALL',
......
......@@ -401,8 +401,7 @@ const test_ovmCREATE: TestDefinition = {
],
},
{
name:
'ovmCREATE => ovmSSTORE, ovmCALL(CREATED) => ovmSLOAD(EXIST) + ovmSLOAD(NONEXIST)',
name: 'ovmCREATE => ovmSSTORE, ovmCALL(CREATED) => ovmSLOAD(EXIST) + ovmSLOAD(NONEXIST)',
steps: [
{
functionName: 'ovmCREATE',
......@@ -450,8 +449,7 @@ const test_ovmCREATE: TestDefinition = {
],
},
{
name:
'ovmCREATE => ovmCALL(ADDRESS_1) => ovmSSTORE, ovmCALL(ADDRESS_1) => ovmSLOAD',
name: 'ovmCREATE => ovmCALL(ADDRESS_1) => ovmSSTORE, ovmCALL(ADDRESS_1) => ovmSLOAD',
steps: [
{
functionName: 'ovmCREATE',
......@@ -503,8 +501,7 @@ const test_ovmCREATE: TestDefinition = {
{
// TODO: appears to be failing due to a smoddit issue
skip: true,
name:
'ovmCREATE => (ovmCALL(ADDRESS_2) => ovmSSTORE) + ovmREVERT, ovmCALL(ADDRESS_2) => ovmSLOAD',
name: 'ovmCREATE => (ovmCALL(ADDRESS_2) => ovmSSTORE) + ovmREVERT, ovmCALL(ADDRESS_2) => ovmSLOAD',
steps: [
{
functionName: 'ovmCREATE',
......@@ -775,9 +772,10 @@ const test_ovmCREATE: TestDefinition = {
contractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
// initialized? true, allowArbitraryDeployment? false
'0x0000000000000000000000000000000000000000000000000000000000000000': getStorageXOR(
'0x0000000000000000000000000000000000000000000000000000000000000001'
),
'0x0000000000000000000000000000000000000000000000000000000000000000':
getStorageXOR(
'0x0000000000000000000000000000000000000000000000000000000000000001'
),
// non-whitelisted deployer is whitelisted? false
[NON_WHITELISTED_DEPLOYER_KEY]: getStorageXOR(
ethers.constants.HashZero
......@@ -905,9 +903,10 @@ const test_ovmCREATE: TestDefinition = {
contractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
// initialized? true, allowArbitraryDeployment? true
'0x0000000000000000000000000000000000000000000000000000000000000000': getStorageXOR(
'0x0000000000000000000000000000000000000000000000000000000000000101'
),
'0x0000000000000000000000000000000000000000000000000000000000000000':
getStorageXOR(
'0x0000000000000000000000000000000000000000000000000000000000000101'
),
// non-whitelisted deployer is whitelisted? false
[NON_WHITELISTED_DEPLOYER_KEY]: getStorageXOR(
ethers.constants.HashZero
......@@ -946,7 +945,8 @@ const test_ovmCREATE: TestDefinition = {
subSteps: [],
},
expectedReturnStatus: true,
expectedReturnValue: CREATED_BY_NON_WHITELISTED_DEPLOYER,
expectedReturnValue:
CREATED_BY_NON_WHITELISTED_DEPLOYER,
},
],
},
......
......@@ -54,10 +54,8 @@ const test_ovmCREATEEOA: TestDefinition = {
_messageHash:
'0x92d658d25f963af824e9d4bd533c165773d4a694a67d88135d119d5bca97c001',
_v: 1,
_r:
'0x73757c671fae2c3fb6825766c724b7715720bda4b309d3612f2c623364556967',
_s:
'0x2fc9b7222783390b9f10e22e92a52871beaff2613193d6e2dbf18d0e2d2eb8ff',
_r: '0x73757c671fae2c3fb6825766c724b7715720bda4b309d3612f2c623364556967',
_s: '0x2fc9b7222783390b9f10e22e92a52871beaff2613193d6e2dbf18d0e2d2eb8ff',
},
expectedReturnStatus: true,
expectedReturnValue: undefined,
......
......@@ -87,8 +87,7 @@ const test_ovmDELEGATECALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmCALLER',
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmCALLER',
steps: [
{
functionName: 'ovmCALL',
......@@ -127,8 +126,7 @@ const test_ovmDELEGATECALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => (ovmDELEGATECALL(ADDRESS_2) => ovmSSTORE) + ovmSLOAD',
name: 'ovmCALL(ADDRESS_1) => (ovmDELEGATECALL(ADDRESS_2) => ovmSSTORE) + ovmSLOAD',
steps: [
{
functionName: 'ovmCALL',
......@@ -202,8 +200,7 @@ const test_ovmDELEGATECALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmDELEGATECALL(ADDRESS_4) => ovmCALLER',
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmDELEGATECALL(ADDRESS_4) => ovmCALLER',
steps: [
{
functionName: 'ovmCALL',
......@@ -252,8 +249,7 @@ const test_ovmDELEGATECALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmDELEGATECALL(ADDRESS_4) => ovmADDRESS',
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmDELEGATECALL(ADDRESS_4) => ovmADDRESS',
steps: [
{
functionName: 'ovmCALL',
......@@ -302,8 +298,7 @@ const test_ovmDELEGATECALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmDELEGATECALL(ADDRESS_4) => ovmCREATE',
name: 'ovmCALL(ADDRESS_1) => ovmCALL(ADDRESS_2) => ovmDELEGATECALL(ADDRESS_3) => ovmDELEGATECALL(ADDRESS_4) => ovmCREATE',
steps: [
{
functionName: 'ovmCALL',
......
......@@ -192,8 +192,7 @@ const test_ovmSTATICCALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmSTATICCALL(ADDRESS_2) => ovmCALL(ADDRESS_3) => ovmSSTORE',
name: 'ovmCALL(ADDRESS_1) => ovmSTATICCALL(ADDRESS_2) => ovmCALL(ADDRESS_3) => ovmSSTORE',
steps: [
{
functionName: 'ovmCALL',
......@@ -240,8 +239,7 @@ const test_ovmSTATICCALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmSTATICCALL(ADDRESS_2) => ovmCALL(ADDRESS_3) => ovmSLOAD',
name: 'ovmCALL(ADDRESS_1) => ovmSTATICCALL(ADDRESS_2) => ovmCALL(ADDRESS_3) => ovmSLOAD',
steps: [
{
functionName: 'ovmCALL',
......@@ -284,8 +282,7 @@ const test_ovmSTATICCALL: TestDefinition = {
],
},
{
name:
'ovmCALL(ADDRESS_1) => ovmSTATICCALL(ADDRESS_2) => ovmCALL(ADDRESS_3) => ovmCREATE',
name: 'ovmCALL(ADDRESS_1) => ovmSTATICCALL(ADDRESS_2) => ovmCALL(ADDRESS_3) => ovmCREATE',
steps: [
{
functionName: 'ovmCALL',
......
......@@ -67,10 +67,9 @@ describe('OVM_BondManager', () => {
token = await (await deployer.getContractFactory('TestERC20')).deploy()
await token.mint(sender, ethers.utils.parseEther('100'))
bondManager = await (await smoddit('OVM_BondManager')).deploy(
token.address,
manager.address
)
bondManager = await (
await smoddit('OVM_BondManager')
).deploy(token.address, manager.address)
await manager.setAddress('OVM_BondManager', bondManager.address)
await fraudVerifier.setBondManager(bondManager.address)
})
......
......@@ -35,9 +35,8 @@ describe('OVM_StateTransitionerFactory', () => {
let OVM_StateTransitionerFactory: Contract
let Mock__OVM_StateManagerFactory: MockContract
beforeEach(async () => {
OVM_StateTransitionerFactory = await Factory__OVM_StateTransitionerFactory.deploy(
AddressManager.address
)
OVM_StateTransitionerFactory =
await Factory__OVM_StateTransitionerFactory.deploy(AddressManager.address)
Mock__OVM_StateManagerFactory = await smockit('OVM_StateManagerFactory')
Mock__OVM_StateManagerFactory.smocked.create.will.return.with(
......
......@@ -44,9 +44,10 @@ describe('Lib_RLPWriter', () => {
const randomAddress = '0x1234123412341234123412341234123412341234'
const rlpEncodedRandomAddress =
'0x941234123412341234123412341234123412341234'
const encoded = await Lib_RLPWriter.callStatic.writeAddressWithTaintedMemory(
randomAddress
)
const encoded =
await Lib_RLPWriter.callStatic.writeAddressWithTaintedMemory(
randomAddress
)
expect(encoded).to.eq(rlpEncodedRandomAddress)
})
})
......
......@@ -10,20 +10,7 @@ import { fromHexString, toHexString } from '@eth-optimism/core-utils'
import { NON_NULL_BYTES32 } from '../../../helpers'
const NODE_COUNTS = [
2,
3,
7,
9,
13,
63,
64,
123,
128,
129,
255,
1021,
1023,
1024,
2, 3, 7, 9, 13, 63, 64, 123, 128, 129, 255, 1021, 1023, 1024,
]
const hash = (el: Buffer | string): Buffer => {
......
......@@ -6,7 +6,8 @@ export const encodeXDomainCalldata = (
message: string,
messageNonce: number
): string => {
return getContractInterface(
'OVM_L2CrossDomainMessenger'
).encodeFunctionData('relayMessage', [target, sender, message, messageNonce])
return getContractInterface('OVM_L2CrossDomainMessenger').encodeFunctionData(
'relayMessage',
[target, sender, message, messageNonce]
)
}
......@@ -16,10 +16,11 @@ export class GasMeasurement {
methodName: string,
methodArgs: Array<any> = []
): Promise<number> {
const gasCost: number = await this.GasMeasurementContract.callStatic.measureCallGas(
targetContract.address,
targetContract.interface.encodeFunctionData(methodName, methodArgs)
)
const gasCost: number =
await this.GasMeasurementContract.callStatic.measureCallGas(
targetContract.address,
targetContract.interface.encodeFunctionData(methodName, methodArgs)
)
return gasCost
}
......
......@@ -83,15 +83,17 @@ export class ExecutionManagerTestRunner {
},
contractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
'0x0000000000000000000000000000000000000000000000000000000000000000': {
getStorageXOR: true,
value: ethers.constants.HashZero,
},
'0x0000000000000000000000000000000000000000000000000000000000000000':
{
getStorageXOR: true,
value: ethers.constants.HashZero,
},
},
},
verifiedContractStorage: {
[predeploys.OVM_DeployerWhitelist]: {
'0x0000000000000000000000000000000000000000000000000000000000000000': true,
'0x0000000000000000000000000000000000000000000000000000000000000000':
true,
},
},
},
......@@ -275,9 +277,8 @@ export class ExecutionManagerTestRunner {
await ethers.getContractFactory('Helper_TestRunner')
).deploy()
this.contracts.Factory__Helper_TestRunner_CREATE = await ethers.getContractFactory(
'Helper_TestRunner_CREATE'
)
this.contracts.Factory__Helper_TestRunner_CREATE =
await ethers.getContractFactory('Helper_TestRunner_CREATE')
this.snapshot = await ethers.provider.send('evm_snapshot', [])
}
......
module.exports = {
"extends": "../../.eslintrc.js"
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
../../.prettierrc.json
\ No newline at end of file
......@@ -14,8 +14,9 @@
"build": "tsc -p tsconfig.build.json",
"clean": "rimraf dist/ ./tsconfig.build.tsbuildinfo",
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "prettier --config .prettierrc.json --write '{src,test}/**/*.ts'",
"lint:check": "eslint -c .eslintrc.js --ext .ts --format stylish .",
"lint:check": "eslint .",
"lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged",
"test": "ts-mocha test/**/*.spec.ts"
},
"devDependencies": {
......@@ -26,7 +27,9 @@
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"chai": "^4.3.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
......@@ -36,6 +39,7 @@
"eslint-plugin-unicorn": "^32.0.1",
"mocha": "^8.3.0",
"prettier": "^2.2.1",
"lint-staged": "11.0.0",
"ts-mocha": "^8.0.0",
"typescript": "^4.2.3"
},
......
......@@ -16,13 +16,13 @@ export interface WatcherOptions {
export class Watcher {
public l1: Layer
public l2: Layer
public pollInterval: number = 3000
public NUM_BLOCKS_TO_FETCH: number = 10_000_000
public pollInterval = 3000
public NUM_BLOCKS_TO_FETCH = 10_000_000
constructor(opts: WatcherOptions) {
this.l1 = opts.l1
this.l2 = opts.l2
if(opts.pollInterval) {
if (opts.pollInterval) {
this.pollInterval = opts.pollInterval
}
}
......@@ -36,14 +36,14 @@ export class Watcher {
public async getL1TransactionReceipt(
l2ToL1MsgHash: string,
pollForPending: boolean = true
pollForPending = true
): Promise<TransactionReceipt> {
return this.getTransactionReceipt(this.l1, l2ToL1MsgHash, pollForPending)
}
public async getL2TransactionReceipt(
l1ToL2MsgHash: string,
pollForPending: boolean = true
pollForPending = true
): Promise<TransactionReceipt> {
return this.getTransactionReceipt(this.l2, l1ToL2MsgHash, pollForPending)
}
......@@ -76,7 +76,7 @@ export class Watcher {
public async getTransactionReceipt(
layer: Layer,
msgHash: string,
pollForPending: boolean = true
pollForPending = true
): Promise<TransactionReceipt> {
let matches: ethers.providers.Log[] = []
......@@ -87,12 +87,12 @@ export class Watcher {
const successFilter: ethers.providers.Filter = {
address: layer.messengerAddress,
topics: [ethers.utils.id(`RelayedMessage(bytes32)`)],
fromBlock: startingBlock
fromBlock: startingBlock,
}
const failureFilter: ethers.providers.Filter = {
address: layer.messengerAddress,
topics: [ethers.utils.id(`FailedRelayedMessage(bytes32)`)],
fromBlock: startingBlock
fromBlock: startingBlock,
}
const successLogs = await layer.provider.getLogs(successFilter)
const failureLogs = await layer.provider.getLogs(failureFilter)
......@@ -105,7 +105,7 @@ export class Watcher {
}
// pause awhile before trying again
await new Promise(r => setTimeout(r, this.pollInterval))
await new Promise((r) => setTimeout(r, this.pollInterval))
}
// Message was relayed in the past
......
module.exports = {
"extends": "../../.eslintrc.js"
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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