Commit 3ad9f739 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #2282 from ethereum-optimism/develop

develop => master
parents a3a5b11d dfd5ac6e
---
'@eth-optimism/sdk': patch
---
Fix typo in constructor docstring
---
'@eth-optimism/sdk': major
---
Update README and bump SDK to 1.0.0
......@@ -27,6 +27,7 @@ module.exports = {
parserOptions: {
project: 'tsconfig.json',
sourceType: 'module',
allowAutomaticSingleRunInference: true,
},
rules: {
'@typescript-eslint/adjacent-overload-signatures': 'error',
......@@ -102,13 +103,9 @@ module.exports = {
'import/no-extraneous-dependencies': ['error'],
'import/no-internal-modules': 'off',
'import/order': [
"error",
'error',
{
groups: [
'builtin',
'external',
'internal',
],
groups: ['builtin', 'external', 'internal'],
'newlines-between': 'always',
},
],
......
......@@ -43,8 +43,8 @@ func NewMetrics(monitoredTokens map[string]string) *Metrics {
return &Metrics{
SyncHeight: promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "l1_sync_height",
Help: "The max height of the indexer's last batch of L1 blocks.",
Name: "sync_height",
Help: "The max height of the indexer's last batch of L1/L1 blocks.",
Namespace: metricsNamespace,
}, []string{
"chain",
......@@ -66,7 +66,7 @@ func NewMetrics(monitoredTokens map[string]string) *Metrics {
"symbol",
}),
StateBatchesCount: prometheus.NewCounter(prometheus.CounterOpts{
StateBatchesCount: promauto.NewCounter(prometheus.CounterOpts{
Name: "state_batches_count",
Help: "The number of state batches indexed.",
Namespace: metricsNamespace,
......@@ -101,7 +101,7 @@ func NewMetrics(monitoredTokens map[string]string) *Metrics {
"chain",
}),
CachedTokensCount: prometheus.NewCounterVec(prometheus.CounterOpts{
CachedTokensCount: promauto.NewCounterVec(prometheus.CounterOpts{
Name: "cached_tokens_count",
Help: "How many tokens are in the cache",
Namespace: metricsNamespace,
......@@ -118,7 +118,7 @@ func (m *Metrics) SetL1SyncHeight(height uint64) {
}
func (m *Metrics) SetL2SyncHeight(height uint64) {
m.SyncHeight.WithLabelValues("l1").Set(float64(height))
m.SyncHeight.WithLabelValues("l2").Set(float64(height))
}
func (m *Metrics) RecordDeposit(addr common.Address) {
......
{
"name": "indexer",
"name": "@eth-optimism/indexer",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"private": true,
"license": "MIT"
}
......@@ -94,9 +94,9 @@ type Service struct {
latestHeader uint64
headerSelector *ConfirmedHeaderSelector
metrics *metrics.Metrics
metrics *metrics.Metrics
tokenCache map[common.Address]*db.Token
wg sync.WaitGroup
wg sync.WaitGroup
}
type IndexerStatus struct {
......@@ -289,10 +289,15 @@ func (s *Service) Update(newHeader *types.Header) error {
logger.Error("Error querying state batches", "err", err)
}
for _, header := range headers {
for i, header := range headers {
blockHash := header.Hash
number := header.Number.Uint64()
deposits := depositsByBlockHash[blockHash]
batches := stateBatches[blockHash]
if len(deposits) == 0 && len(batches) == 0 && i != len(headers)-1 {
continue
}
block := &db.IndexedL1Block{
Hash: blockHash,
......@@ -313,7 +318,6 @@ func (s *Service) Update(newHeader *types.Header) error {
return err
}
batches := stateBatches[blockHash]
err = s.cfg.DB.AddStateBatch(batches)
if err != nil {
logger.Error(
......
......@@ -69,15 +69,15 @@ func respondWithJSON(w http.ResponseWriter, code int, payload interface{}) {
}
type ServiceConfig struct {
Context context.Context
Metrics *metrics.Metrics
L2Client *l2ethclient.Client
ChainID *big.Int
ConfDepth uint64
MaxHeaderBatchSize uint64
StartBlockNumber uint64
StartBlockHash string
DB *db.Database
Context context.Context
Metrics *metrics.Metrics
L2Client *l2ethclient.Client
ChainID *big.Int
ConfDepth uint64
MaxHeaderBatchSize uint64
StartBlockNumber uint64
StartBlockHash string
DB *db.Database
}
type Service struct {
......@@ -89,9 +89,9 @@ type Service struct {
latestHeader uint64
headerSelector *ConfirmedHeaderSelector
metrics *metrics.Metrics
metrics *metrics.Metrics
tokenCache map[common.Address]*db.Token
wg sync.WaitGroup
wg sync.WaitGroup
}
type IndexerStatus struct {
......@@ -267,11 +267,15 @@ func (s *Service) Update(newHeader *types.Header) error {
}
}
for _, header := range headers {
for i, header := range headers {
blockHash := header.Hash()
number := header.Number.Uint64()
withdrawals := withdrawalsByBlockHash[blockHash]
if len(withdrawals) == 0 && i != len(headers)-1 {
continue
}
block := &db.IndexedL2Block{
Hash: blockHash,
ParentHash: header.ParentHash,
......
......@@ -8,12 +8,7 @@
"packages/*",
"l2geth",
"integration-tests",
"specs",
"go/gas-oracle",
"go/batch-submitter",
"go/l2geth-exporter",
"go/proxyd",
"go/op-exporter",
"go/*",
"ops/docker/rpc-proxy",
"ops/docker/hardhat"
],
......
......@@ -66,7 +66,6 @@
"devDependencies": {
"@codechecks/client": "^0.1.11",
"@defi-wonderland/smock": "^2.0.2",
"@eth-optimism/smock": "1.1.10",
"@nomiclabs/ethereumjs-vm": "^4.2.2",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-etherscan": "^2.1.6",
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, BigNumber } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { smock, MockContractFactory } from '@defi-wonderland/smock'
import {
smock,
MockContractFactory,
FakeContract,
} from '@defi-wonderland/smock'
import {
remove0x,
toHexString,
......@@ -56,9 +59,9 @@ describe('L1CrossDomainMessenger', () => {
AddressManager = await makeAddressManager()
})
let Mock__TargetContract: MockContract
let Mock__L2CrossDomainMessenger: MockContract
let Mock__StateCommitmentChain: MockContract
let Fake__TargetContract: FakeContract
let Fake__L2CrossDomainMessenger: FakeContract
let Fake__StateCommitmentChain: FakeContract
let Factory__CanonicalTransactionChain: ContractFactory
let Factory__ChainStorageContainer: ContractFactory
......@@ -66,28 +69,28 @@ describe('L1CrossDomainMessenger', () => {
let CanonicalTransactionChain: Contract
before(async () => {
Mock__TargetContract = await smockit(
Fake__TargetContract = await smock.fake<Contract>(
await ethers.getContractFactory('Helper_SimpleProxy')
)
Mock__L2CrossDomainMessenger = await smockit(
Fake__L2CrossDomainMessenger = await smock.fake<Contract>(
await ethers.getContractFactory('L2CrossDomainMessenger'),
{
address: predeploys.L2CrossDomainMessenger,
}
)
Mock__StateCommitmentChain = await smockit(
Fake__StateCommitmentChain = await smock.fake<Contract>(
await ethers.getContractFactory('StateCommitmentChain')
)
await AddressManager.setAddress(
'L2CrossDomainMessenger',
Mock__L2CrossDomainMessenger.address
Fake__L2CrossDomainMessenger.address
)
await setProxyTarget(
AddressManager,
'StateCommitmentChain',
Mock__StateCommitmentChain
Fake__StateCommitmentChain
)
Factory__CanonicalTransactionChain = await ethers.getContractFactory(
......@@ -178,7 +181,7 @@ describe('L1CrossDomainMessenger', () => {
['address', 'address', 'uint256', 'bytes'],
[
applyL1ToL2Alias(L1CrossDomainMessenger.address),
Mock__L2CrossDomainMessenger.address,
Fake__L2CrossDomainMessenger.address,
gasLimit,
calldata,
]
......@@ -322,7 +325,7 @@ describe('L1CrossDomainMessenger', () => {
.to.emit(CanonicalTransactionChain, 'TransactionEnqueued')
.withArgs(
applyL1ToL2Alias(L1CrossDomainMessenger.address),
Mock__L2CrossDomainMessenger.address,
Fake__L2CrossDomainMessenger.address,
newGasLimit,
encodeXDomainCalldata(target, sender, message, queueIndex),
newQueueIndex,
......@@ -388,7 +391,7 @@ describe('L1CrossDomainMessenger', () => {
const storageKey = ethers.utils.keccak256(
ethers.utils.keccak256(
calldata + remove0x(Mock__L2CrossDomainMessenger.address)
calldata + remove0x(Fake__L2CrossDomainMessenger.address)
) + '00'.repeat(32)
)
const storageGenerator = await TrieTestGenerator.fromNodes({
......@@ -439,8 +442,8 @@ describe('L1CrossDomainMessenger', () => {
let proof: any
let calldata: string
before(async () => {
target = Mock__TargetContract.address
message = Mock__TargetContract.interface.encodeFunctionData('setTarget', [
target = Fake__TargetContract.address
message = Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
])
sender = await signer.getAddress()
......@@ -455,18 +458,12 @@ describe('L1CrossDomainMessenger', () => {
})
beforeEach(async () => {
Mock__StateCommitmentChain.smocked.verifyStateCommitment.will.return.with(
true
)
Mock__StateCommitmentChain.smocked.insideFraudProofWindow.will.return.with(
false
)
Fake__StateCommitmentChain.verifyStateCommitment.returns(true)
Fake__StateCommitmentChain.insideFraudProofWindow.returns(false)
})
it('should revert if still inside the fraud proof window', async () => {
Mock__StateCommitmentChain.smocked.insideFraudProofWindow.will.return.with(
true
)
Fake__StateCommitmentChain.insideFraudProofWindow.returns(true)
const proof1 = {
stateRoot: ethers.constants.HashZero,
......@@ -502,9 +499,7 @@ describe('L1CrossDomainMessenger', () => {
})
it('should revert if provided an invalid state root proof', async () => {
Mock__StateCommitmentChain.smocked.verifyStateCommitment.will.return.with(
false
)
Fake__StateCommitmentChain.verifyStateCommitment.returns(false)
const proof1 = {
stateRoot: ethers.constants.HashZero,
......
......@@ -2,7 +2,12 @@
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, constants } from 'ethers'
import { Interface } from 'ethers/lib/utils'
import { smockit, MockContract, smoddit } from '@eth-optimism/smock'
import {
smock,
MockContractFactory,
FakeContract,
MockContract,
} from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -30,15 +35,15 @@ describe('L1StandardBridge', () => {
let aliceAddress
// we can just make up this string since it's on the "other" Layer
let Factory__L1ERC20: ContractFactory
let Factory__L1ERC20: MockContractFactory<ContractFactory>
let IL2ERC20Bridge: Interface
before(async () => {
;[l1MessengerImpersonator, alice, bob] = await ethers.getSigners()
await smockit(await ethers.getContractFactory('OVM_ETH'))
await smock.fake<Contract>(await ethers.getContractFactory('OVM_ETH'))
// deploy an ERC20 contract on L1
Factory__L1ERC20 = await smoddit(
Factory__L1ERC20 = await smock.mock(
'@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20'
)
......@@ -49,12 +54,12 @@ describe('L1StandardBridge', () => {
bobsAddress = await bob.getAddress()
})
let L1ERC20: Contract
let L1ERC20: MockContract<Contract>
let L1StandardBridge: Contract
let Mock__L1CrossDomainMessenger: MockContract
let Fake__L1CrossDomainMessenger: FakeContract
beforeEach(async () => {
// Get a new mock L1 messenger
Mock__L1CrossDomainMessenger = await smockit(
Fake__L1CrossDomainMessenger = await smock.fake<Contract>(
await ethers.getContractFactory('L1CrossDomainMessenger'),
{ address: await l1MessengerImpersonator.getAddress() } // This allows us to use an ethers override {from: Mock__L2CrossDomainMessenger.address} to mock calls
)
......@@ -64,16 +69,15 @@ describe('L1StandardBridge', () => {
await ethers.getContractFactory('L1StandardBridge')
).deploy()
await L1StandardBridge.initialize(
Mock__L1CrossDomainMessenger.address,
Fake__L1CrossDomainMessenger.address,
DUMMY_L2_BRIDGE_ADDRESS
)
L1ERC20 = await Factory__L1ERC20.deploy('L1ERC20', 'ERC')
await L1ERC20.smodify.put({
_totalSupply: INITIAL_TOTAL_L1_SUPPLY,
_balances: {
[aliceAddress]: INITIAL_TOTAL_L1_SUPPLY,
},
await L1ERC20.setVariable('_totalSupply', INITIAL_TOTAL_L1_SUPPLY)
await L1ERC20.setVariable('_balances', {
[aliceAddress]: INITIAL_TOTAL_L1_SUPPLY,
})
})
......@@ -116,7 +120,7 @@ describe('L1StandardBridge', () => {
)
const depositCallToMessenger =
Mock__L1CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L1CrossDomainMessenger.sendMessage.getCall(0)
const depositerBalance = await ethers.provider.getBalance(depositer)
const receipt = await res.wait()
......@@ -136,11 +140,11 @@ describe('L1StandardBridge', () => {
// Check the correct cross-chain call was sent:
// Message should be sent to the L2 bridge
expect(depositCallToMessenger._target).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
expect(depositCallToMessenger.args[0]).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
// Message data should be a call telling the L2ETHToken to finalize the deposit
// the L1 bridge sends the correct message to the L1 messenger
expect(depositCallToMessenger._message).to.equal(
expect(depositCallToMessenger.args[1]).to.equal(
IL2ERC20Bridge.encodeFunctionData('finalizeDeposit', [
constants.AddressZero,
predeploys.OVM_ETH,
......@@ -150,7 +154,7 @@ describe('L1StandardBridge', () => {
NON_NULL_BYTES32,
])
)
expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
expect(depositCallToMessenger.args[2]).to.equal(FINALIZATION_GAS)
})
it('depositETHTo() escrows the deposit amount and sends the correct deposit message', async () => {
......@@ -166,7 +170,7 @@ describe('L1StandardBridge', () => {
}
)
const depositCallToMessenger =
Mock__L1CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L1CrossDomainMessenger.sendMessage.getCall(0)
const depositerBalance = await ethers.provider.getBalance(aliceAddress)
const receipt = await res.wait()
......@@ -186,11 +190,11 @@ describe('L1StandardBridge', () => {
// Check the correct cross-chain call was sent:
// Message should be sent to the L2 bridge
expect(depositCallToMessenger._target).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
expect(depositCallToMessenger.args[0]).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
// Message data should be a call telling the L2ETHToken to finalize the deposit
// the L1 bridge sends the correct message to the L1 messenger
expect(depositCallToMessenger._message).to.equal(
expect(depositCallToMessenger.args[1]).to.equal(
IL2ERC20Bridge.encodeFunctionData('finalizeDeposit', [
constants.AddressZero,
predeploys.OVM_ETH,
......@@ -200,7 +204,7 @@ describe('L1StandardBridge', () => {
NON_NULL_BYTES32,
])
)
expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
expect(depositCallToMessenger.args[2]).to.equal(FINALIZATION_GAS)
})
it('cannot depositETH from a contract account', async () => {
......@@ -233,11 +237,11 @@ describe('L1StandardBridge', () => {
await ethers.getContractFactory('L1StandardBridge')
).deploy()
await L1StandardBridge.initialize(
Mock__L1CrossDomainMessenger.address,
Fake__L1CrossDomainMessenger.address,
DUMMY_L2_BRIDGE_ADDRESS
)
Mock__L1CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L1CrossDomainMessenger.xDomainMessageSender.returns(
'0x' + '22'.repeat(20)
)
......@@ -248,7 +252,7 @@ describe('L1StandardBridge', () => {
1,
NON_NULL_BYTES32,
{
from: Mock__L1CrossDomainMessenger.address,
from: Fake__L1CrossDomainMessenger.address,
}
)
).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER)
......@@ -259,7 +263,7 @@ describe('L1StandardBridge', () => {
expect(await ethers.provider.getBalance(NON_ZERO_ADDRESS)).to.be.equal(0)
const withdrawalAmount = 100
Mock__L1CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L1CrossDomainMessenger.xDomainMessageSender.returns(
() => DUMMY_L2_BRIDGE_ADDRESS
)
......@@ -270,7 +274,7 @@ describe('L1StandardBridge', () => {
withdrawalAmount,
NON_NULL_BYTES32,
{
from: Mock__L1CrossDomainMessenger.address,
from: Fake__L1CrossDomainMessenger.address,
}
)
).to.be.revertedWith(
......@@ -283,7 +287,7 @@ describe('L1StandardBridge', () => {
expect(await ethers.provider.getBalance(NON_ZERO_ADDRESS)).to.be.equal(0)
const withdrawalAmount = 100
Mock__L1CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L1CrossDomainMessenger.xDomainMessageSender.returns(
() => DUMMY_L2_BRIDGE_ADDRESS
)
......@@ -302,7 +306,7 @@ describe('L1StandardBridge', () => {
withdrawalAmount,
NON_NULL_BYTES32,
{
from: Mock__L1CrossDomainMessenger.address,
from: Fake__L1CrossDomainMessenger.address,
}
)
......@@ -333,7 +337,7 @@ describe('L1StandardBridge', () => {
)
const depositCallToMessenger =
Mock__L1CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L1CrossDomainMessenger.sendMessage.getCall(0)
const depositerBalance = await L1ERC20.balanceOf(aliceAddress)
......@@ -345,11 +349,11 @@ describe('L1StandardBridge', () => {
// Check the correct cross-chain call was sent:
// Message should be sent to the L2 bridge
expect(depositCallToMessenger._target).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
expect(depositCallToMessenger.args[0]).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
// Message data should be a call telling the L2DepositedERC20 to finalize the deposit
// the L1 bridge sends the correct message to the L1 messenger
expect(depositCallToMessenger._message).to.equal(
expect(depositCallToMessenger.args[1]).to.equal(
IL2ERC20Bridge.encodeFunctionData('finalizeDeposit', [
L1ERC20.address,
DUMMY_L2_ERC20_ADDRESS,
......@@ -359,7 +363,7 @@ describe('L1StandardBridge', () => {
NON_NULL_BYTES32,
])
)
expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
expect(depositCallToMessenger.args[2]).to.equal(FINALIZATION_GAS)
})
it('depositERC20To() escrows the deposit amount and sends the correct deposit message', async () => {
......@@ -373,7 +377,7 @@ describe('L1StandardBridge', () => {
NON_NULL_BYTES32
)
const depositCallToMessenger =
Mock__L1CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L1CrossDomainMessenger.sendMessage.getCall(0)
const depositerBalance = await L1ERC20.balanceOf(aliceAddress)
expect(depositerBalance).to.equal(INITIAL_TOTAL_L1_SUPPLY - depositAmount)
......@@ -384,11 +388,11 @@ describe('L1StandardBridge', () => {
// Check the correct cross-chain call was sent:
// Message should be sent to the L2DepositedERC20 on L2
expect(depositCallToMessenger._target).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
expect(depositCallToMessenger.args[0]).to.equal(DUMMY_L2_BRIDGE_ADDRESS)
// Message data should be a call telling the L2DepositedERC20 to finalize the deposit
// the L1 bridge sends the correct message to the L1 messenger
expect(depositCallToMessenger._message).to.equal(
expect(depositCallToMessenger.args[1]).to.equal(
IL2ERC20Bridge.encodeFunctionData('finalizeDeposit', [
L1ERC20.address,
DUMMY_L2_ERC20_ADDRESS,
......@@ -398,7 +402,7 @@ describe('L1StandardBridge', () => {
NON_NULL_BYTES32,
])
)
expect(depositCallToMessenger._gasLimit).to.equal(FINALIZATION_GAS)
expect(depositCallToMessenger.args[2]).to.equal(FINALIZATION_GAS)
})
it('cannot depositERC20 from a contract account', async () => {
......@@ -414,20 +418,20 @@ describe('L1StandardBridge', () => {
})
describe('Handling ERC20.transferFrom() failures that revert ', () => {
let MOCK__L1ERC20: MockContract
let Fake__L1ERC20: FakeContract
before(async () => {
// Deploy the L1 ERC20 token, Alice will receive the full initialSupply
MOCK__L1ERC20 = await smockit(
Fake__L1ERC20 = await smock.fake<Contract>(
await Factory__L1ERC20.deploy('L1ERC20', 'ERC')
)
MOCK__L1ERC20.smocked.transferFrom.will.revert()
Fake__L1ERC20.transferFrom.reverts()
})
it('depositERC20(): will revert if ERC20.transferFrom() reverts', async () => {
await expect(
L1StandardBridge.connect(alice).depositERC20(
MOCK__L1ERC20.address,
Fake__L1ERC20.address,
DUMMY_L2_ERC20_ADDRESS,
depositAmount,
FINALIZATION_GAS,
......@@ -439,7 +443,7 @@ describe('L1StandardBridge', () => {
it('depositERC20To(): will revert if ERC20.transferFrom() reverts', async () => {
await expect(
L1StandardBridge.connect(alice).depositERC20To(
MOCK__L1ERC20.address,
Fake__L1ERC20.address,
DUMMY_L2_ERC20_ADDRESS,
bobsAddress,
depositAmount,
......@@ -464,18 +468,18 @@ describe('L1StandardBridge', () => {
})
describe('Handling ERC20.transferFrom failures that return false', () => {
let MOCK__L1ERC20: MockContract
let Fake__L1ERC20: FakeContract
before(async () => {
MOCK__L1ERC20 = await smockit(
Fake__L1ERC20 = await smock.fake(
await Factory__L1ERC20.deploy('L1ERC20', 'ERC')
)
MOCK__L1ERC20.smocked.transferFrom.will.return.with(false)
Fake__L1ERC20.transferFrom.returns(false)
})
it('deposit(): will revert if ERC20.transferFrom() returns false', async () => {
await expect(
L1StandardBridge.connect(alice).depositERC20(
MOCK__L1ERC20.address,
Fake__L1ERC20.address,
DUMMY_L2_ERC20_ADDRESS,
depositAmount,
FINALIZATION_GAS,
......@@ -487,7 +491,7 @@ describe('L1StandardBridge', () => {
it('depositTo(): will revert if ERC20.transferFrom() returns false', async () => {
await expect(
L1StandardBridge.depositERC20To(
MOCK__L1ERC20.address,
Fake__L1ERC20.address,
DUMMY_L2_ERC20_ADDRESS,
bobsAddress,
depositAmount,
......@@ -514,8 +518,8 @@ describe('L1StandardBridge', () => {
})
it('onlyFromCrossDomainAccount: should revert on calls from the right crossDomainMessenger, but wrong xDomainMessageSender (ie. not the L2DepositedERC20)', async () => {
Mock__L1CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
'0x' + '22'.repeat(20)
Fake__L1CrossDomainMessenger.xDomainMessageSender.returns(
() => NON_ZERO_ADDRESS
)
await expect(
......@@ -527,7 +531,7 @@ describe('L1StandardBridge', () => {
1,
NON_NULL_BYTES32,
{
from: Mock__L1CrossDomainMessenger.address,
from: Fake__L1CrossDomainMessenger.address,
}
)
).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER)
......@@ -556,7 +560,7 @@ describe('L1StandardBridge', () => {
// make sure no balance at start of test
expect(await L1ERC20.balanceOf(NON_ZERO_ADDRESS)).to.be.equal(0)
Mock__L1CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L1CrossDomainMessenger.xDomainMessageSender.returns(
() => DUMMY_L2_BRIDGE_ADDRESS
)
......@@ -567,7 +571,7 @@ describe('L1StandardBridge', () => {
NON_ZERO_ADDRESS,
withdrawalAmount,
NON_NULL_BYTES32,
{ from: Mock__L1CrossDomainMessenger.address }
{ from: Fake__L1CrossDomainMessenger.address }
)
expect(await L1ERC20.balanceOf(NON_ZERO_ADDRESS)).to.be.equal(
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smoddit } from '@eth-optimism/smock'
import { MockContract, smock } from '@defi-wonderland/smock'
import { expectApprox } from '@eth-optimism/core-utils'
/* Internal Imports */
......@@ -92,7 +92,7 @@ describe('[GAS BENCHMARK] Depositing via the standard bridge [ @skip-on-coverage
})
// 4 Bridge
let L1ERC20: Contract
let L1ERC20: MockContract<Contract>
let L1StandardBridge: Contract
before('Deploy the bridge and setup the token', async () => {
// Deploy the Bridge
......@@ -105,14 +105,12 @@ describe('[GAS BENCHMARK] Depositing via the standard bridge [ @skip-on-coverage
)
L1ERC20 = await (
await smoddit('@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20')
await smock.mock('@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20')
).deploy('L1ERC20', 'ERC')
const aliceAddress = await alice.getAddress()
await L1ERC20.smodify.put({
_totalSupply: INITIAL_TOTAL_L1_SUPPLY,
_balances: {
[aliceAddress]: INITIAL_TOTAL_L1_SUPPLY,
},
await L1ERC20.setVariable('_totalSupply', INITIAL_TOTAL_L1_SUPPLY)
await L1ERC20.setVariable('_balances', {
[aliceAddress]: INITIAL_TOTAL_L1_SUPPLY,
})
})
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { smock, FakeContract } from '@defi-wonderland/smock'
import {
AppendSequencerBatchParams,
BatchContext,
......@@ -46,7 +46,7 @@ describe('[GAS BENCHMARK] CanonicalTransactionChain [ @skip-on-coverage ]', () =
})
let AddressManager: Contract
let Mock__StateCommitmentChain: MockContract
let Fake__StateCommitmentChain: FakeContract
before(async () => {
AddressManager = await makeAddressManager()
await AddressManager.setAddress(
......@@ -54,14 +54,14 @@ describe('[GAS BENCHMARK] CanonicalTransactionChain [ @skip-on-coverage ]', () =
await sequencer.getAddress()
)
Mock__StateCommitmentChain = await smockit(
Fake__StateCommitmentChain = await smock.fake<Contract>(
await ethers.getContractFactory('StateCommitmentChain')
)
await setProxyTarget(
AddressManager,
'StateCommitmentChain',
Mock__StateCommitmentChain
Fake__StateCommitmentChain
)
})
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { smock, FakeContract } from '@defi-wonderland/smock'
import {
AppendSequencerBatchParams,
encodeAppendSequencerBatch,
......@@ -69,7 +69,7 @@ describe('CanonicalTransactionChain', () => {
})
let AddressManager: Contract
let Mock__StateCommitmentChain: MockContract
let Fake__StateCommitmentChain: FakeContract
before(async () => {
AddressManager = await makeAddressManager()
await AddressManager.setAddress(
......@@ -77,14 +77,14 @@ describe('CanonicalTransactionChain', () => {
await sequencer.getAddress()
)
Mock__StateCommitmentChain = await smockit(
Fake__StateCommitmentChain = await smock.fake<Contract>(
await ethers.getContractFactory('StateCommitmentChain')
)
await setProxyTarget(
AddressManager,
'StateCommitmentChain',
Mock__StateCommitmentChain
Fake__StateCommitmentChain
)
})
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, constants } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { smock, FakeContract } from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -25,26 +25,26 @@ describe('StateCommitmentChain', () => {
AddressManager = await makeAddressManager()
})
let Mock__CanonicalTransactionChain: MockContract
let Mock__BondManager: MockContract
let Fake__CanonicalTransactionChain: FakeContract
let Fake__BondManager: FakeContract
before(async () => {
Mock__CanonicalTransactionChain = await smockit(
Fake__CanonicalTransactionChain = await smock.fake<Contract>(
await ethers.getContractFactory('CanonicalTransactionChain')
)
await setProxyTarget(
AddressManager,
'CanonicalTransactionChain',
Mock__CanonicalTransactionChain
Fake__CanonicalTransactionChain
)
Mock__BondManager = await smockit(
Fake__BondManager = await smock.fake<Contract>(
await ethers.getContractFactory('BondManager')
)
await setProxyTarget(AddressManager, 'BondManager', Mock__BondManager)
await setProxyTarget(AddressManager, 'BondManager', Fake__BondManager)
Mock__BondManager.smocked.isCollateralized.will.return.with(true)
Fake__BondManager.isCollateralized.returns(true)
await AddressManager.setAddress(
'OVM_Proposer',
......@@ -114,7 +114,7 @@ describe('StateCommitmentChain', () => {
describe('when submitting more elements than present in the CanonicalTransactionChain', () => {
before(() => {
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
Fake__CanonicalTransactionChain.getTotalElements.returns(
batch.length - 1
)
})
......@@ -130,9 +130,7 @@ describe('StateCommitmentChain', () => {
describe('when not submitting more elements than present in the CanonicalTransactionChain', () => {
before(() => {
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
})
it('should append the state batch', async () => {
......@@ -143,7 +141,7 @@ describe('StateCommitmentChain', () => {
describe('when a sequencer submits ', () => {
beforeEach(async () => {
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
Fake__CanonicalTransactionChain.getTotalElements.returns(
batch.length * 2
)
......@@ -182,7 +180,7 @@ describe('StateCommitmentChain', () => {
})
describe('when the proposer has not previously staked at the BondManager', () => {
before(() => {
Mock__BondManager.smocked.isCollateralized.will.return.with(false)
Fake__BondManager.isCollateralized.returns(false)
})
it('should revert', async () => {
......@@ -207,13 +205,11 @@ describe('StateCommitmentChain', () => {
}
before(() => {
Mock__BondManager.smocked.isCollateralized.will.return.with(true)
Fake__BondManager.isCollateralized.returns(true)
})
beforeEach(async () => {
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
await StateCommitmentChain.appendStateBatch(batch, 0)
batchHeader.extraData = ethers.utils.defaultAbiCoder.encode(
['uint256', 'address'],
......@@ -329,9 +325,7 @@ describe('StateCommitmentChain', () => {
describe('when one batch element has been inserted', () => {
beforeEach(async () => {
const batch = [NON_NULL_BYTES32]
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
await StateCommitmentChain.appendStateBatch(batch, 0)
})
......@@ -343,9 +337,7 @@ describe('StateCommitmentChain', () => {
describe('when 64 batch elements have been inserted in one batch', () => {
beforeEach(async () => {
const batch = Array(64).fill(NON_NULL_BYTES32)
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
await StateCommitmentChain.appendStateBatch(batch, 0)
})
......@@ -357,7 +349,7 @@ describe('StateCommitmentChain', () => {
describe('when 32 batch elements have been inserted in each of two batches', () => {
beforeEach(async () => {
const batch = Array(32).fill(NON_NULL_BYTES32)
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
Fake__CanonicalTransactionChain.getTotalElements.returns(
batch.length * 2
)
await StateCommitmentChain.appendStateBatch(batch, 0)
......@@ -380,9 +372,7 @@ describe('StateCommitmentChain', () => {
describe('when one batch has been inserted', () => {
beforeEach(async () => {
const batch = [NON_NULL_BYTES32]
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
await StateCommitmentChain.appendStateBatch(batch, 0)
})
......@@ -394,7 +384,7 @@ describe('StateCommitmentChain', () => {
describe('when 8 batches have been inserted', () => {
beforeEach(async () => {
const batch = [NON_NULL_BYTES32]
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
Fake__CanonicalTransactionChain.getTotalElements.returns(
batch.length * 8
)
......@@ -422,9 +412,7 @@ describe('StateCommitmentChain', () => {
let timestamp
beforeEach(async () => {
const batch = [NON_NULL_BYTES32]
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
await StateCommitmentChain.appendStateBatch(batch, 0)
timestamp = await getEthTime(ethers.provider)
})
......@@ -455,13 +443,11 @@ describe('StateCommitmentChain', () => {
const element = NON_NULL_BYTES32
before(async () => {
Mock__BondManager.smocked.isCollateralized.will.return.with(true)
Fake__BondManager.isCollateralized.returns(true)
})
beforeEach(async () => {
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
Fake__CanonicalTransactionChain.getTotalElements.returns(batch.length)
await StateCommitmentChain.appendStateBatch(batch, 0)
batchHeader.extraData = ethers.utils.defaultAbiCoder.encode(
['uint256', 'address'],
......
/* External Imports */
import hre, { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { applyL1ToL2Alias } from '@eth-optimism/core-utils'
import { smock, MockContractFactory } from '@defi-wonderland/smock'
import {
smock,
MockContractFactory,
FakeContract,
} from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -20,17 +23,17 @@ describe('L2CrossDomainMessenger', () => {
;[signer] = await ethers.getSigners()
})
let Mock__TargetContract: MockContract
let Mock__L1CrossDomainMessenger: MockContract
let Mock__OVM_L2ToL1MessagePasser: MockContract
let Fake__TargetContract: FakeContract
let Fake__L1CrossDomainMessenger: FakeContract
let Fake__OVM_L2ToL1MessagePasser: FakeContract
before(async () => {
Mock__TargetContract = await smockit(
Fake__TargetContract = await smock.fake<Contract>(
await ethers.getContractFactory('Helper_SimpleProxy')
)
Mock__L1CrossDomainMessenger = await smockit(
Fake__L1CrossDomainMessenger = await smock.fake<Contract>(
await ethers.getContractFactory('L1CrossDomainMessenger')
)
Mock__OVM_L2ToL1MessagePasser = await smockit(
Fake__OVM_L2ToL1MessagePasser = await smock.fake<Contract>(
await ethers.getContractFactory('OVM_L2ToL1MessagePasser'),
{ address: predeploys.OVM_L2ToL1MessagePasser }
)
......@@ -39,7 +42,7 @@ describe('L2CrossDomainMessenger', () => {
let impersonatedL1CrossDomainMessengerSender: Signer
before(async () => {
const impersonatedAddress = applyL1ToL2Alias(
Mock__L1CrossDomainMessenger.address
Fake__L1CrossDomainMessenger.address
)
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
......@@ -64,7 +67,7 @@ describe('L2CrossDomainMessenger', () => {
let L2CrossDomainMessenger: Contract
beforeEach(async () => {
L2CrossDomainMessenger = await Factory__L2CrossDomainMessenger.deploy(
Mock__L1CrossDomainMessenger.address
Fake__L1CrossDomainMessenger.address
)
})
......@@ -77,7 +80,7 @@ describe('L2CrossDomainMessenger', () => {
)
Mock__L2CrossDomainMessenger =
await Mock__Factory__L2CrossDomainMessenger.deploy(
Mock__L1CrossDomainMessenger.address
Fake__L1CrossDomainMessenger.address
)
})
......@@ -103,10 +106,10 @@ describe('L2CrossDomainMessenger', () => {
).to.not.be.reverted
expect(
Mock__OVM_L2ToL1MessagePasser.smocked.passMessageToL1.calls[0]
).to.deep.equal([
encodeXDomainCalldata(target, await signer.getAddress(), message, 0),
])
Fake__OVM_L2ToL1MessagePasser.passMessageToL1.getCall(0).args[0]
).to.deep.equal(
encodeXDomainCalldata(target, await signer.getAddress(), message, 0)
)
})
it('should be able to send the same message twice', async () => {
......@@ -123,8 +126,8 @@ describe('L2CrossDomainMessenger', () => {
let message: string
let sender: string
before(async () => {
target = Mock__TargetContract.address
message = Mock__TargetContract.interface.encodeFunctionData('setTarget', [
target = Fake__TargetContract.address
message = Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
])
sender = await signer.getAddress()
......@@ -146,9 +149,9 @@ describe('L2CrossDomainMessenger', () => {
impersonatedL1CrossDomainMessengerSender
).relayMessage(target, sender, message, 0)
expect(Mock__TargetContract.smocked.setTarget.calls[0]).to.deep.equal([
NON_ZERO_ADDRESS,
])
expect(Fake__TargetContract.setTarget.getCall(0).args[0]).to.deep.equal(
NON_ZERO_ADDRESS
)
})
it('the xDomainMessageSender is reset to the original value', async () => {
......@@ -179,7 +182,7 @@ describe('L2CrossDomainMessenger', () => {
it('should not make a call if the target is the L2 MessagePasser', async () => {
target = predeploys.OVM_L2ToL1MessagePasser
message = Mock__OVM_L2ToL1MessagePasser.interface.encodeFunctionData(
message = Fake__OVM_L2ToL1MessagePasser.interface.encodeFunctionData(
'passMessageToL1(bytes)',
[NON_NULL_BYTES32]
)
......@@ -193,7 +196,7 @@ describe('L2CrossDomainMessenger', () => {
// There should be no 'relayedMessage' event logged in the receipt.
const logs = (
await Mock__OVM_L2ToL1MessagePasser.provider.getTransactionReceipt(
await Fake__OVM_L2ToL1MessagePasser.provider.getTransactionReceipt(
(
await resProm
).hash
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import {
smockit,
MockContract,
smoddit,
ModifiableContract,
} from '@eth-optimism/smock'
import { smock } from '@defi-wonderland/smock'
import { smock, FakeContract, MockContract } from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -47,10 +41,10 @@ describe('L2StandardBridge', () => {
let L2StandardBridge: Contract
let L2ERC20: Contract
let Mock__L2CrossDomainMessenger: MockContract
let Fake__L2CrossDomainMessenger: FakeContract
beforeEach(async () => {
// Get a new mock L2 messenger
Mock__L2CrossDomainMessenger = await smockit(
Fake__L2CrossDomainMessenger = await smock.fake<Contract>(
await ethers.getContractFactory('L2CrossDomainMessenger'),
// This allows us to use an ethers override {from: Mock__L2CrossDomainMessenger.address} to mock calls
{ address: await l2MessengerImpersonator.getAddress() }
......@@ -59,7 +53,7 @@ describe('L2StandardBridge', () => {
// Deploy the contract under test
L2StandardBridge = await (
await ethers.getContractFactory('L2StandardBridge')
).deploy(Mock__L2CrossDomainMessenger.address, DUMMY_L1BRIDGE_ADDRESS)
).deploy(Fake__L2CrossDomainMessenger.address, DUMMY_L1BRIDGE_ADDRESS)
// Deploy an L2 ERC20
L2ERC20 = await (
......@@ -83,7 +77,7 @@ describe('L2StandardBridge', () => {
})
it('onlyFromCrossDomainAccount: should revert on calls from the right crossDomainMessenger, but wrong xDomainMessageSender (ie. not the L1L1StandardBridge)', async () => {
Mock__L2CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L2CrossDomainMessenger.xDomainMessageSender.returns(
NON_ZERO_ADDRESS
)
......@@ -96,7 +90,7 @@ describe('L2StandardBridge', () => {
0,
NON_NULL_BYTES32,
{
from: Mock__L2CrossDomainMessenger.address,
from: Fake__L2CrossDomainMessenger.address,
}
)
).to.be.revertedWith(ERR_INVALID_X_DOMAIN_MSG_SENDER)
......@@ -118,11 +112,11 @@ describe('L2StandardBridge', () => {
0,
NON_NULL_BYTES32,
{
from: Mock__L2CrossDomainMessenger.address,
from: Fake__L2CrossDomainMessenger.address,
}
)
Mock__L2CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L2CrossDomainMessenger.xDomainMessageSender.returns(
() => DUMMY_L1BRIDGE_ADDRESS
)
......@@ -134,15 +128,15 @@ describe('L2StandardBridge', () => {
100,
NON_NULL_BYTES32,
{
from: Mock__L2CrossDomainMessenger.address,
from: Fake__L2CrossDomainMessenger.address,
}
)
const withdrawalCallToMessenger =
Mock__L2CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L2CrossDomainMessenger.sendMessage.getCall(1)
expect(withdrawalCallToMessenger._target).to.equal(DUMMY_L1BRIDGE_ADDRESS)
expect(withdrawalCallToMessenger._message).to.equal(
expect(withdrawalCallToMessenger.args[0]).to.equal(DUMMY_L1BRIDGE_ADDRESS)
expect(withdrawalCallToMessenger.args[1]).to.equal(
Factory__L1StandardBridge.interface.encodeFunctionData(
'finalizeERC20Withdrawal',
[
......@@ -160,7 +154,7 @@ describe('L2StandardBridge', () => {
it('should credit funds to the depositor', async () => {
const depositAmount = 100
Mock__L2CrossDomainMessenger.smocked.xDomainMessageSender.will.return.with(
Fake__L2CrossDomainMessenger.xDomainMessageSender.returns(
() => DUMMY_L1BRIDGE_ADDRESS
)
......@@ -172,7 +166,7 @@ describe('L2StandardBridge', () => {
depositAmount,
NON_NULL_BYTES32,
{
from: Mock__L2CrossDomainMessenger.address,
from: Fake__L2CrossDomainMessenger.address,
}
)
......@@ -183,7 +177,7 @@ describe('L2StandardBridge', () => {
describe('withdrawals', () => {
const withdrawAmount = 1_000
let SmoddedL2Token: ModifiableContract
let Mock__L2Token: MockContract<Contract>
let Fake__OVM_ETH
......@@ -195,8 +189,8 @@ describe('L2StandardBridge', () => {
beforeEach(async () => {
// Deploy a smodded gateway so we can give some balances to withdraw
SmoddedL2Token = await (
await smoddit('L2StandardERC20', alice)
Mock__L2Token = await (
await smock.mock('L2StandardERC20')
).deploy(
L2StandardBridge.address,
DUMMY_L1TOKEN_ADDRESS,
......@@ -204,14 +198,11 @@ describe('L2StandardBridge', () => {
'L2T'
)
// Populate the initial state with a total supply and some money in alice's balance
SmoddedL2Token.smodify.put({
_totalSupply: INITIAL_TOTAL_SUPPLY,
_balances: {
[aliceAddress]: ALICE_INITIAL_BALANCE,
},
l2Bridge: L2StandardBridge.address,
await Mock__L2Token.setVariable('_totalSupply', INITIAL_TOTAL_SUPPLY)
await Mock__L2Token.setVariable('_balances', {
[aliceAddress]: ALICE_INITIAL_BALANCE,
})
await Mock__L2Token.setVariable('l2Bridge', L2StandardBridge.address)
})
it('withdraw() withdraws and sends the correct withdrawal message for OVM_ETH', async () => {
......@@ -223,14 +214,14 @@ describe('L2StandardBridge', () => {
)
const withdrawalCallToMessenger =
Mock__L2CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L2CrossDomainMessenger.sendMessage.getCall(0)
// Assert the correct cross-chain call was sent:
// Message should be sent to the L1L1StandardBridge on L1
expect(withdrawalCallToMessenger._target).to.equal(DUMMY_L1BRIDGE_ADDRESS)
expect(withdrawalCallToMessenger.args[0]).to.equal(DUMMY_L1BRIDGE_ADDRESS)
// Message data should be a call telling the L1StandardBridge to finalize the withdrawal
expect(withdrawalCallToMessenger._message).to.equal(
expect(withdrawalCallToMessenger.args[1]).to.equal(
Factory__L1StandardBridge.interface.encodeFunctionData(
'finalizeETHWithdrawal',
[
......@@ -245,16 +236,16 @@ describe('L2StandardBridge', () => {
it('withdraw() burns and sends the correct withdrawal message', async () => {
await L2StandardBridge.withdraw(
SmoddedL2Token.address,
Mock__L2Token.address,
withdrawAmount,
0,
NON_NULL_BYTES32
)
const withdrawalCallToMessenger =
Mock__L2CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L2CrossDomainMessenger.sendMessage.getCall(0)
// Assert Alice's balance went down
const aliceBalance = await SmoddedL2Token.balanceOf(
const aliceBalance = await Mock__L2Token.balanceOf(
await alice.getAddress()
)
expect(aliceBalance).to.deep.equal(
......@@ -262,21 +253,21 @@ describe('L2StandardBridge', () => {
)
// Assert totalSupply went down
const newTotalSupply = await SmoddedL2Token.totalSupply()
const newTotalSupply = await Mock__L2Token.totalSupply()
expect(newTotalSupply).to.deep.equal(
ethers.BigNumber.from(INITIAL_TOTAL_SUPPLY - withdrawAmount)
)
// Assert the correct cross-chain call was sent:
// Message should be sent to the L1L1StandardBridge on L1
expect(withdrawalCallToMessenger._target).to.equal(DUMMY_L1BRIDGE_ADDRESS)
expect(withdrawalCallToMessenger.args[0]).to.equal(DUMMY_L1BRIDGE_ADDRESS)
// Message data should be a call telling the L1L1StandardBridge to finalize the withdrawal
expect(withdrawalCallToMessenger._message).to.equal(
expect(withdrawalCallToMessenger.args[1]).to.equal(
Factory__L1StandardBridge.interface.encodeFunctionData(
'finalizeERC20Withdrawal',
[
DUMMY_L1TOKEN_ADDRESS,
SmoddedL2Token.address,
Mock__L2Token.address,
await alice.getAddress(),
await alice.getAddress(),
withdrawAmount,
......@@ -285,22 +276,22 @@ describe('L2StandardBridge', () => {
)
)
// gaslimit should be correct
expect(withdrawalCallToMessenger._gasLimit).to.equal(0)
expect(withdrawalCallToMessenger.args[2]).to.equal(0)
})
it('withdrawTo() burns and sends the correct withdrawal message', async () => {
await L2StandardBridge.withdrawTo(
SmoddedL2Token.address,
Mock__L2Token.address,
await bob.getAddress(),
withdrawAmount,
0,
NON_NULL_BYTES32
)
const withdrawalCallToMessenger =
Mock__L2CrossDomainMessenger.smocked.sendMessage.calls[0]
Fake__L2CrossDomainMessenger.sendMessage.getCall(0)
// Assert Alice's balance went down
const aliceBalance = await SmoddedL2Token.balanceOf(
const aliceBalance = await Mock__L2Token.balanceOf(
await alice.getAddress()
)
expect(aliceBalance).to.deep.equal(
......@@ -308,21 +299,21 @@ describe('L2StandardBridge', () => {
)
// Assert totalSupply went down
const newTotalSupply = await SmoddedL2Token.totalSupply()
const newTotalSupply = await Mock__L2Token.totalSupply()
expect(newTotalSupply).to.deep.equal(
ethers.BigNumber.from(INITIAL_TOTAL_SUPPLY - withdrawAmount)
)
// Assert the correct cross-chain call was sent.
// Message should be sent to the L1L1StandardBridge on L1
expect(withdrawalCallToMessenger._target).to.equal(DUMMY_L1BRIDGE_ADDRESS)
expect(withdrawalCallToMessenger.args[0]).to.equal(DUMMY_L1BRIDGE_ADDRESS)
// The message data should be a call telling the L1L1StandardBridge to finalize the withdrawal
expect(withdrawalCallToMessenger._message).to.equal(
expect(withdrawalCallToMessenger.args[1]).to.equal(
Factory__L1StandardBridge.interface.encodeFunctionData(
'finalizeERC20Withdrawal',
[
DUMMY_L1TOKEN_ADDRESS,
SmoddedL2Token.address,
Mock__L2Token.address,
await alice.getAddress(),
await bob.getAddress(),
withdrawAmount,
......@@ -331,7 +322,7 @@ describe('L2StandardBridge', () => {
)
)
// gas value is ignored and set to 0.
expect(withdrawalCallToMessenger._gasLimit).to.equal(0)
expect(withdrawalCallToMessenger.args[2]).to.equal(0)
})
})
......
/* External Imports */
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smoddit } from '@eth-optimism/smock'
import {
smock,
MockContractFactory,
MockContract,
} from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -9,13 +13,13 @@ import { predeploys, getContractInterface } from '../../../../src'
describe('L2StandardTokenFactory', () => {
let signer: Signer
let Factory__L1ERC20: ContractFactory
let L1ERC20: Contract
let Factory__L1ERC20: MockContractFactory<ContractFactory>
let L1ERC20: MockContract<Contract>
let L2StandardTokenFactory: Contract
before(async () => {
;[signer] = await ethers.getSigners()
// deploy an ERC20 contract on L1
Factory__L1ERC20 = await smoddit(
Factory__L1ERC20 = await smock.mock(
'@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20'
)
L1ERC20 = await Factory__L1ERC20.deploy('L1ERC20', 'ERC')
......
/* External Imports */
import { ethers } from 'hardhat'
import { ContractFactory, Contract } from 'ethers'
import { MockContract, smockit } from '@eth-optimism/smock'
import { smock, FakeContract } from '@defi-wonderland/smock'
import { remove0x } from '@eth-optimism/core-utils'
import { keccak256 } from 'ethers/lib/utils'
......@@ -25,9 +25,9 @@ const callPredeploy = async (
// TODO: rewrite this test to bypass the execution manager
describe.skip('OVM_L2ToL1MessagePasser', () => {
let Mock__OVM_ExecutionManager: MockContract
let Fake__OVM_ExecutionManager: FakeContract
before(async () => {
Mock__OVM_ExecutionManager = await smockit(
Fake__OVM_ExecutionManager = await smock.fake<Contract>(
await ethers.getContractFactory('OVM_ExecutionManager')
)
})
......@@ -38,7 +38,7 @@ describe.skip('OVM_L2ToL1MessagePasser', () => {
await ethers.getContractFactory('Helper_PredeployCaller')
).deploy()
Helper_PredeployCaller.setTarget(Mock__OVM_ExecutionManager.address)
Helper_PredeployCaller.setTarget(Fake__OVM_ExecutionManager.address)
})
let Factory__OVM_L2ToL1MessagePasser: ContractFactory
......@@ -55,9 +55,7 @@ describe.skip('OVM_L2ToL1MessagePasser', () => {
describe('passMessageToL1', () => {
before(async () => {
Mock__OVM_ExecutionManager.smocked.ovmCALLER.will.return.with(
NON_ZERO_ADDRESS
)
Fake__OVM_ExecutionManager.ovmCALLER.returns(NON_ZERO_ADDRESS)
})
for (const size of ELEMENT_TEST_SIZES) {
......
/* Imports: External */
import hre from 'hardhat'
import { MockContract, smockit } from '@eth-optimism/smock'
import { smock, FakeContract } from '@defi-wonderland/smock'
import { Contract, Signer } from 'ethers'
/* Imports: Internal */
......@@ -13,9 +13,9 @@ describe('OVM_SequencerFeeVault', () => {
;[signer1] = await hre.ethers.getSigners()
})
let Mock__L2StandardBridge: MockContract
let Fake__L2StandardBridge: FakeContract
before(async () => {
Mock__L2StandardBridge = await smockit('L2StandardBridge', {
Fake__L2StandardBridge = await smock.fake<Contract>('L2StandardBridge', {
address: predeploys.L2StandardBridge,
})
})
......@@ -42,13 +42,21 @@ describe('OVM_SequencerFeeVault', () => {
await expect(OVM_SequencerFeeVault.withdraw()).to.not.be.reverted
expect(Mock__L2StandardBridge.smocked.withdrawTo.calls[0]).to.deep.equal([
predeploys.OVM_ETH,
await signer1.getAddress(),
amount,
0,
'0x',
])
expect(
Fake__L2StandardBridge.withdrawTo.getCall(0).args[0]
).to.deep.equal(predeploys.OVM_ETH)
expect(
Fake__L2StandardBridge.withdrawTo.getCall(0).args[1]
).to.deep.equal(await signer1.getAddress())
expect(
Fake__L2StandardBridge.withdrawTo.getCall(0).args[2]
).to.deep.equal(amount)
expect(
Fake__L2StandardBridge.withdrawTo.getCall(0).args[3]
).to.deep.equal(0)
expect(
Fake__L2StandardBridge.withdrawTo.getCall(0).args[4]
).to.deep.equal('0x')
})
it('should succeed when the contract has more than sufficient balance', async () => {
......@@ -62,14 +70,21 @@ describe('OVM_SequencerFeeVault', () => {
})
await expect(OVM_SequencerFeeVault.withdraw()).to.not.be.reverted
expect(Mock__L2StandardBridge.smocked.withdrawTo.calls[0]).to.deep.equal([
predeploys.OVM_ETH,
await signer1.getAddress(),
amount,
0,
'0x',
])
expect(
Fake__L2StandardBridge.withdrawTo.getCall(1).args[0]
).to.deep.equal(predeploys.OVM_ETH)
expect(
Fake__L2StandardBridge.withdrawTo.getCall(1).args[1]
).to.deep.equal(await signer1.getAddress())
expect(
Fake__L2StandardBridge.withdrawTo.getCall(1).args[2]
).to.deep.equal(amount)
expect(
Fake__L2StandardBridge.withdrawTo.getCall(1).args[3]
).to.deep.equal(0)
expect(
Fake__L2StandardBridge.withdrawTo.getCall(1).args[4]
).to.deep.equal('0x')
})
it('should have an owner in storage slot 0x00...00', async () => {
......
/* Imports: External */
import hre from 'hardhat'
import { Contract, Signer } from 'ethers'
import { smockit } from '@eth-optimism/smock'
import { smock } from '@defi-wonderland/smock'
/* Imports: Internal */
import { expect } from '../../setup'
......@@ -170,11 +170,13 @@ describe('L1ChugSplashProxy', () => {
})
it('should throw an error if the owner has signalled an upgrade', async () => {
const owner = await smockit(getContractInterface('iL1ChugSplashDeployer'))
const owner = await smock.fake<Contract>(
getContractInterface('iL1ChugSplashDeployer')
)
const factory = await hre.ethers.getContractFactory('L1ChugSplashProxy')
const proxy = await factory.deploy(owner.address)
owner.smocked.isUpgrading.will.return.with(true)
owner.isUpgrading.returns(true)
await expect(
owner.wallet.sendTransaction({
......
/* External Imports */
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
import { FakeContract } from '@defi-wonderland/smock'
export const setProxyTarget = async (
AddressManager: Contract,
name: string,
target: Contract
target: FakeContract
): Promise<void> => {
const SimpleProxy: Contract = await (
await ethers.getContractFactory('Helper_SimpleProxy')
......
ignores: [
"@eth-optimism/core-utils",
"ts-mocha",
]
\ No newline at end of file
"typedoc",
]
......@@ -4,19 +4,33 @@
The `@eth-optimism/sdk` package provides a set of tools for interacting with Optimism.
## NOTICE
WARNING: This package is currently under construction.
You can definitely try to use it, but you probably won't have a good time.
Lots of pieces are missing.
We will announce the 1.0.0 release on Discord and on Twitter once it's ready, keep an eye out!
## Installation
```
npm install @eth-optimism/sdk
```
## API
## Docs
You can find auto-generated API documentation over at [sdk.optimism.io](https://sdk.optimism.io).
## Using the SDK
### CrossChainMessenger
The [`CrossChainMessenger`](https://github.com/ethereum-optimism/optimism/blob/develop/packages/sdk/src/cross-chain-messenger.ts) class simplifies the process of moving assets and data between Ethereum and Optimism.
You can use this class to, for example, initiate a withdrawal of ERC20 tokens from Optimism back to Ethereum, accurately track when the withdrawal is ready to be finalized on Ethereum, and execute the finalization transaction after the challenge period has elapsed.
The `CrossChainMessenger` can handle deposits and withdrawals of ETH and any ERC20-compatible token.
Detailed API descriptions can be found at [sdk.optimism.io](https://sdk.optimism.io/classes/crosschainmessenger).
The `CrossChainMessenger` automatically connects to all relevant contracts so complex configuration is not necessary.
### L2Provider and related utilities
The Optimism SDK includes [various utilities](https://github.com/ethereum-optimism/optimism/blob/develop/packages/sdk/src/l2-provider.ts) for handling Optimism's [transaction fee model](https://community.optimism.io/docs/developers/build/transaction-fees/).
For instance, [`estimateTotalGasCost`](https://sdk.optimism.io/modules.html#estimateTotalGasCost) will estimate the total cost (in wei) to send at transaction on Optimism including both the L2 execution cost and the L1 data cost.
You can also use the [`asL2Provider`](https://sdk.optimism.io/modules.html#asL2Provider) function to wrap an ethers Provider object into an `L2Provider` which will have all of these helper functions attached.
### Other utilities
TODO: Fill this in once the initial package version is finished.
The SDK contains other useful helper functions and constants.
For a complete list, refer to the auto-generated [SDK documentation](https://sdk.optimism.io/)
......@@ -16,7 +16,8 @@
"lint:fix": "yarn lint:check --fix",
"pre-commit": "lint-staged",
"test": "hardhat test",
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json"
"test:coverage": "nyc hardhat test && nyc merge .nyc_output coverage.json",
"autogen:docs": "typedoc --out docs src/index.ts"
},
"keywords": [
"optimism",
......@@ -60,6 +61,7 @@
"nyc": "^15.1.0",
"prettier": "^2.3.1",
"ts-mocha": "^8.0.0",
"typedoc": "^0.22.13",
"typescript": "^4.3.5"
},
"dependencies": {
......
......@@ -64,7 +64,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
*
* @param opts Options for the provider.
* @param opts.l1SignerOrProvider Signer or Provider for the L1 chain, or a JSON-RPC url.
* @param opts.l1SignerOrProvider Signer or Provider for the L2 chain, or a JSON-RPC url.
* @param opts.l2SignerOrProvider Signer or Provider for the L2 chain, or a JSON-RPC url.
* @param opts.l1ChainId Chain ID for the L1 chain.
* @param opts.depositConfirmationBlocks Optional number of blocks before a deposit is confirmed.
* @param opts.l1BlockTimeSeconds Optional estimated block time in seconds for the L1 chain.
......
......@@ -497,23 +497,6 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
"@eth-optimism/core-utils@^0.5.1":
version "0.5.5"
resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.5.5.tgz#0e2bb95b23965fb51adfb8ba6841c3afd26a6411"
integrity sha512-N/uyZjHltnvnQyBOE498EGlqeYvWRUQTW6BpXhexKljEXZpnria4J4MFO9s1lJOpogLXTaS+lhM1Ic8zUNj8Pg==
dependencies:
"@ethersproject/abstract-provider" "^5.4.1"
ethers "^5.4.5"
lodash "^4.17.21"
"@eth-optimism/smock@1.1.10":
version "1.1.10"
resolved "https://registry.yarnpkg.com/@eth-optimism/smock/-/smock-1.1.10.tgz#98a6eefc994ccf707f52ab06849468f3cc57bdb7"
integrity sha512-XPx1x9odF/noTBHzIhRgL9ihhr769WgUhf9dOm6X7bjSWRAVsII3IqbdB4ssPycaoSuNSmv8HG1xTLgfgcyOYw==
dependencies:
"@eth-optimism/core-utils" "^0.5.1"
bn.js "^5.2.0"
"@ethereum-waffle/chai@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@ethereum-waffle/chai/-/chai-3.4.0.tgz#2477877410a96bf370edd64df905b04fb9aba9d5"
......@@ -712,7 +695,7 @@
"@ethersproject/properties" "^5.4.0"
"@ethersproject/strings" "^5.4.0"
"@ethersproject/abstract-provider@5.4.1", "@ethersproject/abstract-provider@^5.4.0", "@ethersproject/abstract-provider@^5.4.1":
"@ethersproject/abstract-provider@5.4.1", "@ethersproject/abstract-provider@^5.4.0":
version "5.4.1"
resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.4.1.tgz#e404309a29f771bd4d28dbafadcaa184668c2a6e"
integrity sha512-3EedfKI3LVpjSKgAxoUaI+gB27frKsxzm+r21w9G60Ugk+3wVLQwhi1LsEJAKNV7WoZc8CIpNrATlL1QFABjtQ==
......@@ -4574,6 +4557,13 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
brace-expansion@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
dependencies:
balanced-match "^1.0.0"
braces@^2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
......@@ -7176,7 +7166,7 @@ ethers@^4.0.32, ethers@^4.0.40:
uuid "2.0.1"
xmlhttprequest "1.8.0"
ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.2, ethers@^5.4.5:
ethers@^5.0.0, ethers@^5.0.1, ethers@^5.0.2:
version "5.4.5"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.4.5.tgz#cec133b9f5b514dc55e2561ee7aa7218c33affd7"
integrity sha512-PPZ6flOAj230sXEWf/r/It6ZZ5c7EOVWx+PU87Glkbg79OtT7pLE1WgL4MRdwx6iF7HzSOvUUI+8cAmcdzo12w==
......@@ -8219,6 +8209,18 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, gl
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
global-modules@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
......@@ -9697,6 +9699,11 @@ json5@^2.1.0, json5@^2.1.2, json5@^2.2.0:
dependencies:
minimist "^1.2.5"
jsonc-parser@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.0.0.tgz#abdd785701c7e7eaca8a9ec8cf070ca51a745a22"
integrity sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==
jsonfile@^2.1.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8"
......@@ -10418,6 +10425,11 @@ ltgt@~2.1.1:
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34"
integrity sha1-EIUaBtmWS5cReEQcI8nlJpjuzjQ=
lunr@^2.3.9:
version "2.3.9"
resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1"
integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==
make-dir@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
......@@ -10532,6 +10544,11 @@ marked@^0.7.0:
resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e"
integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==
marked@^4.0.12:
version "4.0.12"
resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.12.tgz#2262a4e6fd1afd2f13557726238b69a48b982f7d"
integrity sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==
match-all@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/match-all/-/match-all-1.2.6.tgz#66d276ad6b49655551e63d3a6ee53e8be0566f8d"
......@@ -10847,6 +10864,13 @@ minimalistic-crypto-utils@^1.0.1:
dependencies:
brace-expansion "^1.1.7"
minimatch@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b"
integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==
dependencies:
brace-expansion "^2.0.1"
minimist-options@4.1.0, minimist-options@^4.0.2:
version "4.1.0"
resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
......@@ -13700,6 +13724,15 @@ shelljs@^0.8.3:
interpret "^1.0.0"
rechoir "^0.6.2"
shiki@^0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14"
integrity sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==
dependencies:
jsonc-parser "^3.0.0"
vscode-oniguruma "^1.6.1"
vscode-textmate "5.2.0"
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
......@@ -15138,6 +15171,17 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typedoc@^0.22.13:
version "0.22.13"
resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.22.13.tgz#d061f8f0fb7c9d686e48814f245bddeea4564e66"
integrity sha512-NHNI7Dr6JHa/I3+c62gdRNXBIyX7P33O9TafGLd07ur3MqzcKgwTvpg18EtvCLHJyfeSthAtCLpM7WkStUmDuQ==
dependencies:
glob "^7.2.0"
lunr "^2.3.9"
marked "^4.0.12"
minimatch "^5.0.1"
shiki "^0.10.1"
typescript@^4.3.4, typescript@^4.3.5:
version "4.3.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
......@@ -15460,6 +15504,16 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vscode-oniguruma@^1.6.1:
version "1.6.2"
resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz#aeb9771a2f1dbfc9083c8a7fdd9cccaa3f386607"
integrity sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==
vscode-textmate@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-5.2.0.tgz#01f01760a391e8222fe4f33fbccbd1ad71aed74e"
integrity sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==
wcwidth@^1.0.0, wcwidth@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
......
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