Commit b9a47cbc authored by smartcontracts's avatar smartcontracts Committed by GitHub

Merge pull request #1349 from ethereum-optimism/develop

merge develop into master
parents fcc20ab3 48e3ab13
---
'@eth-optimism/l2geth': patch
---
Allow transactions via RPC to `address(0)`
---
'@eth-optimism/l2geth': patch
---
Removes `id` field from EVM and no longer logs the EVM execution id
---
'@eth-optimism/message-relayer': patch
---
Use latest contracts package for browser compatibility support
---
'@eth-optimism/replica-healthcheck': patch
---
Bug fix from leftover error during testing
---
'@eth-optimism/l2geth': patch
---
Style fix in the `RollupClient`
---
'@eth-optimism/l2geth': patch
---
Remove dead code in `blockchain.go` and `miner/worker.go`
---
'@eth-optimism/contracts': patch
---
Makes the contracts package browser compatible.
......@@ -50,56 +50,6 @@ jobs:
working-directory: ./ops
run: docker-compose run integration_tests
# Examples Tests
# - name: Test & deploy hardhat-example on Ethereum (regression)
# working-directory: ./examples/hardhat
# run: |
# yarn
# yarn deploy
# yarn test:integration
# - name: Test & deploy hardhat-example on Optimistic Ethereum
# working-directory: ./examples/hardhat
# run: |
# yarn deploy:ovm
# yarn test:integration:ovm
- name: Test & deploy waffle-example on Ethereum (regression)
working-directory: ./examples/waffle
run: |
yarn
yarn compile
yarn test:integration
- name: Test & deploy waffle-example on Optimistic Ethereum
working-directory: ./examples/waffle
run: |
yarn compile:ovm
yarn test:integration:ovm
- name: Test & deploy truffle-example on Ethereum (regression)
working-directory: ./examples/truffle
run: |
yarn
yarn compile
yarn test:integration
yarn deploy
- name: Test & deploy truffle-example on Optimistic Ethereum
working-directory: ./examples/truffle
run: |
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: |
# yarn
# yarn compile
# yarn compile:ovm
# yarn test:integration:ovm
- name: Collect docker logs on failure
if: failure()
uses: jwalton/gh-docker-logs@v1
......
......@@ -21,6 +21,7 @@ jobs:
message-relayer: ${{ steps.packages.outputs.message-relayer }}
data-transport-layer: ${{ steps.packages.outputs.data-transport-layer }}
contracts: ${{ steps.packages.outputs.contracts }}
replica-healthcheck: ${{ steps.packages.outputs.replica-healthcheck }}
canary-docker-tag: ${{ steps.docker-image-name.outputs.canary-docker-tag }}
steps:
......@@ -128,6 +129,7 @@ jobs:
data-transport-layer: ${{ needs.canary-publish.outputs.data-transport-layer }}
contracts: ${{ needs.canary-publish.outputs.contracts }}
integration-tests: ${{ needs.canary-publish.outputs.integration-tests }}
replica-healthcheck: ${{ needs.canary-publish.outputs.replica-healthcheck }}
canary-docker-tag: ${{ needs.canary-publish.outputs.canary-docker-tag }}
......@@ -280,3 +282,29 @@ jobs:
file: ./ops/docker/Dockerfile.integration-tests
push: true
tags: ethereumoptimism/integration-tests:${{ needs.builder.outputs.canary-docker-tag }}
replica-healthcheck:
name: Publish Data Transport Layer Version ${{ needs.builder.outputs.canary-docker-tag }}
needs: builder
if: needs.builder.outputs.replica-healthcheck != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.replica-healthcheck
push: true
tags: ethereumoptimism/replica-healthcheck:${{ needs.builder.outputs.canary-docker-tag }}
......@@ -18,6 +18,7 @@ jobs:
data-transport-layer: ${{ steps.packages.outputs.data-transport-layer }}
contracts: ${{ steps.packages.outputs.contracts }}
gas-oracle: ${{ steps.packages.outputs.gas-oracle }}
replica-healthcheck: ${{ steps.packages.outputs.replica-healthcheck }}
steps:
- name: Checkout Repo
......@@ -148,6 +149,7 @@ jobs:
data-transport-layer: ${{ needs.release.outputs.data-transport-layer }}
contracts: ${{ needs.release.outputs.contracts }}
integration-tests: ${{ needs.release.outputs.integration-tests }}
replica-healthcheck: ${{ needs.release.outputs.replica-healthcheck }}
steps:
- name: Checkout
......@@ -298,3 +300,29 @@ jobs:
file: ./ops/docker/Dockerfile.integration-tests
push: true
tags: ethereumoptimism/integration-tests:${{ needs.builder.outputs.integration-tests }},ethereumoptimism/integration-tests:latest
replica-healthcheck:
name: Publish Replica Healthcheck Version ${{ needs.builder.outputs.replica-healthcheck }}
needs: builder
if: needs.builder.outputs.replica-healthcheck != ''
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN_SECRET }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
file: ./ops/docker/Dockerfile.replica-healthcheck
push: true
tags: ethereumoptimism/replica-healthcheck:${{ needs.builder.outputs.replica-healthcheck }},ethereumoptimism/replica-healthcheck:latest
......@@ -3,12 +3,11 @@
**Please read our [general contributing guide](https://github.com/ethereum-optimism/.github/blob/master/CONTRIBUTING.md) before continuing**
These packages only require 1 reviewer (all other packages require 2 reviewers, unless the changes do not affect production or test code).
These packages only require 1 reviewer (all other packages require 2 reviewers, unless the changes do not affect production or test code).
- packages/smock
- packages/core-utils
- packages/hardhat-ovm
- packages/common-ts
- examples
- integration-tests
- integration-tests
(The MIT License)
Copyright 2020-2021 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.
# The Official™ Optimism Tutorial
[![Discord](https://img.shields.io/discord/667044843901681675.svg?color=768AD4&label=discord&logo=https%3A%2F%2Fdiscordapp.com%2Fassets%2F8c9701b98ad4372b58f13fd9f65f966e.svg)](https://discord.com/channels/667044843901681675)
[![Twitter Follow](https://img.shields.io/twitter/follow/optimismPBC.svg?label=optimismPBC&style=social)](https://twitter.com/optimismPBC)
### For the full README, please see the [guided repository of the `optimism-tutorial`](https://github.com/ethereum-optimism/optimism-tutorial) repository
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity >0.6.0 <0.8.0;
/**
* @title ERC20
* @dev A super simple ERC20 implementation!
*/
contract ERC20 {
/**********
* Events *
**********/
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
/*************
* Variables *
*************/
mapping (address => uint256) public balances;
mapping (address => mapping (address => uint256)) public allowances;
// Some optional extra goodies.
uint256 public totalSupply;
string public name;
/***************
* Constructor *
***************/
/**
* @param _initialSupply Initial maximum token supply.
* @param _name A name for our ERC20 (technically optional, but it's fun ok jeez).
*/
constructor(
uint256 _initialSupply,
string memory _name
)
public
{
balances[msg.sender] = _initialSupply;
totalSupply = _initialSupply;
name = _name;
}
/********************
* Public Functions *
********************/
/**
* Checks the balance of an address.
* @param _owner Address to check a balance for.
* @return Balance of the address.
*/
function balanceOf(
address _owner
)
external
view
returns (
uint256
)
{
return balances[_owner];
}
/**
* Transfers a balance from your account to someone else's account!
* @param _to Address to transfer a balance to.
* @param _amount Amount to transfer to the other account.
* @return true if the transfer was successful.
*/
function transfer(
address _to,
uint256 _amount
)
external
returns (
bool
)
{
require(
balances[msg.sender] >= _amount,
"You don't have enough balance to make this transfer!"
);
balances[msg.sender] -= _amount;
balances[_to] += _amount;
emit Transfer(
msg.sender,
_to,
_amount
);
return true;
}
/**
* Transfers a balance from someone else's account to another account. You need an allowance
* from the sending account for this to work!
* @param _from Account to transfer a balance from.
* @param _to Account to transfer a balance to.
* @param _amount Amount to transfer to the other account.
* @return true if the transfer was successful.
*/
function transferFrom(
address _from,
address _to,
uint256 _amount
)
external
returns (
bool
)
{
require(
balances[_from] >= _amount,
"Can't transfer from the desired account because it doesn't have enough balance."
);
require(
allowances[_from][msg.sender] >= _amount,
"Can't transfer from the desired account because you don't have enough of an allowance."
);
balances[_to] += _amount;
balances[_from] -= _amount;
emit Transfer(
_from,
_to,
_amount
);
return true;
}
/**
* Approves an account to spend some amount from your account.
* @param _spender Account to approve a balance for.
* @param _amount Amount to allow the account to spend from your account.
* @return true if the allowance was successful.
*/
function approve(
address _spender,
uint256 _amount
)
external
returns (
bool
)
{
allowances[msg.sender][_spender] = _amount;
emit Approval(
msg.sender,
_spender,
_amount
);
return true;
}
/**
* Checks how much a given account is allowed to spend from another given account.
* @param _owner Address of the account to check an allowance from.
* @param _spender Address of the account trying to spend from the owner.
* @return Allowance for the spender from the owner.
*/
function allowance(
address _owner,
address _spender
)
external
view
returns (
uint256
)
{
return allowances[_owner][_spender];
}
}
// Just a standard hardhat-deploy deployment definition file!
const func = async (hre) => {
const { deployments, getNamedAccounts } = hre
const { deploy } = deployments
const { deployer } = await getNamedAccounts()
const initialSupply = 1000000
const name = 'My Optimistic Token'
await deploy('ERC20', {
from: deployer,
args: [initialSupply, name],
log: true
})
}
func.tags = ['ERC20']
module.exports = func
require('@nomiclabs/hardhat-ethers')
require('@nomiclabs/hardhat-waffle')
require('hardhat-deploy')
require('@eth-optimism/hardhat-ovm')
module.exports = {
networks: {
// Add this network to your config!
optimism: {
url: 'http://127.0.0.1:8545',
// instantiate with a mnemonic so that you have >1 accounts available
accounts: {
mnemonic: 'test test test test test test test test test test test junk'
},
// This sets the gas price to 0 for all transactions on L2. We do this
// because account balances are not automatically initiated with an ETH
// balance (yet, sorry!).
gasPrice: 0,
ovm: true // This sets the network as using the ovm and ensure contract will be compiled against that.
},
},
solidity: '0.7.6',
ovm: {
solcVersion: '0.7.6'
},
namedAccounts: {
deployer: 0
},
}
{
"name": "@eth-optimism/hardhat-example",
"private": true,
"version": "1.0.0",
"main": "index.js",
"author": "Optimism PBC",
"license": "MIT",
"scripts": {
"clean": "rimraf ./cache-ovm ./cache ./artifacts-ovm ./artifacts ./deployments",
"compile": "hardhat compile",
"compile:ovm": "hardhat compile --network optimism",
"test:integration": "hardhat test",
"test:integration:ovm": "hardhat test --network optimism",
"deploy": "hardhat deploy",
"deploy:ovm": "hardhat deploy --network optimism"
},
"devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.1",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@types/chai": "4.2.17",
"@types/mocha": "^8.2.2",
"chai": "4.3.4",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.1.4",
"hardhat": "^2.2.0",
"hardhat-deploy": "^0.7.5",
"mocha": "^8.2.1"
},
"dependencies": {
"@eth-optimism/hardhat-ovm": "^0.2.0"
}
}
/* External Imports */
const { ethers, network } = require('hardhat')
const chai = require('chai')
const { solidity } = require('ethereum-waffle')
const { expect } = chai
chai.use(solidity)
describe(`ERC20`, () => {
const INITIAL_SUPPLY = 1000000
const TOKEN_NAME = 'An Optimistic ERC20'
let account1
let account2
before(`load accounts`, async () => {
;[ account1, account2 ] = await ethers.getSigners()
})
let ERC20
beforeEach(`deploy ERC20 contract`, async () => {
const Factory__ERC20 = await ethers.getContractFactory('ERC20')
ERC20 = await Factory__ERC20.connect(account1).deploy(
INITIAL_SUPPLY,
TOKEN_NAME
)
await ERC20.deployTransaction.wait()
})
it(`should have a name`, async () => {
const tokenName = await ERC20.name()
expect(tokenName).to.equal(TOKEN_NAME)
})
it(`should have a total supply equal to the initial supply`, async () => {
const tokenSupply = await ERC20.totalSupply()
expect(tokenSupply).to.equal(INITIAL_SUPPLY)
})
it(`should give the initial supply to the creator's address`, async () => {
const balance = await ERC20.balanceOf(await account1.getAddress())
expect(balance).to.equal(INITIAL_SUPPLY)
})
describe(`transfer(...)`, () => {
it(`should revert when the sender does not have enough balance`, async () => {
const tx = ERC20.connect(account1).transfer(
await account2.getAddress(),
INITIAL_SUPPLY + 1
)
await expect(tx).to.be.revertedWith("You don't have enough balance to make this transfer!")
})
it(`should succeed when the sender has enough balance`, async () => {
const tx = await ERC20.connect(account1).transfer(
await account2.getAddress(),
INITIAL_SUPPLY
)
await tx.wait()
expect(
(await ERC20.balanceOf(
await account1.getAddress()
)).toNumber()
).to.equal(0)
expect(
(await ERC20.balanceOf(
await account2.getAddress()
)).toNumber()
).to.equal(INITIAL_SUPPLY)
})
})
describe(`transferFrom(...)`, () => {
it(`should revert when the sender does not have enough of an allowance`, async () => {
const tx = ERC20.connect(account2).transferFrom(
await account1.getAddress(),
await account2.getAddress(),
INITIAL_SUPPLY
)
await expect(tx).to.be.revertedWith("Can't transfer from the desired account because you don't have enough of an allowance.")
})
it(`should succeed when the owner has enough balance and the sender has a large enough allowance`, async () => {
const tx1 = await ERC20.connect(account1).approve(
await account2.getAddress(),
INITIAL_SUPPLY
)
await tx1.wait()
const tx2 = await ERC20.connect(account2).transferFrom(
await account1.getAddress(),
await account2.getAddress(),
INITIAL_SUPPLY
)
await tx2.wait()
expect(
(await ERC20.balanceOf(
await account1.getAddress()
)).toNumber()
).to.equal(0)
expect(
(await ERC20.balanceOf(
await account2.getAddress()
)).toNumber()
).to.equal(INITIAL_SUPPLY)
})
})
})
# Packages
node_modules/
# Hardhat build outputs
artifacts/
artifacts-ovm/
cache/
cache-ovm/
optimism
.env
\ No newline at end of file
# L1/L2 ERC20 Deposit + Withdrawal Example
### For the full README, please see the [guided repository of `l1-l2-deposit-withdrawal`](https://github.com/ethereum-optimism/l1-l2-deposit-withdrawal)
\ No newline at end of file
// SPDX-License-Identifier: MIT
pragma solidity >0.6.0 <0.8.0;
/**
* @title ERC20
* @dev A super simple ERC20 implementation! Also *very* insecure. Do not use in prod.
*/
contract ERC20 {
/**********
* Events *
**********/
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
/*************
* Variables *
*************/
mapping (address => uint256) public balances;
mapping (address => mapping (address => uint256)) public allowances;
// Some optional extra goodies.
uint256 public totalSupply;
string public name;
/***************
* Constructor *
***************/
/**
* @param _initialSupply Initial maximum token supply.
* @param _name A name for our ERC20 (technically optional, but it's fun ok jeez).
*/
constructor(
uint256 _initialSupply,
string memory _name
)
public
{
balances[msg.sender] = _initialSupply;
totalSupply = _initialSupply;
name = _name;
}
/********************
* Public Functions *
********************/
/**
* Checks the balance of an address.
* @param _owner Address to check a balance for.
* @return Balance of the address.
*/
function balanceOf(
address _owner
)
external
view
returns (
uint256
)
{
return balances[_owner];
}
/**
* Transfers a balance from your account to someone else's account!
* @param _to Address to transfer a balance to.
* @param _amount Amount to transfer to the other account.
* @return true if the transfer was successful.
*/
function transfer(
address _to,
uint256 _amount
)
external
returns (
bool
)
{
require(
balances[msg.sender] >= _amount,
"You don't have enough balance to make this transfer!"
);
balances[msg.sender] -= _amount;
balances[_to] += _amount;
emit Transfer(
msg.sender,
_to,
_amount
);
return true;
}
/**
* Transfers a balance from someone else's account to another account. You need an allowance
* from the sending account for this to work!
* @param _from Account to transfer a balance from.
* @param _to Account to transfer a balance to.
* @param _amount Amount to transfer to the other account.
* @return true if the transfer was successful.
*/
function transferFrom(
address _from,
address _to,
uint256 _amount
)
external
returns (
bool
)
{
require(
balances[_from] >= _amount,
"Can't transfer from the desired account because it doesn't have enough balance."
);
require(
allowances[_from][msg.sender] >= _amount,
"Can't transfer from the desired account because you don't have enough of an allowance."
);
balances[_to] += _amount;
balances[_from] -= _amount;
emit Transfer(
_from,
_to,
_amount
);
return true;
}
/**
* Approves an account to spend some amount from your account.
* @param _spender Account to approve a balance for.
* @param _amount Amount to allow the account to spend from your account.
* @return true if the allowance was successful.
*/
function approve(
address _spender,
uint256 _amount
)
external
returns (
bool
)
{
allowances[msg.sender][_spender] = _amount;
emit Approval(
msg.sender,
_spender,
_amount
);
return true;
}
/**
* Checks how much a given account is allowed to spend from another given account.
* @param _owner Address of the account to check an allowance from.
* @param _spender Address of the account trying to spend from the owner.
* @return Allowance for the spender from the owner.
*/
function allowance(
address _owner,
address _spender
)
external
view
returns (
uint256
)
{
return allowances[_owner][_spender];
}
/**
* Internal minting function.
* @param _who Address to mint tokens for.
* @param _amount Number of tokens to mint.
*/
function _mint(
address _who,
uint256 _amount
)
internal
{
totalSupply += _amount;
balances[_who] += _amount;
emit Transfer(address(0), _who, _amount);
}
/**
* Internal burning function.
* @param _who Address to burn tokens from.
* @param _amount Number of tokens to burn.
*/
function _burn(
address _who,
uint256 _amount
)
internal
{
require(
totalSupply >= _amount,
"Can't burn more than total supply."
);
require(
balances[_who] >= _amount,
"Account does not have enough to burn."
);
totalSupply -= _amount;
balances[_who] -= _amount;
emit Transfer(_who, address(0), _amount);
}
}
// SPDX-License-Identifier: MIT LICENSE
pragma solidity >0.5.0 <0.8.0;
pragma experimental ABIEncoderV2;
/* Contract Imports */
import { ERC20 } from "./ERC20.sol";
/* Library Imports */
import {
Abs_L2DepositedToken
} from "@eth-optimism/contracts/OVM/bridge/tokens/Abs_L2DepositedToken.sol";
/**
* @title L2DepositedERC20
* @dev An L2 Deposited ERC20 is an ERC20 implementation which represents L1 assets deposited into L2, minting and burning on
* deposits and withdrawals.
*
* `L2DepositedERC20` uses the Abs_L2DepositedToken class provided by optimism to link into a standard L1 deposit contract
* while using the `ERC20`implementation I as a developer want to use.
*
* Compiler used: optimistic-solc
* Runtime target: OVM
*/
contract L2DepositedERC20 is Abs_L2DepositedToken, ERC20 {
/**
* @param _l2CrossDomainMessenger Address of the L2 cross domain messenger.
* @param _name Name for the ERC20 token.
*/
constructor(
address _l2CrossDomainMessenger,
string memory _name
)
Abs_L2DepositedToken(_l2CrossDomainMessenger)
ERC20(0, _name)
{}
/**
* Handler that gets called when a withdrawal is initiated.
* @param _to Address triggering the withdrawal.
* @param _amount Amount being withdrawn.
*/
function _handleInitiateWithdrawal(
address _to,
uint256 _amount
)
internal
override
{
_burn(msg.sender, _amount);
}
/**
* Handler that gets called when a deposit is received.
* @param _to Address receiving the deposit.
* @param _amount Amount being deposited.
*/
function _handleFinalizeDeposit(
address _to,
uint256 _amount
)
internal
override
{
_mint(_to, _amount);
}
}
// Plugins
require('@nomiclabs/hardhat-ethers')
require('@nomiclabs/hardhat-waffle')
require('@eth-optimism/hardhat-ovm')
module.exports = {
networks: {
// Add this network to your config!
optimism: {
url: 'http://127.0.0.1:8545',
// This sets the gas price to 0 for all transactions on L2. We do this
// because account balances are not automatically initiated with an ETH
// balance.
gasPrice: 0,
ovm: true // This sets the network as using the ovm and ensure contract will be compiled against that.
},
},
solidity: '0.7.6',
ovm: {
solcVersion: '0.7.6'
},
mocha: {
timeout: 60000
}
}
{
"name": "l1-l2-deposit-withdrawal",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"clean": "rimraf ./cache ./artifacts ./cache-ovm ./artifacts-ovm",
"compile": "hardhat compile",
"compile:ovm": "hardhat compile --network optimism",
"test:integration:ovm": "yarn hardhat test --network optimism"
},
"devDependencies": {
"@eth-optimism/contracts": "^0.3.0",
"@eth-optimism/core-utils": "^0.4.2",
"@eth-optimism/hardhat-ovm": "^0.2.0",
"@eth-optimism/watcher": "^0.0.1-alpha.9",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"chai": "^4.3.4",
"ethereum-waffle": "^3.3.0",
"ethers": "^5.1.4",
"hardhat": "^2.2.1",
"mocha": "^8.4.0",
"rimraf": "^3.0.2"
}
}
/* External Imports */
const { ethers } = require('hardhat')
const { expect } = require('chai')
const { Watcher } = require('@eth-optimism/watcher')
const { getContractFactory } = require('@eth-optimism/contracts')
/* Internal Imports */
const factory = (name, ovm = false) => {
const artifact = require(`../artifacts${ovm ? '-ovm' : ''}/contracts/${name}.sol/${name}.json`)
return new ethers.ContractFactory(artifact.abi, artifact.bytecode)
}
const factory__L1_ERC20 = factory('ERC20')
const factory__L2_ERC20 = factory('L2DepositedERC20', true)
const factory__L1StandardBridge = getContractFactory('OVM_L1StandardBridge')
describe(`L1 <> L2 Deposit and Withdrawal`, () => {
// Set up our RPC provider connections.
const l1RpcProvider = new ethers.providers.JsonRpcProvider('http://127.0.0.1:9545')
const l2RpcProvider = new ethers.providers.JsonRpcProvider('http://127.0.0.1:8545')
// Constructor arguments for `ERC20.sol`
const INITIAL_SUPPLY = 1234
const L1_ERC20_NAME = 'L1 ERC20'
// L1 messenger address depends on the deployment, this is default for our local deployment.
const l1MessengerAddress = '0x59b670e9fA9D0A427751Af201D676719a970857b'
// L2 messenger address is always the same.
const l2MessengerAddress = '0x4200000000000000000000000000000000000007'
const L2_ERC20_NAME = 'L2 ERC20'
// Set up our wallets (using a default private key with 10k ETH allocated to it).
// Need two wallets objects, one for interacting with L1 and one for interacting with L2.
// Both will use the same private key.
const key = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
const l1Wallet = new ethers.Wallet(key, l1RpcProvider)
const l2Wallet = new ethers.Wallet(key, l2RpcProvider)
// Tool that helps watches and waits for messages to be relayed between L1 and L2.
const watcher = new Watcher({
l1: {
provider: l1RpcProvider,
messengerAddress: l1MessengerAddress
},
l2: {
provider: l2RpcProvider,
messengerAddress: l2MessengerAddress
}
})
let L1_ERC20,
L2_ERC20,
L1StandardBridge
before(`deploy contracts`, async () => {
// Deploy an ERC20 token on L1.
L1_ERC20 = await factory__L1_ERC20.connect(l1Wallet).deploy(
INITIAL_SUPPLY,
L1_ERC20_NAME,
{
gasPrice: 0
}
)
await L1_ERC20.deployTransaction.wait()
// Deploy the paired ERC20 token to L2.
L2_ERC20 = await factory__L2_ERC20.connect(l2Wallet).deploy(
l2MessengerAddress,
L2_ERC20_NAME,
{
gasPrice: 0
}
)
await L2_ERC20.deployTransaction.wait()
// Create a bridge that connects the two contracts.
L1StandardBridge = await factory__L1StandardBridge.connect(l1Wallet).deploy(
L1_ERC20.address,
L2_ERC20.address,
l1MessengerAddress,
{
gasPrice: 0
}
)
await L1StandardBridge.deployTransaction.wait()
})
describe('Initialization and initial balances', async () => {
it(`should initialize L2 ERC20`, async () => {
const tx = await L2_ERC20.init(L1StandardBridge.address, { gasPrice: 0 })
await tx.wait()
const txHashPrefix = tx.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x')
})
it(`should have initial L1 balance of 1234 and initial L2 balance of 0`, async () => {
const l1Balance = await L1_ERC20.balanceOf(l1Wallet.address)
const l2Balance = await L2_ERC20.balanceOf(l1Wallet.address)
expect(l1Balance).to.eq(1234)
expect(l2Balance).to.eq(0)
})
})
describe('L1 to L2 deposit', async () => {
let l1Tx1
it(`should approve 1234 tokens for ERC20 bridge`, async () => {
const tx = await L1_ERC20.approve(L1StandardBridge.address, 1234)
await tx.wait()
const txHashPrefix = tx.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x')
})
it(`should deposit 1234 tokens into L2 ERC20`, async () => {
l1Tx1 = await L1StandardBridge.deposit(1234, { gasPrice: 0 })
await l1Tx1.wait()
const txHashPrefix = l1Tx1.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x')
})
it(`should relay deposit message to L2`, async () => {
// Wait for the message to be relayed to L2.
const [ msgHash1 ] = await watcher.getMessageHashesFromL1Tx(l1Tx1.hash)
const l2TxReceipt = await watcher.getL2TransactionReceipt(msgHash1)
expect(l2TxReceipt.to).to.eq(l2MessengerAddress)
})
it(`should have changed L1 balance to 0 and L2 balance to 1234`, async () => {
const l1Balance = await L1_ERC20.balanceOf(l1Wallet.address)
const l2Balance = await L2_ERC20.balanceOf(l1Wallet.address)
expect(l1Balance).to.eq(0)
expect(l2Balance).to.eq(1234)
})
})
describe('L2 to L1 withdrawal', async () => {
let l2Tx1
it(`should withdraw tokens back to L1 ERC20 and relay the message`, async () => {
// Burn the tokens on L2 and ask the L1 contract to unlock on our behalf.
l2Tx1 = await L2_ERC20.withdraw(1234, { gasPrice: 0 })
await l2Tx1.wait()
const txHashPrefix = l2Tx1.hash.slice(0, 2)
expect(txHashPrefix).to.eq('0x')
})
it(`should relay withdrawal message to L1`, async () => {
const [ msgHash2 ] = await watcher.getMessageHashesFromL2Tx(l2Tx1.hash)
const l1TxReceipt = await watcher.getL1TransactionReceipt(msgHash2)
expect(l1TxReceipt.to).to.eq(l1MessengerAddress)
})
it(`should have changed L1 balance back to 1234 and L2 balance back to 0`, async () => {
const l1Balance = await L1_ERC20.balanceOf(l1Wallet.address)
const l2Balance = await L2_ERC20.balanceOf(l1Wallet.address)
expect(l1Balance).to.eq(1234)
expect(l2Balance).to.eq(0)
})
})
})
# Project specific
build
build-ovm
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and *not* Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
.DS_Store
build/
(The MIT License)
Copyright 2020-2021 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.
# Getting Started with Optimistic Ethereum: Simple ERC20 Token Truffle Tutorial
### For the full README, please see the [guided repository, `Truffle-ER20-Example`](https://github.com/ethereum-optimism/Truffle-ERC20-Example)
\ No newline at end of file
// SPDX-License-Identifier: MIT LICENSE
/* Implements ERC20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md */
pragma solidity ^0.7.6;
import "./IERC20.sol";
contract ERC20 is IERC20 {
uint256 private constant MAX_UINT256 = 2**256 - 1;
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowed;
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name;
uint8 public decimals;
string public symbol;
uint256 public totalSupply;
constructor(
uint256 _initialAmount,
string memory _tokenName,
uint8 _decimalUnits,
string memory _tokenSymbol
) {
balances[msg.sender] = _initialAmount; // Give the creator all initial tokens
totalSupply = _initialAmount; // Update total supply
name = _tokenName; // Set the name for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
}
function transfer(address _to, uint256 _value)
public
override
returns (bool success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars
return true;
}
function transferFrom(
address _from,
address _to,
uint256 _value
) public override returns (bool success) {
uint256 allowance_ = allowed[_from][msg.sender];
require(balances[_from] >= _value && allowance_ >= _value);
balances[_to] += _value;
balances[_from] -= _value;
if (allowance_ < MAX_UINT256) {
allowed[_from][msg.sender] -= _value;
}
emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars
return true;
}
function balanceOf(address _owner)
public
view
override
returns (uint256 balance)
{
return balances[_owner];
}
function approve(address _spender, uint256 _value)
public
override
returns (bool success)
{
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars
return true;
}
function allowance(address _owner, address _spender)
public
view
override
returns (uint256 remaining)
{
return allowed[_owner][_spender];
}
}
// SPDX-License-Identifier: MIT LICENSE
// Abstract contract for the full ERC20 Token standard
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
pragma solidity ^0.7.6;
interface IERC20 {
/// @param _owner The address from which the balance will be retrieved
/// @return balance The balance
function balanceOf(address _owner) external view returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transfer(address _to, uint256 _value)
external
returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transferFrom(
address _from,
address _to,
uint256 _value
) external returns (bool success);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return success Whether the approval was successful or not
function approve(address _spender, uint256 _value)
external
returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return remaining Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender)
external
view
returns (uint256 remaining);
// solhint-disable-next-line no-simple-event-func-name
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
}
const ERC20 = artifacts.require('ERC20')
module.exports = function (deployer, accounts) {
const tokenName = 'My Optimistic Coin'
const tokenSymbol = 'OPT'
const tokenDecimals = 1
// deployment steps
deployer.deploy(
ERC20,
10000,
tokenName,
tokenDecimals,
tokenSymbol,
{ gasPrice: 0 }
)
}
{
"name": "@ethereum-optimism/Truffle-ERC20-Example",
"private": true,
"version": "1.0.0-alpha.1",
"description": "Example of using Optimistic Ethereum compiler & local Optimistic Ethereum nodes with Truffle to run a full ERC20 test suite",
"scripts": {
"clean": "rimraf build build-ovm",
"compile": "truffle compile",
"compile:ovm": "truffle compile --config truffle-config-ovm.js",
"test:integration": "truffle test",
"test:integration:ovm": "truffle test --network optimism --config truffle-config-ovm.js",
"deploy": "truffle migrate --network ethereum --config truffle-config",
"deploy:ovm": "truffle migrate --network optimism --config truffle-config-ovm.js"
},
"keywords": [
"optimism",
"rollup",
"optimistic",
"ethereum",
"truffle",
"ovm",
"example",
"ERC20",
"token"
],
"homepage": "https://github.com/ethereum-optimism/Truffle-ERC20-Example#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/Truffle-ERC20-Example.git"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@eth-optimism/solc": "0.7.6-alpha.1",
"rimraf": "^3.0.2",
"truffle": "^5.3.6",
"@truffle/hdwallet-provider": "^1.4.0"
}
}
\ No newline at end of file
let token
const ERC20 = artifacts.require('ERC20')
contract('ERC20', (accounts) => {
const tokenName = 'My Optimistic Coin'
const tokenSymbol = 'OPT'
const tokenDecimals = 1
beforeEach(async () => {
token = await ERC20.new(10000, tokenName, tokenDecimals, tokenSymbol, { from: accounts[ 0 ], gasPrice: 0 })
})
it('creation: should create an initial balance of 10000 for the creator', async () => {
const balance = await token.balanceOf.call(accounts[ 0 ], {
gasPrice: 0
})
assert.strictEqual(balance.toNumber(), 10000)
})
it('creation: test correct setting of vanity information', async () => {
const name = await token.name.call()
assert.strictEqual(name, tokenName)
const decimals = await token.decimals.call()
assert.strictEqual(decimals.toNumber(), tokenDecimals)
const symbol = await token.symbol.call()
assert.strictEqual(symbol, tokenSymbol)
})
it('creation: should succeed in creating over 2^256 - 1 (max) tokens', async () => {
// 2^256 - 1
const token2 = await ERC20.new('115792089237316195423570985008687907853269984665640564039457584007913129639935', 'Simon Bucks', 1, 'SBX', { from: accounts[ 0 ], gasPrice: 0 })
const totalSupply = await token2.totalSupply()
assert.strictEqual(totalSupply.toString(), '115792089237316195423570985008687907853269984665640564039457584007913129639935')
})
// TRANSERS
// normal transfers without approvals
it('transfers: ether transfer should be reversed.', async () => {
const balanceBefore = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balanceBefore.toNumber(), 10000)
let threw = false
try {
await web3.eth.sendTransaction({ from: accounts[ 0 ], to: token.address, value: web3.utils.toWei('10', 'Ether'), gasPrice: 0 })
} catch (e) {
threw = true
}
assert.equal(threw, true)
const balanceAfter = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balanceAfter.toNumber(), 10000)
})
it('transfers: should transfer 10000 to accounts[1] with accounts[0] having 10000', async () => {
await token.transfer(accounts[ 1 ], 10000, { from: accounts[ 0 ], gasPrice: 0 })
const balance = await token.balanceOf.call(accounts[ 1 ])
assert.strictEqual(balance.toNumber(), 10000)
})
it('transfers: should fail when trying to transfer 10001 to accounts[1] with accounts[0] having 10000', async () => {
let threw = false
try {
await token.transfer.call(accounts[ 1 ], 10001, { from: accounts[ 0 ], gasPrice: 0 })
} catch (e) {
threw = true
}
assert.equal(threw, true)
})
it('transfers: should handle zero-transfers normally', async () => {
assert(await token.transfer.call(accounts[ 1 ], 0, { from: accounts[ 0 ], gasPrice: 0 }), 'zero-transfer has failed')
})
// NOTE: testing uint256 wrapping is impossible since you can't supply > 2^256 -1
// todo: transfer max amounts
// APPROVALS
it('approvals: msg.sender should approve 100 to accounts[1]', async () => {
await token.approve(accounts[ 1 ], 100, { from: accounts[ 0 ], gasPrice: 0 })
const allowance = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance.toNumber(), 100)
})
// bit overkill. But is for testing a bug
it('approvals: msg.sender approves accounts[1] of 100 & withdraws 20 once.', async () => {
const balance0 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance0.toNumber(), 10000)
await token.approve(accounts[ 1 ], 100, { from: accounts[ 0 ], gasPrice: 0 }) // 100
const balance2 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance2.toNumber(), 0, 'balance2 not correct')
await token.transferFrom.call(accounts[ 0 ], accounts[ 2 ], 20, { from: accounts[ 1 ], gasPrice: 0 })
await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
await token.transferFrom(accounts[ 0 ], accounts[ 2 ], 20, { from: accounts[ 1 ], gasPrice: 0 }) // -20
const allowance01 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance01.toNumber(), 80) // =80
const balance22 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance22.toNumber(), 20)
const balance02 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance02.toNumber(), 9980)
})
// should approve 100 of msg.sender & withdraw 50, twice. (should succeed)
it('approvals: msg.sender approves accounts[1] of 100 & withdraws 20 twice.', async () => {
await token.approve(accounts[ 1 ], 100, { from: accounts[ 0 ], gasPrice: 0 })
const allowance01 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance01.toNumber(), 100)
await token.transferFrom(accounts[ 0 ], accounts[ 2 ], 20, { from: accounts[ 1 ], gasPrice: 0 })
const allowance012 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance012.toNumber(), 80)
const balance2 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance2.toNumber(), 20)
const balance0 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance0.toNumber(), 9980)
// FIRST tx done.
// onto next.
await token.transferFrom(accounts[ 0 ], accounts[ 2 ], 20, { from: accounts[ 1 ], gasPrice: 0 })
const allowance013 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance013.toNumber(), 60)
const balance22 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance22.toNumber(), 40)
const balance02 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance02.toNumber(), 9960)
})
// should approve 100 of msg.sender & withdraw 50 & 60 (should fail).
it('approvals: msg.sender approves accounts[1] of 100 & withdraws 50 & 60 (2nd tx should fail)', async () => {
await token.approve(accounts[ 1 ], 100, { from: accounts[ 0 ], gasPrice: 0 })
const allowance01 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance01.toNumber(), 100)
await token.transferFrom(accounts[ 0 ], accounts[ 2 ], 50, { from: accounts[ 1 ], gasPrice: 0 })
const allowance012 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance012.toNumber(), 50)
const balance2 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance2.toNumber(), 50)
const balance0 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance0.toNumber(), 9950)
// FIRST tx done.
// onto next.
let threw = false
try {
await token.transferFrom.call(accounts[ 0 ], accounts[ 2 ], 60, { from: accounts[ 1 ], gasPrice: 0 })
} catch (e) {
threw = true
}
assert.equal(threw, true)
})
it('approvals: attempt withdrawal from account with no allowance (should fail)', async () => {
let threw = false
try {
await token.transferFrom.call(accounts[ 0 ], accounts[ 2 ], 60, { from: accounts[ 1 ], gasPrice: 0 })
} catch (e) {
threw = true
}
assert.equal(threw, true)
})
it('approvals: allow accounts[1] 100 to withdraw from accounts[0]. Withdraw 60 and then approve 0 & attempt transfer.', async () => {
await token.approve(accounts[ 1 ], 100, { from: accounts[ 0 ], gasPrice: 0 })
await token.transferFrom(accounts[ 0 ], accounts[ 2 ], 60, { from: accounts[ 1 ], gasPrice: 0 })
await token.approve(accounts[ 1 ], 0, { from: accounts[ 0 ], gasPrice: 0 })
let threw = false
try {
await token.transferFrom.call(accounts[ 0 ], accounts[ 2 ], 10, { from: accounts[ 1 ], gasPrice: 0 })
} catch (e) {
threw = true
}
assert.equal(threw, true)
})
it('approvals: approve max (2^256 - 1)', async () => {
await token.approve(accounts[ 1 ], '115792089237316195423570985008687907853269984665640564039457584007913129639935', { from: accounts[ 0 ], gasPrice: 0 })
const allowance = await token.allowance(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance.toString(), '115792089237316195423570985008687907853269984665640564039457584007913129639935')
})
// should approve max of msg.sender & withdraw 20 without changing allowance (should succeed).
it('approvals: msg.sender approves accounts[1] of max (2^256 - 1) & withdraws 20', async () => {
const balance0 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance0.toNumber(), 10000)
const max = '115792089237316195423570985008687907853269984665640564039457584007913129639935'
await token.approve(accounts[ 1 ], max, { from: accounts[ 0 ], gasPrice: 0 })
const balance2 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance2.toNumber(), 0, 'balance2 not correct')
await token.transferFrom(accounts[ 0 ], accounts[ 2 ], 20, { from: accounts[ 1 ], gasPrice: 0 })
const allowance01 = await token.allowance.call(accounts[ 0 ], accounts[ 1 ])
assert.strictEqual(allowance01.toString(), max)
const balance22 = await token.balanceOf.call(accounts[ 2 ])
assert.strictEqual(balance22.toNumber(), 20)
const balance02 = await token.balanceOf.call(accounts[ 0 ])
assert.strictEqual(balance02.toNumber(), 9980)
})
it('events: should fire Transfer event properly', async () => {
const res = await token.transfer(accounts[ 1 ], '2666', { from: accounts[ 0 ], gasPrice: 0 })
const transferLog = res.logs.find(
element => element.event.match('Transfer') &&
element.address.match(token.address)
)
assert.strictEqual(transferLog.args._from, accounts[ 0 ])
// L2 ETH transfer also emits a transfer event
assert.strictEqual(transferLog.args._to, accounts[ 1 ])
assert.strictEqual(transferLog.args._value.toString(), '2666')
})
it('events: should fire Transfer event normally on a zero transfer', async () => {
const res = await token.transfer(accounts[ 1 ], '0', { from: accounts[ 0 ], gasPrice: 0 })
const transferLog = res.logs.find(
element => element.event.match('Transfer') &&
element.address.match(token.address)
)
assert.strictEqual(transferLog.args._from, accounts[ 0 ])
assert.strictEqual(transferLog.args._to, accounts[ 1 ])
assert.strictEqual(transferLog.args._value.toString(), '0')
})
it('events: should fire Approval event properly', async () => {
const res = await token.approve(accounts[ 1 ], '2666', { from: accounts[ 0 ], gasPrice: 0 })
const approvalLog = res.logs.find(element => element.event.match('Approval'))
assert.strictEqual(approvalLog.args._owner, accounts[ 0 ])
assert.strictEqual(approvalLog.args._spender, accounts[ 1 ])
assert.strictEqual(approvalLog.args._value.toString(), '2666')
})
})
const mnemonicPhrase = "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat"
const HDWalletProvider = require('@truffle/hdwallet-provider')
module.exports = {
contracts_build_directory: './build-ovm',
networks: {
optimism: {
provider: function () {
return new HDWalletProvider({
mnemonic: {
phrase: mnemonicPhrase
},
providerOrUrl: 'http://127.0.0.1:8545'
})
},
network_id: 420,
host: '127.0.0.1',
port: 8545,
gasPrice: 0,
gas: 54180127,
}
},
compilers: {
solc: {
// Add path to the optimism solc fork
version: './node_modules/@eth-optimism/solc',
settings: {
optimizer: {
enabled: true,
runs: 1
},
}
}
}
}
module.exports = {
contracts_build_directory: './build',
networks: {
ethereum: {
network_id: 31337,
host: '127.0.0.1',
port: 9545,
gasPrice: 0,
},
},
// Configure your compilers
compilers: {
solc: {
version: "0.7.6", // Fetch exact version from solc-bin (default: truffle's version)
}
}
}
../../.prettierrc.json
\ No newline at end of file
(The MIT License)
Copyright 2020-2021 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.
# Getting Started with the Optimistic Ethereum: Simple ERC20 Token Waffle Tutorial
### For the full README, please see the [guided repository, `Waffle-ERC20-Example`](https://github.com/ethereum-optimism/Waffle-ERC20-Example)
\ No newline at end of file
// SPDX-License-Identifier: MIT LICENSE
/*
Implements ERC20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
.*/
pragma solidity ^0.7.6;
import "./IERC20.sol";
contract ERC20 is IERC20 {
uint256 private constant MAX_UINT256 = 2**256 - 1;
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowed;
/*
NOTE:
The following variables are OPTIONAL vanities. One does not have to include them.
They allow one to customise the token contract & in no way influences the core functionality.
Some wallets/interfaces might not even bother to look at this information.
*/
string public name; //fancy name: eg OVM Coin
uint8 public decimals; //How many decimals to show.
string public symbol; //An identifier: eg OVM
uint256 public override totalSupply;
constructor(
uint256 _initialAmount,
string memory _tokenName,
uint8 _decimalUnits,
string memory _tokenSymbol
) {
balances[msg.sender] = _initialAmount; // Give the creator all initial tokens
totalSupply = _initialAmount; // Update total supply
name = _tokenName; // Set the name for display purposes
decimals = _decimalUnits; // Amount of decimals for display purposes
symbol = _tokenSymbol; // Set the symbol for display purposes
}
function transfer(address _to, uint256 _value)
external
override
returns (bool success)
{
require(balances[msg.sender] >= _value);
balances[msg.sender] -= _value;
balances[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(
address _from,
address _to,
uint256 _value
) external override returns (bool success) {
uint256 allowance_ = allowed[_from][msg.sender];
require(balances[_from] >= _value && allowance_ >= _value);
balances[_to] += _value;
balances[_from] -= _value;
if (allowance_ < MAX_UINT256) {
allowed[_from][msg.sender] -= _value;
}
emit Transfer(_from, _to, _value);
return true;
}
function balanceOf(address _owner)
external
view
override
returns (uint256 balance)
{
return balances[_owner];
}
function approve(address _spender, uint256 _value)
external
override
returns (bool success)
{
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender)
external
view
override
returns (uint256 remaining)
{
return allowed[_owner][_spender];
}
}
// SPDX-License-Identifier: MIT LICENSE
// Abstract contract for the full ERC 20 Token standard
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
pragma solidity ^0.7.6;
interface IERC20 {
/* This is a slight change to the ERC20 base standard.
function totalSupply() constant returns (uint256 supply);
is replaced with:
uint256 public totalSupply;
This automatically creates a getter function for the totalSupply.
This is moved to the base contract since public getter functions are not
currently recognised as an implementation of the matching abstract
function by the compiler.
*/
/// total amount of tokens
function totalSupply() external view returns (uint256);
/// @param _owner The address from which the balance will be retrieved
/// @return balance
function balanceOf(address _owner) external view returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transfer(address _to, uint256 _value)
external
returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return success Whether the transfer was successful or not
function transferFrom(
address _from,
address _to,
uint256 _value
) external returns (bool success);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of tokens to be approved for transfer
/// @return success Whether the approval was successful or not
function approve(address _spender, uint256 _value)
external
returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return remaining Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender)
external
view
returns (uint256 remaining);
// solhint-disable-next-line no-simple-event-func-name
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
}
{
"name": "@eth-optimism/ERC20-Example",
"version": "0.0.1-alpha.1",
"description": "Basic example of how to test a basic token contract with Waffle in the OVM",
"scripts": {
"clean": "rimraf build",
"compile": "waffle",
"compile:ovm": "waffle waffle-ovm.json",
"test:integration": "mocha 'test/*.spec.js' --timeout 10000",
"test:integration:ovm": "TARGET=OVM mocha 'test/*.spec.js' --timeout 50000"
},
"keywords": [
"optimism",
"rollup",
"optimistic",
"ethereum",
"virtual",
"machine",
"OVM",
"ERC20",
"waffle"
],
"private": true,
"homepage": "https://github.com/ethereum-optimism/ERC20-Example#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/ERC20-Example.git"
},
"devDependencies": {
"@types/chai": "^4.2.17",
"@types/mocha": "^7.0.2",
"@types/rimraf": "^3.0.0",
"chai": "^4.3.4",
"dotenv": "^8.2.0",
"ethereum-waffle": "^3.0.0",
"mocha": "^7.0.1",
"rimraf": "^2.6.3"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@eth-optimism/solc": "0.7.6-alpha.1",
"solc": "0.7.6"
}
}
\ No newline at end of file
/* External imports */
require('dotenv/config')
const { use, expect } = require('chai')
const { ethers } = require('ethers')
const { solidity } = require('ethereum-waffle')
/* Internal imports */
const { getArtifact } = require('./getArtifact')
use(solidity)
const config = {
l2Url: process.env.L2_URL || 'http://127.0.0.1:8545',
l1Url: process.env.L1_URL || 'http://127.0.0.1:9545',
useL2: process.env.TARGET === 'OVM',
privateKey: process.env.PRIVATE_KEY || '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
}
describe('ERC20 smart contract', () => {
let ERC20,
provider
if (config.useL2) {
provider = new ethers.providers.JsonRpcProvider(config.l2Url)
provider.pollingInterval = 100
provider.getGasPrice = async () => ethers.BigNumber.from(0)
} else {
provider = new ethers.providers.JsonRpcProvider(config.l1Url)
}
const wallet = new ethers.Wallet(config.privateKey).connect(provider)
// parameters to use for our test coin
const COIN_NAME = 'OVM Test Coin'
const TICKER = 'OVM'
const NUM_DECIMALS = 1
describe('when using a deployed contract instance', () => {
before(async () => {
const Artifact__ERC20 = getArtifact(config.useL2)
const Factory__ERC20 = new ethers.ContractFactory(
Artifact__ERC20.abi,
Artifact__ERC20.bytecode,
wallet
)
// TODO: Remove this hardcoded gas limit
ERC20 = await Factory__ERC20.connect(wallet).deploy(
1000,
COIN_NAME,
NUM_DECIMALS,
TICKER
)
await ERC20.deployTransaction.wait()
})
it('should assigns initial balance', async () => {
const address = await wallet.getAddress()
expect(await ERC20.balanceOf(address)).to.equal(1000)
})
it('should correctly set vanity information', async () => {
const name = await ERC20.name()
expect(name).to.equal(COIN_NAME)
const decimals = await ERC20.decimals()
expect(decimals).to.equal(NUM_DECIMALS)
const symbol = await ERC20.symbol()
expect(symbol).to.equal(TICKER)
})
it('should transfer amount to destination account', async () => {
const freshWallet = ethers.Wallet.createRandom()
const destination = await freshWallet.getAddress()
const tx = await ERC20.connect(wallet).transfer(destination, 7)
await tx.wait()
const walletToBalance = await ERC20.balanceOf(destination)
expect(walletToBalance.toString()).to.equal('7')
})
it('should emit Transfer event', async () => {
const address = await wallet.getAddress()
const tx = ERC20.connect(wallet).transfer(address, 7)
await expect(tx)
.to.emit(ERC20, 'Transfer')
.withArgs(address, address, 7)
})
it('should not transfer above the amount', async () => {
const address = await wallet.getAddress()
const walletToBalanceBefore = await ERC20.balanceOf(address)
await expect(ERC20.transfer(address, 1007)).to.be.reverted
const walletToBalanceAfter = await ERC20.balanceOf(address)
expect(walletToBalanceBefore).to.eq(walletToBalanceAfter)
})
it('should not transfer from empty account', async () => {
const emptyWallet = ethers.Wallet.createRandom()
const address = await emptyWallet.getAddress()
const ERC20FromOtherWallet = ERC20.connect(emptyWallet)
await expect(ERC20FromOtherWallet.transfer(address, 1)).to.be
.reverted
})
})
})
const getArtifact = (useL2) => {
const buildFolder = useL2 ? 'build-ovm' : 'build'
const ERC20Artifact = require(`../${buildFolder}/ERC20.json`)
return ERC20Artifact
}
module.exports = { getArtifact }
{
"compilerVersion": "./node_modules/@eth-optimism/solc",
"sourceDirectory": "./contracts",
"outputDirectory": "./build-ovm"
}
\ No newline at end of file
{
"compilerVersion": "./node_modules/solc",
"sourceDirectory": "./contracts",
"outputDirectory": "./build"
}
\ No newline at end of file
......@@ -151,8 +151,6 @@ type BlockChain struct {
chainmu sync.RWMutex // blockchain insertion lock
currentTimestamp atomic.Value // Timestamp to be used when mining the current block.
currentBlock atomic.Value // Current head of the block chain
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
......@@ -249,13 +247,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
// it in advance.
bc.engine.VerifyHeader(bc, bc.CurrentHeader(), true)
if currentHeader := bc.CurrentHeader(); currentHeader != nil {
log.Debug("Read timestamp from last block. ", "timestamp", bc.CurrentHeader().Time)
bc.SetCurrentTimestamp(int64(bc.CurrentHeader().Time))
} else {
bc.SetCurrentTimestamp(int64(0))
}
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
var (
needRewind bool
......@@ -504,17 +495,6 @@ func (bc *BlockChain) GasLimit() uint64 {
return bc.CurrentBlock().GasLimit()
}
// SetCurrentTimestamp sets the timestamp for blocks added to the canonical chain.
func (bc *BlockChain) SetCurrentTimestamp(timestamp int64) {
bc.currentTimestamp.Store(&timestamp)
}
// CurrentTimestamp retrieves the timestamp used for blocks added to the canonical chain.
func (bc *BlockChain) CurrentTimestamp() int64 {
// Note: Can never be nil
return *bc.currentTimestamp.Load().(*int64)
}
// CurrentBlock retrieves the current head block of the canonical chain. The
// block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentBlock() *types.Block {
......
......@@ -249,7 +249,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
l1MessageSender = msg.L1MessageSender().Hex()
}
if st.evm.EthCallSender == nil {
log.Debug("Applying transaction", "ID", st.evm.Id, "from", sender.Address().Hex(), "to", to, "nonce", msg.Nonce(), "gasPrice", msg.GasPrice().Uint64(), "gasLimit", msg.Gas(), "value", msg.Value().Uint64(), "l1MessageSender", l1MessageSender, "data", hexutil.Encode(msg.Data()))
log.Debug("Applying transaction", "from", sender.Address().Hex(), "to", to, "nonce", msg.Nonce(), "gasPrice", msg.GasPrice().Uint64(), "gasLimit", msg.Gas(), "value", msg.Value().Uint64(), "l1MessageSender", l1MessageSender, "data", hexutil.Encode(msg.Data()))
}
}
......
......@@ -18,8 +18,6 @@ package vm
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"strings"
......@@ -120,7 +118,7 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
// OVM_ENABLED
// Only log for non `eth_call`s
if evm.Context.EthCallSender == nil {
log.Debug("Calling contract", "ID", evm.Id, "Address", contract.Address().Hex(), "Data", hexutil.Encode(input))
log.Debug("Calling contract", "Address", contract.Address().Hex(), "Data", hexutil.Encode(input))
}
// Uncomment to make Safety checker always returns true.
......@@ -132,7 +130,7 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err
if contract.Address() == evm.Context.OvmStateManager.Address {
// The caller must be the execution manager
if contract.Caller() != evm.Context.OvmExecutionManager.Address {
log.Error("StateManager called by non ExecutionManager", "ID", evm.Id, "caller", contract.Caller().Hex())
log.Error("StateManager called by non ExecutionManager", "caller", contract.Caller().Hex())
return nil, ErrOvmSandboxEscape
}
return callStateManager(input, evm, contract)
......@@ -238,8 +236,6 @@ type EVM struct {
// available gas is calculated in gasCall* according to the 63/64 rule and later
// applied in opCall*.
callGasTemp uint64
Id string
}
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
......@@ -256,9 +252,6 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
ctx.OvmL2StandardBridge = chainConfig.StateDump.Accounts["OVM_L2StandardBridge"]
}
id := make([]byte, 4)
rand.Read(id)
evm := &EVM{
Context: ctx,
StateDB: statedb,
......@@ -266,8 +259,6 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon
chainConfig: chainConfig,
chainRules: chainConfig.Rules(ctx.BlockNumber),
interpreters: make([]Interpreter, 0, 1),
Id: hex.EncodeToString(id),
}
if chainConfig.IsEWASM(ctx.BlockNumber) {
......@@ -467,7 +458,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
}
if evm.Context.EthCallSender == nil {
log.Debug("Reached the end of an OVM execution", "ID", evm.Id, "Return Data", hexutil.Encode(ret), "Error", err)
log.Debug("Reached the end of an OVM execution", "Return Data", hexutil.Encode(ret), "Error", err)
}
}
}
......@@ -700,7 +691,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
contractAddr = evm.OvmADDRESS()
if evm.Context.EthCallSender == nil {
log.Debug("[EM] Creating contract.", "ID", evm.Id, "New contract address", contractAddr.Hex(), "Caller Addr", caller.Address().Hex(), "Caller nonce", evm.StateDB.GetNonce(caller.Address()))
log.Debug("[EM] Creating contract.", "New contract address", contractAddr.Hex(), "Caller Addr", caller.Address().Hex(), "Caller nonce", evm.StateDB.GetNonce(caller.Address()))
}
}
......@@ -726,7 +717,7 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *
contractAddr = evm.OvmADDRESS()
if evm.Context.EthCallSender == nil {
log.Debug("[EM] Creating contract [create2].", "ID", evm.Id, "New contract address", contractAddr.Hex(), "Caller Addr", caller.Address().Hex(), "Caller nonce", evm.StateDB.GetNonce(caller.Address()))
log.Debug("[EM] Creating contract [create2].", "New contract address", contractAddr.Hex(), "Caller Addr", caller.Address().Hex(), "Caller nonce", evm.StateDB.GetNonce(caller.Address()))
}
}
......
......@@ -304,9 +304,6 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
if b.UsingOVM {
to := signedTx.To()
if to != nil {
if *to == (common.Address{}) {
return errors.New("Cannot send transaction to zero address")
}
// Prevent QueueOriginSequencer transactions that are too large to
// be included in a batch. The `MaxCallDataSize` should be set to
// the layer one consensus max transaction size in bytes minus the
......@@ -323,10 +320,6 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
return b.eth.txPool.AddLocal(signedTx)
}
func (b *EthAPIBackend) SetTimestamp(timestamp int64) {
b.eth.blockchain.SetCurrentTimestamp(timestamp)
}
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
pending, err := b.eth.txPool.Pending()
if err != nil {
......
......@@ -86,7 +86,6 @@ type Backend interface {
CurrentBlock() *types.Block
// Optimism-specific API
SetTimestamp(timestamp int64)
IsVerifier() bool
IsSyncing() bool
GetEthContext() (uint64, uint64)
......
......@@ -352,7 +352,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
select {
case <-w.startCh:
clearPending(w.chain.CurrentBlock().NumberU64())
timestamp = w.chain.CurrentTimestamp()
commit(false, commitInterruptNewHead)
// Remove this code for the OVM implementation. It is responsible for
......@@ -374,7 +373,6 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
timer.Reset(recommit)
continue
}
timestamp = w.chain.CurrentTimestamp()
commit(true, commitInterruptResubmit)
}
......@@ -543,7 +541,7 @@ func (w *worker) mainLoop() {
// If clique is running in dev mode(period is 0), disable
// advance sealing here.
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 {
w.commitNewWork(nil, true, w.chain.CurrentTimestamp())
w.commitNewWork(nil, true, time.Now().Unix())
}
}
atomic.AddInt32(&w.newTxs, int32(len(ev.Txs)))
......
......@@ -331,11 +331,12 @@ func batchedTransactionToTransaction(res *transaction, signer *types.EIP155Signe
// The queue origin must be either sequencer of l1, otherwise
// it is considered an unknown queue origin and will not be processed
var queueOrigin types.QueueOrigin
if res.QueueOrigin == sequencer {
switch res.QueueOrigin {
case sequencer:
queueOrigin = types.QueueOriginSequencer
} else if res.QueueOrigin == l1 {
case l1:
queueOrigin = types.QueueOriginL1ToL2
} else {
default:
return nil, fmt.Errorf("Unknown queue origin: %s", res.QueueOrigin)
}
// Transactions that have been decoded are
......
FROM ethereumoptimism/builder AS builder
FROM node:14-alpine
WORKDIR /opt/optimism
# copy top level files
COPY --from=builder /optimism/*.json ./
COPY --from=builder /optimism/yarn.lock .
COPY --from=builder /optimism/node_modules ./node_modules
# copy deps (would have been nice if docker followed the symlinks required)
COPY --from=builder /optimism/packages/core-utils/package.json ./packages/core-utils/package.json
COPY --from=builder /optimism/packages/core-utils/dist ./packages/core-utils/dist
COPY --from=builder /optimism/packages/common-ts/package.json ./packages/common-ts/package.json
COPY --from=builder /optimism/packages/common-ts/dist ./packages/common-ts/dist
# copy the service
WORKDIR /opt/optimism/packages/replica-healthcheck
COPY --from=builder /optimism/packages/replica-healthcheck/dist ./dist
COPY --from=builder /optimism/packages/replica-healthcheck/package.json .
COPY --from=builder /optimism/packages/replica-healthcheck/node_modules ./node_modules
ENTRYPOINT ["node", "dist/exec/run-healthcheck-server.js"]
......@@ -1730,9 +1730,9 @@ path-is-absolute@^1.0.0:
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
pbkdf2@^3.0.17:
version "3.1.1"
......
src/contract-artifacts.ts
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { ethers } from 'hardhat'
/* 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
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
async function main() {
const l2TokenFactory = await ethers.getContractFactory(
'OVM_L2StandardTokenFactory'
)
const l2StandardTokenFactory = await l2TokenFactory.deploy()
await deploy('OVM_L2StandardTokenFactory', {
contract: l2TokenFactory,
args: [],
from: deployer,
log: true,
})
console.log(
'L2 Standard Token Factory deployed to:',
l2StandardTokenFactory.address
)
}
deployFn.tags = ['OVM_L2StandardTokenFactory']
export default deployFn
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error)
process.exit(1)
})
{
"_format": "hh-sol-artifact-1",
"contractName": "OVM_L2StandardTokenFactory",
"sourceName": "contracts/optimistic-ethereum/OVM/bridge/tokens/OVM_L2StandardTokenFactory.sol",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "_l1Token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "_l2Token",
"type": "address"
}
],
"name": "StandardL2TokenCreated",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "_l1Token",
"type": "address"
},
{
"internalType": "string",
"name": "_name",
"type": "string"
},
{
"internalType": "string",
"name": "_symbol",
"type": "string"
}
],
"name": "createStandardL2Token",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x60806040523480156100195760008061001661001f565b50505b5061008a565b632a2a7adb598160e01b8152600481016020815285602082015260005b8681101561005757808601518282016040015260200161003c565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b611c72806100996000396000f3fe60806040523480156200001c576000806200001962000145565b50505b5060043610620000395760003560e01c8063896f93d11462000049575b6000806200004662000145565b50505b620000606200005a366004620002db565b62000062565b005b6001600160a01b0383166200009f5760405162461bcd60e51b81526004016200008b906200042b565b604051809103906200009c62000145565b50505b60006010602160991b01848484604051620000ba90620001b2565b620000c99493929190620003de565b604051809103906000620000dc620001c0565b505080158015620000fc573d6000803e3d6000620000f962000145565b50505b509050806001600160a01b0316846001600160a01b03167fceeb8e7d520d7f3b65fc11a262b91066940193b05d4f93df07cfdced0eb551cf60405160405180910390a350505050565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156200017f57808601518282016040015260200162000162565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b61180f806200046383390190565b6314aa2ff7598160e01b8152600481016020815286602082015260005b87811015620001fa578087015182820160400152602001620001dd565b506020828860640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8151965059825b818110156200024557600081526020016200022f565b5050505050565b600082601f830112620002685780816200026562000145565b50505b813567ffffffffffffffff808211156200027e57fe5b604051601f8301601f1916810160200182811182821017156200029d57fe5b604052828152848301602001861015620002c0578384620002bd62000145565b50505b82602086016020830137918201602001929092529392505050565b600080600060608486031215620002fb578283620002f862000145565b50505b83356001600160a01b03811681146200031d5783846200031a62000145565b50505b9250602084013567ffffffffffffffff80821115620003455783846200034262000145565b50505b62000353878388016200024c565b93506040860135915080821115620003745782836200037162000145565b50505b5062000383868287016200024c565b9150509250925092565b60008151808452815b81811015620003b75760208082860101518683019091015260200162000396565b81811115620003c95782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526080604082018190526000906200040c908301856200038d565b82810360608401526200042081856200038d565b979650505050505050565b6020808252601d908201527f4d7573742070726f76696465204c3120746f6b656e206164647265737300000060408201526060019056fe60806040523480156200001c5760008062000019620002e2565b50505b506040516200180f3803806200180f833981810160405260808110156200004d576000806200004a620002e2565b50505b810190808051929190602001805192919060200180516040519392919084640100000000821115620000895760008062000086620002e2565b50505b908301906020820185811115620000aa57600080620000a7620002e2565b50505b8251640100000000811182820188101715620000d057600080620000cd620002e2565b50505b825250602001908051906020019080838360005b83811015620000fe578082015183820152602001620000e4565b50505050905090810190601f1680156200012c5780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200015b5760008062000158620002e2565b50505b9083019060208201858111156200017c5760008062000179620002e2565b50505b8251640100000000811182820188101715620001a2576000806200019f620002e2565b50505b825250602001908051906020019080838360005b83811015620001d0578082015183820152602001620001b6565b50505050905090810190601f168015620001fe5780820380516001836020036101000a031916815260200191505b5060405250505081818160039080516200021d9291602001906200034f565b506004818051620002339291602001906200034f565b50601260056001816200024562000411565b8160ff021916908360ff160217906200025d62000473565b505050505082600560016101000a816200027662000411565b816001600160a01b0302191690836001600160a01b03160217906200029a62000473565b50505083600660006101000a81620002b162000411565b816001600160a01b0302191690836001600160a01b0316021790620002d562000473565b50505050505050620004e5565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156200031c578086015182820160400152602001620002ff565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b82806200035b62000411565b600181600116156101000203166002900490600052602060002090601f0160209004810192826200039b576000856200039362000473565b5050620003ff565b82601f10620003b957805160ff191683800117856200039362000473565b82800160010185620003ca62000473565b50508215620003ff579182015b82811115620003ff57825182620003ed62000473565b505091602001919060010190620003d7565b506200040d929150620004c2565b5090565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156200046e5760008282015260200162000455565b505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60008152602062000455565b808211156200040d5760008082620004d962000473565b505050600101620004c2565b61131a80620004f56000396000f3fe60806040523480156100195760008061001661107b565b50505b50600436106101095760003560e01c806370a08231116100a0578063a9059cbb1161006f578063a9059cbb14610393578063ae1f6aaf146103c8578063c01e1bd6146103ec578063dd62ed3e146103f457610109565b806370a08231146102f257806395d89b41146103215780639dc29fac14610329578063a457c2d71461035e57610109565b806323b872dd116100dc57806323b872dd14610229578063313ce56714610268578063395093511461028657806340c10f19146102bb57610109565b806301ffc9a71461011757806306fdde031461015b578063095ea7b3146101da57806318160ddd1461020f575b60008061011461107b565b50505b610147600480360360208110156101365760008061013361107b565b50505b50356001600160e01b03191661042b565b604051901515815260200160405180910390f35b610163610489565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561019f578082015183820152602001610187565b50505050905090810190601f1680156101cc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610147600480360360408110156101f9576000806101f661107b565b50505b506001600160a01b038135169060200135610546565b610217610563565b60405190815260200160405180910390f35b610147600480360360608110156102485760008061024561107b565b50505b506001600160a01b03813581169160208101359091169060400135610574565b610270610608565b60405160ff909116815260200160405180910390f35b610147600480360360408110156102a5576000806102a261107b565b50505b506001600160a01b038135169060200135610624565b6102f0600480360360408110156102da576000806102d761107b565b50505b506001600160a01b038135169060200135610689565b005b610217600480360360208110156103115760008061030e61107b565b50505b50356001600160a01b0316610765565b61016361078b565b6102f0600480360360408110156103485760008061034561107b565b50505b506001600160a01b038135169060200135610831565b6101476004803603604081101561037d5760008061037a61107b565b50505b506001600160a01b03813516906020013561090d565b610147600480360360408110156103b2576000806103af61107b565b50505b506001600160a01b038135169060200135610983565b6103d0610997565b6040516001600160a01b03909116815260200160405180910390f35b6103d06109b6565b610217600480360360408110156104135760008061041061107b565b50505b506001600160a01b03813581169160200135166109c2565b60007f01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e2631d1d8b6360e01b6001600160e01b031984166301ffc9a760e01b148061048157506001600160e01b0319848116908216145b949350505050565b60606003806104966110e6565b600181600116156101000203166002900480601f0160208091040260200160405190810160405281815291906020830182806104d06110e6565b6001816001161561010002031660029004801561053c5780601f1061050a5761010080836104fc6110e6565b04028352916020019161053c565b820191906000526020600020905b816105216110e6565b8152906001019060200180831161051857829003601f168201915b5050505050905090565b600061055a610553610a02565b8484610a0d565b50600192915050565b6000600261056f6110e6565b905090565b6000610581848484610b35565b6105fe8461058d610a02565b6105f98560405160608101604052602880825261126360208301396001600160a01b038a16600090815260016020526040902060006105ca610a02565b6001600160a01b03166001600160a01b031681526020019081526020016000206105f26110e6565b9190610cd3565b610a0d565b5060019392505050565b60008060056106156110e6565b906101000a900460ff16905090565b600061055a610631610a02565b846105f98560016000610642610a02565b6001600160a01b03166001600160a01b031681526020019081526020016000206001600160a01b0389166000908152602091909152604090206106836110e6565b90610d73565b600060066106956110e6565b906101000a90046001600160a01b03166001600160a01b03165a6106b7611141565b6001600160a01b03161461071a5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e60448201526064016040518091039061071761107b565b50505b6107248282610ddb565b816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405190815260200160405180910390a25050565b6001600160a01b03811660009081526020819052604081206107856110e6565b92915050565b60606004806107986110e6565b600181600116156101000203166002900480601f0160208091040260200160405190810160405281815291906020830182806107d26110e6565b6001816001161561010002031660029004801561053c5780601f106107fe5761010080836104fc6110e6565b820191906000526020600020905b816108156110e6565b8152906001019060200180831161080c57509395945050505050565b6000600661083d6110e6565b906101000a90046001600160a01b03166001600160a01b03165a61085f611141565b6001600160a01b0316146108c25760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e6044820152606401604051809103906108bf61107b565b50505b6108cc8282610ef4565b816001600160a01b03167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58260405190815260200160405180910390a25050565b600061055a61091a610a02565b846105f9856040516060810160405260258082526112f5602083013960016000610942610a02565b6001600160a01b03166001600160a01b031681526020019081526020016000206001600160a01b038a166000908152602091909152604090206105f26110e6565b600061055a610990610a02565b8484610b35565b600060066109a36110e6565b906101000a90046001600160a01b031681565b600160056109a36110e6565b6001600160a01b03821660009081526001602052604081206001600160a01b0383166000908152602091909152604090206109fb6110e6565b9392505050565b60005a61056f611141565b6001600160a01b038316610a5b5760405162461bcd60e51b81526004018080602001828103825260248152602001806112d16024913960400191505060405180910390610a5861107b565b50505b6001600160a01b038216610aa95760405162461bcd60e51b815260040180806020018281038252602281526020018061121b6022913960400191505060405180910390610aa661107b565b50505b6001600160a01b038316600090815260016020528190604090206001600160a01b0384166000908152602091909152604090208190610ae6611187565b505050816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405190815260200160405180910390a3505050565b6001600160a01b038316610b835760405162461bcd60e51b81526004018080602001828103825260258152602001806112ac6025913960400191505060405180910390610b8061107b565b50505b6001600160a01b038216610bd15760405162461bcd60e51b81526004018080602001828103825260238152602001806111d66023913960400191505060405180910390610bce61107b565b50505b610bdc838383611014565b610c178160405160608101604052602680825261123d60208301396001600160a01b03861660009081526020819052604090206105f26110e6565b6001600160a01b03841660009081526020819052604090208190610c39611187565b5050506001600160a01b03821660009081526020819052610c62908290604090206106836110e6565b6001600160a01b03831660009081526020819052604090208190610c84611187565b505050816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a3505050565b60008184841115610d6b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610d27578082015183820152602001610d0f565b50505050905090810190601f168015610d545780820380516001836020036101000a031916815260200191505b509250505060405180910390610d6861107b565b50505b505050900390565b6000828201838110156109fb5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640160405180910390610dd261107b565b50509392505050565b6001600160a01b038216610e3e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390610e3b61107b565b50505b610e4a60008383611014565b610e588160026106836110e6565b806002610e63611187565b5050506001600160a01b03821660009081526020819052610e8c908290604090206106836110e6565b6001600160a01b03831660009081526020819052604090208190610eae611187565b5050506001600160a01b03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b6001600160a01b038216610f425760405162461bcd60e51b815260040180806020018281038252602181526020018061128b6021913960400191505060405180910390610f3f61107b565b50505b610f4e82600083611014565b610f89816040516060810160405260228082526111f960208301396001600160a01b03851660009081526020819052604090206105f26110e6565b6001600160a01b03831660009081526020819052604090208190610fab611187565b505050610fc2816002610fbc6110e6565b90611019565b806002610fcd611187565b5060009150506001600160a01b0383167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b505050565b6000828211156110755760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015260640160405180910390610d6b61107b565b50900390565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156110b3578086015182820160400152602001611098565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156110145760008282015260200161112a565b6373509064598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051600082529350602061112a565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60008152602061112a56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f",
"deployedBytecode": "0x60806040523480156200001c576000806200001962000145565b50505b5060043610620000395760003560e01c8063896f93d11462000049575b6000806200004662000145565b50505b620000606200005a366004620002db565b62000062565b005b6001600160a01b0383166200009f5760405162461bcd60e51b81526004016200008b906200042b565b604051809103906200009c62000145565b50505b60006010602160991b01848484604051620000ba90620001b2565b620000c99493929190620003de565b604051809103906000620000dc620001c0565b505080158015620000fc573d6000803e3d6000620000f962000145565b50505b509050806001600160a01b0316846001600160a01b03167fceeb8e7d520d7f3b65fc11a262b91066940193b05d4f93df07cfdced0eb551cf60405160405180910390a350505050565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156200017f57808601518282016040015260200162000162565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b61180f806200046383390190565b6314aa2ff7598160e01b8152600481016020815286602082015260005b87811015620001fa578087015182820160400152602001620001dd565b506020828860640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8151965059825b818110156200024557600081526020016200022f565b5050505050565b600082601f830112620002685780816200026562000145565b50505b813567ffffffffffffffff808211156200027e57fe5b604051601f8301601f1916810160200182811182821017156200029d57fe5b604052828152848301602001861015620002c0578384620002bd62000145565b50505b82602086016020830137918201602001929092529392505050565b600080600060608486031215620002fb578283620002f862000145565b50505b83356001600160a01b03811681146200031d5783846200031a62000145565b50505b9250602084013567ffffffffffffffff80821115620003455783846200034262000145565b50505b62000353878388016200024c565b93506040860135915080821115620003745782836200037162000145565b50505b5062000383868287016200024c565b9150509250925092565b60008151808452815b81811015620003b75760208082860101518683019091015260200162000396565b81811115620003c95782602083870101525b50601f01601f19169290920160200192915050565b6001600160a01b038581168252841660208201526080604082018190526000906200040c908301856200038d565b82810360608401526200042081856200038d565b979650505050505050565b6020808252601d908201527f4d7573742070726f76696465204c3120746f6b656e206164647265737300000060408201526060019056fe60806040523480156200001c5760008062000019620002e2565b50505b506040516200180f3803806200180f833981810160405260808110156200004d576000806200004a620002e2565b50505b810190808051929190602001805192919060200180516040519392919084640100000000821115620000895760008062000086620002e2565b50505b908301906020820185811115620000aa57600080620000a7620002e2565b50505b8251640100000000811182820188101715620000d057600080620000cd620002e2565b50505b825250602001908051906020019080838360005b83811015620000fe578082015183820152602001620000e4565b50505050905090810190601f1680156200012c5780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200015b5760008062000158620002e2565b50505b9083019060208201858111156200017c5760008062000179620002e2565b50505b8251640100000000811182820188101715620001a2576000806200019f620002e2565b50505b825250602001908051906020019080838360005b83811015620001d0578082015183820152602001620001b6565b50505050905090810190601f168015620001fe5780820380516001836020036101000a031916815260200191505b5060405250505081818160039080516200021d9291602001906200034f565b506004818051620002339291602001906200034f565b50601260056001816200024562000411565b8160ff021916908360ff160217906200025d62000473565b505050505082600560016101000a816200027662000411565b816001600160a01b0302191690836001600160a01b03160217906200029a62000473565b50505083600660006101000a81620002b162000411565b816001600160a01b0302191690836001600160a01b0316021790620002d562000473565b50505050505050620004e5565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156200031c578086015182820160400152602001620002ff565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b82806200035b62000411565b600181600116156101000203166002900490600052602060002090601f0160209004810192826200039b576000856200039362000473565b5050620003ff565b82601f10620003b957805160ff191683800117856200039362000473565b82800160010185620003ca62000473565b50508215620003ff579182015b82811115620003ff57825182620003ed62000473565b505091602001919060010190620003d7565b506200040d929150620004c2565b5090565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156200046e5760008282015260200162000455565b505050565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60008152602062000455565b808211156200040d5760008082620004d962000473565b505050600101620004c2565b61131a80620004f56000396000f3fe60806040523480156100195760008061001661107b565b50505b50600436106101095760003560e01c806370a08231116100a0578063a9059cbb1161006f578063a9059cbb14610393578063ae1f6aaf146103c8578063c01e1bd6146103ec578063dd62ed3e146103f457610109565b806370a08231146102f257806395d89b41146103215780639dc29fac14610329578063a457c2d71461035e57610109565b806323b872dd116100dc57806323b872dd14610229578063313ce56714610268578063395093511461028657806340c10f19146102bb57610109565b806301ffc9a71461011757806306fdde031461015b578063095ea7b3146101da57806318160ddd1461020f575b60008061011461107b565b50505b610147600480360360208110156101365760008061013361107b565b50505b50356001600160e01b03191661042b565b604051901515815260200160405180910390f35b610163610489565b60405160208082528190810183818151815260200191508051906020019080838360005b8381101561019f578082015183820152602001610187565b50505050905090810190601f1680156101cc5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610147600480360360408110156101f9576000806101f661107b565b50505b506001600160a01b038135169060200135610546565b610217610563565b60405190815260200160405180910390f35b610147600480360360608110156102485760008061024561107b565b50505b506001600160a01b03813581169160208101359091169060400135610574565b610270610608565b60405160ff909116815260200160405180910390f35b610147600480360360408110156102a5576000806102a261107b565b50505b506001600160a01b038135169060200135610624565b6102f0600480360360408110156102da576000806102d761107b565b50505b506001600160a01b038135169060200135610689565b005b610217600480360360208110156103115760008061030e61107b565b50505b50356001600160a01b0316610765565b61016361078b565b6102f0600480360360408110156103485760008061034561107b565b50505b506001600160a01b038135169060200135610831565b6101476004803603604081101561037d5760008061037a61107b565b50505b506001600160a01b03813516906020013561090d565b610147600480360360408110156103b2576000806103af61107b565b50505b506001600160a01b038135169060200135610983565b6103d0610997565b6040516001600160a01b03909116815260200160405180910390f35b6103d06109b6565b610217600480360360408110156104135760008061041061107b565b50505b506001600160a01b03813581169160200135166109c2565b60007f01ffc9a7a5cef8baa21ed3c5c0d7e23accb804b619e9333b597f47a0d84076e2631d1d8b6360e01b6001600160e01b031984166301ffc9a760e01b148061048157506001600160e01b0319848116908216145b949350505050565b60606003806104966110e6565b600181600116156101000203166002900480601f0160208091040260200160405190810160405281815291906020830182806104d06110e6565b6001816001161561010002031660029004801561053c5780601f1061050a5761010080836104fc6110e6565b04028352916020019161053c565b820191906000526020600020905b816105216110e6565b8152906001019060200180831161051857829003601f168201915b5050505050905090565b600061055a610553610a02565b8484610a0d565b50600192915050565b6000600261056f6110e6565b905090565b6000610581848484610b35565b6105fe8461058d610a02565b6105f98560405160608101604052602880825261126360208301396001600160a01b038a16600090815260016020526040902060006105ca610a02565b6001600160a01b03166001600160a01b031681526020019081526020016000206105f26110e6565b9190610cd3565b610a0d565b5060019392505050565b60008060056106156110e6565b906101000a900460ff16905090565b600061055a610631610a02565b846105f98560016000610642610a02565b6001600160a01b03166001600160a01b031681526020019081526020016000206001600160a01b0389166000908152602091909152604090206106836110e6565b90610d73565b600060066106956110e6565b906101000a90046001600160a01b03166001600160a01b03165a6106b7611141565b6001600160a01b03161461071a5760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e60448201526064016040518091039061071761107b565b50505b6107248282610ddb565b816001600160a01b03167f0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d41213968858260405190815260200160405180910390a25050565b6001600160a01b03811660009081526020819052604081206107856110e6565b92915050565b60606004806107986110e6565b600181600116156101000203166002900480601f0160208091040260200160405190810160405281815291906020830182806107d26110e6565b6001816001161561010002031660029004801561053c5780601f106107fe5761010080836104fc6110e6565b820191906000526020600020905b816108156110e6565b8152906001019060200180831161080c57509395945050505050565b6000600661083d6110e6565b906101000a90046001600160a01b03166001600160a01b03165a61085f611141565b6001600160a01b0316146108c25760405162461bcd60e51b815260206004820181905260248201527f4f6e6c79204c32204272696467652063616e206d696e7420616e64206275726e6044820152606401604051809103906108bf61107b565b50505b6108cc8282610ef4565b816001600160a01b03167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca58260405190815260200160405180910390a25050565b600061055a61091a610a02565b846105f9856040516060810160405260258082526112f5602083013960016000610942610a02565b6001600160a01b03166001600160a01b031681526020019081526020016000206001600160a01b038a166000908152602091909152604090206105f26110e6565b600061055a610990610a02565b8484610b35565b600060066109a36110e6565b906101000a90046001600160a01b031681565b600160056109a36110e6565b6001600160a01b03821660009081526001602052604081206001600160a01b0383166000908152602091909152604090206109fb6110e6565b9392505050565b60005a61056f611141565b6001600160a01b038316610a5b5760405162461bcd60e51b81526004018080602001828103825260248152602001806112d16024913960400191505060405180910390610a5861107b565b50505b6001600160a01b038216610aa95760405162461bcd60e51b815260040180806020018281038252602281526020018061121b6022913960400191505060405180910390610aa661107b565b50505b6001600160a01b038316600090815260016020528190604090206001600160a01b0384166000908152602091909152604090208190610ae6611187565b505050816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258360405190815260200160405180910390a3505050565b6001600160a01b038316610b835760405162461bcd60e51b81526004018080602001828103825260258152602001806112ac6025913960400191505060405180910390610b8061107b565b50505b6001600160a01b038216610bd15760405162461bcd60e51b81526004018080602001828103825260238152602001806111d66023913960400191505060405180910390610bce61107b565b50505b610bdc838383611014565b610c178160405160608101604052602680825261123d60208301396001600160a01b03861660009081526020819052604090206105f26110e6565b6001600160a01b03841660009081526020819052604090208190610c39611187565b5050506001600160a01b03821660009081526020819052610c62908290604090206106836110e6565b6001600160a01b03831660009081526020819052604090208190610c84611187565b505050816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a3505050565b60008184841115610d6b5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610d27578082015183820152602001610d0f565b50505050905090810190601f168015610d545780820380516001836020036101000a031916815260200191505b509250505060405180910390610d6861107b565b50505b505050900390565b6000828201838110156109fb5760405162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015260640160405180910390610dd261107b565b50509392505050565b6001600160a01b038216610e3e5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640160405180910390610e3b61107b565b50505b610e4a60008383611014565b610e588160026106836110e6565b806002610e63611187565b5050506001600160a01b03821660009081526020819052610e8c908290604090206106836110e6565b6001600160a01b03831660009081526020819052604090208190610eae611187565b5050506001600160a01b03821660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b6001600160a01b038216610f425760405162461bcd60e51b815260040180806020018281038252602181526020018061128b6021913960400191505060405180910390610f3f61107b565b50505b610f4e82600083611014565b610f89816040516060810160405260228082526111f960208301396001600160a01b03851660009081526020819052604090206105f26110e6565b6001600160a01b03831660009081526020819052604090208190610fab611187565b505050610fc2816002610fbc6110e6565b90611019565b806002610fcd611187565b5060009150506001600160a01b0383167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405190815260200160405180910390a35050565b505050565b6000828211156110755760405162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015260640160405180910390610d6b61107b565b50900390565b632a2a7adb598160e01b8152600481016020815285602082015260005b868110156110b3578086015182820160400152602001611098565b506020828760640184336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b505050565b6303daa959598160e01b8152836004820152602081602483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051935060005b60408110156110145760008282015260200161112a565b6373509064598160e01b8152602081600483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b8051600082529350602061112a565b6322bd64c0598160e01b8152836004820152846024820152600081604483336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b60008152602061112a56fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726f",
"linkReferences": {},
"deployedLinkReferences": {}
}
......@@ -39,13 +39,14 @@
"lint:fix": "yarn lint:check --fix",
"lint:contracts": "yarn solhint -f table contracts/optimistic-ethereum/**/*.sol",
"clean": "rm -rf ./dist ./artifacts ./artifacts-ovm ./cache ./cache-ovm ./tsconfig.build.tsbuildinfo",
"deploy": "ts-node \"./bin/deploy.ts\" && yarn generate-markdown",
"deploy": "ts-node \"./bin/deploy.ts\" && yarn generate:markdown",
"serve": "./bin/serve_dump.sh",
"prepublishOnly": "yarn copyfiles -u 2 \"contracts/optimistic-ethereum/**/*\" ./",
"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\"",
"generate:artifacts": "node \"./scripts/generate-artifacts.js\"",
"pre-commit": "lint-staged"
},
"dependencies": {
......
......@@ -2,6 +2,7 @@
set -e
yarn build:typescript &
yarn build:contracts
yarn build:contracts:ovm
yarn generate:artifacts
yarn build:typescript
#!/usr/bin/env node
const path = require('path')
const glob = require('glob')
const fs = require('fs')
;(async () => {
console.log(`writing contract artifacts typescript file`)
const getContractJsonFiles = (artifactsFolder) => {
return glob.sync(`${artifactsFolder}/**/*.json`).filter((match) => {
return !match.endsWith('.dbg.json')
})
}
const evmArtifactPaths = getContractJsonFiles(
path.resolve(__dirname, `../artifacts/contracts`)
)
const ovmArtifactPaths = getContractJsonFiles(
path.resolve(__dirname, `../artifacts-ovm/contracts`)
)
const content = `
/* eslint-disable @typescript-eslint/no-var-requires, no-empty */
/*
THIS FILE IS AUTOMATICALLY GENERATED.
DO NOT EDIT.
*/
${ovmArtifactPaths
.map((artifactPath) => {
const artifact = require(artifactPath)
const relPath = path.relative(__dirname, artifactPath)
return `
let ovm__${artifact.contractName}
try {
ovm__${artifact.contractName} = require('${relPath}')
} catch {}
`
})
.join('\n')}
${evmArtifactPaths
.map((artifactPath) => {
const artifact = require(artifactPath)
const relPath = path.relative(__dirname, artifactPath)
return `
let ${artifact.contractName}
try {
${artifact.contractName} = require('${relPath}')
} catch {}
`
})
.join('\n')}
export const getContractArtifact = (name: string, ovm: boolean): any => {
if (ovm) {
return {
${ovmArtifactPaths
.map((artifactPath) => {
const artifact = require(artifactPath)
return `${artifact.contractName}: ovm__${artifact.contractName}`
})
.join(',\n')}
}[name]
} else {
return {
${evmArtifactPaths
.map((artifactPath) => {
const artifact = require(artifactPath)
return `${artifact.contractName}: ${artifact.contractName}`
})
.join(',\n')}
}[name]
}
}
`
fs.writeFileSync(`./src/contract-artifacts.ts`, content)
})().catch(console.error)
......@@ -4,10 +4,9 @@ import { expect } from '../../../../setup'
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'
import { predeploys, getContractInterface } from '../../../../../src'
describe('OVM_L2StandardTokenFactory', () => {
let signer: Signer
......
......@@ -92,7 +92,6 @@ export class HealthcheckServer {
}
runSyncCheck = async () => {
throw new Error('trial')
const sequencerProvider = injectL2Context(
new providers.JsonRpcProvider(this.options.sequencerRpcProvider)
)
......
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