Skip to content
This repository has been archived by the owner on Dec 5, 2021. It is now read-only.

Commit

Permalink
Import contracts (#18)
Browse files Browse the repository at this point in the history
* feat: add contracts

* fix: configure tsconfig and replace build => dist

* chore: remove CI files

* chore: use monorepo tslint / prettier
  • Loading branch information
gakonst authored Mar 30, 2021
1 parent a800832 commit 788b4f2
Show file tree
Hide file tree
Showing 207 changed files with 41,472 additions and 29 deletions.
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
node_modules
**/dist
results
temp
.nyc_output
*.tsbuildinfo

build
dist

artifacts
artifacts-ovm
cache
cache-ovm

1 change: 1 addition & 0 deletions packages/contracts/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sol linguist-language=Solidity
82 changes: 82 additions & 0 deletions packages/contracts/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Changelog

## v0.1.11
- cleanup: ECDSAContractAccount
- cleanup: Proxy_EOA
- cleanup: StateManagerFactory
- cleanup: Bytes32Utils
- cleanup: Minor cleanup to state manager
- cleanup: SafetyChecker
- Remove gas estimators from gateway interface
- Add ERC1820 Registry as a precompile
- dev: Remove usage of custom concat function in Solidity
- Fix revert string generated by EM wrapper
- Update OVM_L1ERC20Gateway.sol
- Move OVM_BondManager test into the right location

## v0.1.10
Adds extensible ERC20Gateway and Improve CI.

- dev: Apply linting to all test files
- Test gas consumption of EM.run()
- Extensible deposit withdraw
- Update OVM_L2DepositedERC20.sol
- Commit state dumps to regenesis repo for new tags
- Update OVM_ChainStorageContainer.sol
- Update OVM_ECDSAContractAccount.sol
- Update OVM_CanonicalTransactionChain.sol
- Reset Context on invalid gaslimit
- [Fix] CI on merge
- [Fix] Run integration tests in forked context

## v0.1.9

Standardized ETH and ERC20 Gateways.

- Add ETH deposit contract.
- Add standard deposit/withdrawal interfaces.

## v0.1.5

Various cleanup and maintenance tasks.

- Improving comments and some names (#211)
- Add descriptive comments above the contract declaration for all 'non-abstract contracts' (#200)
- Add generic mock xdomain messenger (#209)
- Move everything over to hardhat (#208)
- Add comment to document v argument (#199)
- Add security related comments (#191)

## v0.1.4

Fix single contract redeployment & state dump script for
mainnet.

## v0.1.3

Add events to fraud proof initialization and finalization.

## v0.1.2

Npm publish integrity.

## v0.1.1

Audit fixes, deployment fixes & final parameterization.

- Add build mainnet command to package.json (#186)
- revert chain ID 422 -> 420 (#185)
- add `AddressSet` event (#184)
- Add mint & burn to L2 ETH (#178)
- Wait for deploy transactions (#180)
- Final Parameterization of Constants (#176)
- re-enable monotonicity tests (#177)
- make ovmSETNONCE notStatic (#179)
- Add reentry protection to ExecutionManager.run() (#175)
- Add nonReentrant to `relayMessage()` (#172)
- ctc: public getters, remove dead variable (#174)
- fix tainted memory bug in `Lib_BytesUtils.slice` (#171)

## v0.1.0

Initial Release
22 changes: 22 additions & 0 deletions packages/contracts/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(The MIT License)

Copyright 2020 Optimism

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76 changes: 76 additions & 0 deletions packages/contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Optimistic Ethereum Smart Contracts

`@eth-optimism/contracts` contains the various Solidity smart contracts used within the Optimistic Ethereum system.
Some of these contracts are deployed on Ethereum ("Layer 1"), while others are meant to be deployed to Optimistic Ethereum ("Layer 2").

Within each contract file you'll find a comment that lists:
1. The compiler with which a contract is intended to be compiled, `solc` or `optimistic-solc`.
2. The network upon to which the contract will be deployed, `OVM` or `EVM`.

A more detailed overview of these contracts can be found on the [community hub](http://community.optimism.io/docs/protocol/protocol.html#system-overview).

<!-- TODO: Add link to final contract docs here when finished. -->

## Usage (npm)
If your development stack is based on Node/npm:

```shell
npm install @eth-optimism/contracts
```

Within your contracts:

```solidity
import { SomeContract } from "@eth-optimism/contracts/SomeContract.sol";
```

## Guide for Developers
### Setup
Install the following:
- [`Node.js` (14+)](https://nodejs.org/en/)
- [`npm`](https://www.npmjs.com/get-npm)
- [`yarn`](https://classic.yarnpkg.com/en/docs/install/)

Clone the repo:

```shell
git clone https://github.com/ethereum-optimism/contracts.git
cd contracts
```

Install `npm` packages:
```shell
yarn install
```

### Running Tests
Tests are executed via `yarn`:
```shell
yarn test
```

Run specific tests by giving a path to the file you want to run:
```shell
yarn test ./test/path/to/my/test.spec.ts
```

### Compiling and Building
Easiest way is to run the primary build script:
```shell
yarn build
```

Running the full build command will perform the following actions:
1. `build:contracts` - Compile all Solidity contracts with both the EVM and OVM compilers.
2. `build:typescript` - Builds the typescript files that are used to export utilities into js.
3. `build:copy` - Copies various other files into the dist folder.
4. `build:dump` - Generates a genesis state from the contracts that L2 geth will use.
5. `build:typechain` - Generates [TypeChain](https://github.com/ethereum-ts/TypeChain) artifacts.

You can also build specific components as follows:
```shell
yarn build:contracts
```

## Security
Please refer to our [Security Policy](https://github.com/ethereum-optimism/.github/security/policy) for information about how to disclose security issues with this code.
120 changes: 120 additions & 0 deletions packages/contracts/bin/deploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env node

const contracts = require('../dist/src/contract-deployment/deploy');
const { providers, Wallet, utils, ethers } = require('ethers');
const { LedgerSigner } = require('@ethersproject/hardware-wallets');
const { JsonRpcProvider } = providers;

const env = process.env;
const key = env.DEPLOYER_PRIVATE_KEY;
const sequencerKey = env.SEQUENCER_PRIVATE_KEY;
let SEQUENCER_ADDRESS = env.SEQUENCER_ADDRESS;
const web3Url = env.L1_NODE_WEB3_URL || 'http://127.0.0.1:8545';
const DEPLOY_TX_GAS_LIMIT = env.DEPLOY_TX_GAS_LIMIT || 5000000;
const MIN_TRANSACTION_GAS_LIMIT = env.MIN_TRANSACTION_GAS_LIMIT || 50000;
const MAX_TRANSACTION_GAS_LIMIT = env.MAX_TRANSACTION_GAS_LIMIT || 9000000;
const MAX_GAS_PER_QUEUE_PER_EPOCH = env.MAX_GAS_PER_QUEUE_PER_EPOCH || 250000000;
const SECONDS_PER_EPOCH = env.SECONDS_PER_EPOCH || 0;
const WAIT_FOR_RECEIPTS = env.WAIT_FOR_RECEIPTS === 'true';
let WHITELIST_OWNER = env.WHITELIST_OWNER;
const WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT = env.WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT || true;
const FORCE_INCLUSION_PERIOD_SECONDS = env.FORCE_INCLUSION_PERIOD_SECONDS || 2592000; // 30 days
const FRAUD_PROOF_WINDOW_SECONDS = env.FRAUD_PROOF_WINDOW_SECONDS || (60 * 60 * 24 * 7); // 7 days
const SEQUENCER_PUBLISH_WINDOW_SECONDS = env.SEQUENCER_PUBLISH_WINDOW_SECONDS || (60 * 30); // 30 min
const CHAIN_ID = env.CHAIN_ID || 420; // layer 2 chainid
const USE_LEDGER = env.USE_LEDGER || false;
const ADDRESS_MANAGER_ADDRESS = env.ADDRESS_MANAGER_ADDRESS || undefined;
const HD_PATH = env.HD_PATH || utils.defaultPath;
const BLOCK_TIME_SECONDS = env.BLOCK_TIME_SECONDS || 15;
const L2_CROSS_DOMAIN_MESSENGER_ADDRESS =
env.L2_CROSS_DOMAIN_MESSENGER_ADDRESS || '0x4200000000000000000000000000000000000007';
let RELAYER_ADDRESS = env.RELAYER_ADDRESS || '0x0000000000000000000000000000000000000000';
const RELAYER_PRIVATE_KEY = env.RELAYER_PRIVATE_KEY;

(async () => {
const provider = new JsonRpcProvider(web3Url);
let signer;

// Use the ledger for the deployer
if (USE_LEDGER) {
signer = new LedgerSigner(provider, 'default', HD_PATH);
} else {
if (typeof key === 'undefined')
throw new Error('Must pass deployer key as DEPLOYER_PRIVATE_KEY');
signer = new Wallet(key, provider);
}

if (SEQUENCER_ADDRESS) {
if (!utils.isAddress(SEQUENCER_ADDRESS))
throw new Error(`Invalid Sequencer Address: ${SEQUENCER_ADDRESS}`);
} else {
if (!sequencerKey)
throw new Error('Must pass sequencer key as SEQUENCER_PRIVATE_KEY');
const sequencer = new Wallet(sequencerKey, provider);
SEQUENCER_ADDRESS = await sequencer.getAddress();
}

if (typeof WHITELIST_OWNER === 'undefined')
WHITELIST_OWNER = signer;

// Use the address derived from RELAYER_PRIVATE_KEY if a private key
// is passed. Using the zero address as the relayer address will mean
// there is no relayer authentication.
if (RELAYER_PRIVATE_KEY) {
if (!utils.isAddress(RELAYER_ADDRESS))
throw new Error(`Invalid Relayer Address: ${RELAYER_ADDRESS}`);
const relayer = new Wallet(RELAYER_PRIVATE_KEY, provider);
RELAYER_ADDRESS = await relayer.getAddress();
}

const result = await contracts.deploy({
deploymentSigner: signer,
transactionChainConfig: {
forceInclusionPeriodSeconds: FORCE_INCLUSION_PERIOD_SECONDS,
sequencer: SEQUENCER_ADDRESS,
forceInclusionPeriodBlocks: Math.ceil(FORCE_INCLUSION_PERIOD_SECONDS/BLOCK_TIME_SECONDS),
},
stateChainConfig: {
fraudProofWindowSeconds: FRAUD_PROOF_WINDOW_SECONDS,
sequencerPublishWindowSeconds: SEQUENCER_PUBLISH_WINDOW_SECONDS,
},
ovmGlobalContext: {
ovmCHAINID: CHAIN_ID,
L2CrossDomainMessengerAddress: L2_CROSS_DOMAIN_MESSENGER_ADDRESS
},
l1CrossDomainMessengerConfig: {
relayerAddress: RELAYER_ADDRESS,
},
ovmGasMeteringConfig: {
minTransactionGasLimit: MIN_TRANSACTION_GAS_LIMIT,
maxTransactionGasLimit: MAX_TRANSACTION_GAS_LIMIT,
maxGasPerQueuePerEpoch: MAX_GAS_PER_QUEUE_PER_EPOCH,
secondsPerEpoch: SECONDS_PER_EPOCH
},
whitelistConfig: {
owner: WHITELIST_OWNER,
allowArbitraryContractDeployment: WHITELIST_ALLOW_ARBITRARY_CONTRACT_DEPLOYMENT
},
deployOverrides: {
gasLimit: DEPLOY_TX_GAS_LIMIT
},
waitForReceipts: WAIT_FOR_RECEIPTS,
addressManager: ADDRESS_MANAGER_ADDRESS,
});

const { failedDeployments, AddressManager } = result;
if (failedDeployments.length !== 0)
throw new Error(`Contract deployment failed: ${failedDeployments.join(',')}`);

const out = {};
out.AddressManager = AddressManager.address;
out.OVM_Sequencer = SEQUENCER_ADDRESS;
out.Deployer = await signer.getAddress()
for (const [name, contract] of Object.entries(result.contracts)) {
out[name] = contract.address;
}
console.log(JSON.stringify(out, null, 2));
})().catch(err => {
console.log(JSON.stringify({error: err.message, stack: err.stack}, null, 2));
process.exit(1);
});
65 changes: 65 additions & 0 deletions packages/contracts/bin/gen_safety_checker_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
# pip3 install pyevmasm
from pyevmasm import instruction_tables

#print(instruction_tables.keys())

def asm(x):
return [instruction_tables['istanbul'][i].opcode for i in x]

push_opcodes = asm(["PUSH%d" % i for i in range(1,33)])
stop_opcodes = asm(["STOP", "JUMP", "RETURN", "INVALID"])
caller_opcodes = asm(["CALLER"])
blacklist_ops = set([
"ADDRESS", "BALANCE", "BLOCKHASH",
"CALL", "CALLCODE", "CHAINID", "COINBASE",
"CREATE", "CREATE2", "DELEGATECALL", "DIFFICULTY",
"EXTCODESIZE", "EXTCODECOPY", "EXTCODEHASH",
"GASLIMIT", "GASPRICE", "NUMBER",
"ORIGIN", "REVERT", "SELFBALANCE", "SELFDESTRUCT",
"SLOAD", "SSTORE", "STATICCALL", "TIMESTAMP"])
whitelist_opcodes = []
for x in instruction_tables['istanbul']:
if x.name not in blacklist_ops:
whitelist_opcodes.append(x.opcode)

pushmask = 0
for x in push_opcodes:
pushmask |= 1 << x

stopmask = 0
for x in stop_opcodes:
stopmask |= 1 << x

stoplist = [0]*256
procmask = 0
for i in range(256):
if i in whitelist_opcodes and \
i not in push_opcodes and \
i not in stop_opcodes and \
i not in caller_opcodes:
# can skip this opcode
stoplist[i] = 1
else:
procmask |= 1 << i

# PUSH1 through PUSH4, can't skip in slow
for i in range(0x60, 0x64):
stoplist[i] = i-0x5e
rr = "uint256[8] memory opcodeSkippableBytes = [\n"
for i in range(0, 0x100, 0x20):
ret = "uint256(0x"
for j in range(i, i+0x20, 1):
ret += ("%02X" % stoplist[j])
rr += ret+"),\n"

rr = rr[:-2] + "];"

print(rr)
print("// Mask to gate opcode specific cases")
print("uint256 opcodeGateMask = ~uint256(0x%x);" % procmask)
print("// Halting opcodes")
print("uint256 opcodeHaltingMask = ~uint256(0x%x);" % stopmask)
print("// PUSH opcodes")
print("uint256 opcodePushMask = ~uint256(0x%x);" % pushmask)

Loading

0 comments on commit 788b4f2

Please sign in to comment.