Commit e4fbde24 authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

Merge pull request #2430 from ethereum-optimism/develop

Develop -> Master PR
parents 71240b1d 1d2567cd
---
'@eth-optimism/go-builder': patch
'@eth-optimism/js-builder': patch
---
Trigger releases
---
'@eth-optimism/sdk': minor
---
New isL2Provider helper function. Internal cleanups.
---
'@eth-optimism/contracts': patch
---
Remove l2 gas price hardhat task
...@@ -37,4 +37,6 @@ M-ops: ...@@ -37,4 +37,6 @@ M-ops:
- any: ['ops/**/*'] - any: ['ops/**/*']
C-Protocol-Critical: C-Protocol-Critical:
- any: ['packages/data-transport-layer/**/*.ts', 'packages/contracts/**/*.sol', 'l2geth/**/*.go'] - 'packages/data-transport-layer/**/*.ts'
- 'packages/contracts/**/*.sol'
- 'l2geth/**/*.go'
---
name: 'Changeset integrity checker'
on:
- pull_request_target
jobs:
changesets-integrity-checker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: 'changeset status'
run: npx changeset status
...@@ -12,6 +12,6 @@ jobs: ...@@ -12,6 +12,6 @@ jobs:
stale-pr-message: 'This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days.' stale-pr-message: 'This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
exempt-pr-labels: exempt-stale exempt-pr-labels: exempt-stale
days-before-issue-stale: 999 days-before-issue-stale: 999
dats-before-pr-stale: 14 days-before-pr-stale: 14
days-before-close: 5 days-before-close: 5
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
...@@ -152,7 +152,7 @@ jobs: ...@@ -152,7 +152,7 @@ jobs:
go-builder: go-builder:
name: Publish go-builder ${{ needs.release.outputs.go-builder }} name: Publish go-builder ${{ needs.release.outputs.go-builder }}
needs: release needs: release
if: needs.release.go-builder != '' if: needs.release.outputs.go-builder != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
...@@ -178,7 +178,7 @@ jobs: ...@@ -178,7 +178,7 @@ jobs:
js-builder: js-builder:
name: Publish js-builder ${{ needs.release.outputs.js-builder }} name: Publish js-builder ${{ needs.release.outputs.js-builder }}
needs: release needs: release
if: needs.release.js-builder != '' if: needs.release.outputs.js-builder != ''
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
......
#!/bin/sh
set -e
RPC_URL=${RPC_URL:-http://localhost:8545}
OVM_GAS_ORACLE=0x420000000000000000000000000000000000000F
function send_tx() {
cast send --rpc-url $RPC_URL \
--private-key $PRIVATE_KEY \
--legacy \
--gas-price 0 \
$OVM_GAS_ORACLE \
$1 \
$2
}
function call() {
cast call --rpc-url $RPC_URL \
$OVM_GAS_ORACLE \
$1
}
echo "Scalar: $(call 'scalar()(uint256)')"
echo "L2 gas price: $(call 'gasPrice()(uint256)')"
echo "Overhead: $(call 'overhead()(uint256)')"
if [[ ! -z $PRIVATE_KEY ]]; then
if [[ ! -z $SCALAR ]]; then
echo "Setting scalar to $SCALAR"
send_tx 'setScalar(uint256)' $SCALAR
fi
if [[ ! -z $OVERHEAD ]]; then
echo "Setting overhead to $OVERHEAD"
send_tx 'setOverhead(uint256)' $OVERHEAD
fi
if [[ ! -z $L2_GAS_PRICE ]]; then
echo "Setting L2 gas price to $L2_GAS_PRICE"
send_tx 'setGasPrice(uint256)' $L2_GAS_PRICE
fi
fi
export * from './l2-gasprice'
export * from './set-owner' export * from './set-owner'
export * from './take-dump' export * from './take-dump'
export * from './validate-address-dictator' export * from './validate-address-dictator'
......
/* Imports: External */
import { ethers } from 'ethers'
import { task } from 'hardhat/config'
import * as types from 'hardhat/internal/core/params/argumentTypes'
import { predeploys } from '../src/predeploys'
import { getContractDefinition } from '../src/contract-defs'
task('set-l2-gasprice')
.addOptionalParam(
'l2GasPrice',
'Gas Price to set on L2',
undefined,
types.int
)
.addOptionalParam('transactionGasPrice', 'tx.gasPrice', undefined, types.int)
.addOptionalParam(
'overhead',
'amortized additional gas used by each batch that users must pay for',
undefined,
types.int
)
.addOptionalParam(
'scalar',
'amount to scale up the gas to charge',
undefined,
types.int
)
.addOptionalParam(
'contractsRpcUrl',
'Sequencer HTTP Endpoint',
process.env.CONTRACTS_RPC_URL,
types.string
)
.addOptionalParam(
'contractsDeployerKey',
'Private Key',
process.env.CONTRACTS_DEPLOYER_KEY,
types.string
)
.setAction(async (args) => {
const provider = new ethers.providers.JsonRpcProvider(args.contractsRpcUrl)
const signer = new ethers.Wallet(args.contractsDeployerKey).connect(
provider
)
const GasPriceOracleArtifact = getContractDefinition('OVM_GasPriceOracle')
const GasPriceOracle = new ethers.Contract(
predeploys.OVM_GasPriceOracle,
GasPriceOracleArtifact.abi,
signer
)
const addr = await signer.getAddress()
console.log(`Using signer ${addr}`)
const owner = await GasPriceOracle.callStatic.owner()
if (owner !== addr) {
throw new Error(`Incorrect key. Owner ${owner}, Signer ${addr}`)
}
// List the current values
const gasPrice = await GasPriceOracle.callStatic.gasPrice()
const scalar = await GasPriceOracle.callStatic.scalar()
const overhead = await GasPriceOracle.callStatic.overhead()
console.log('Current values:')
console.log(`Gas Price: ${gasPrice.toString()}`)
console.log(`Scalar: ${scalar.toString()}`)
console.log(`Overhead: ${overhead.toString()}`)
if (args.l2GasPrice !== undefined) {
console.log(`Setting gas price to ${args.l2GasPrice}`)
const tx = await GasPriceOracle.connect(signer).setGasPrice(
args.l2GasPrice,
{ gasPrice: args.transactionGasPrice }
)
const receipt = await tx.wait()
console.log(`Success - ${receipt.transactionHash}`)
}
if (args.scalar !== undefined) {
console.log(`Setting scalar to ${args.scalar}`)
const tx = await GasPriceOracle.connect(signer).setScalar(args.scalar, {
gasPrice: args.transactionGasPrice,
})
const receipt = await tx.wait()
console.log(`Success - ${receipt.transactionHash}`)
}
if (args.overhead !== undefined) {
console.log(`Setting overhead to ${args.overhead}`)
const tx = await GasPriceOracle.connect(signer).setOverhead(
args.overhead,
{ gasPrice: args.transactionGasPrice }
)
const receipt = await tx.wait()
console.log(`Success - ${receipt.transactionHash}`)
}
})
/* External Imports */
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import { Contract, Signer, ContractFactory } from 'ethers' import { Contract, Signer } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup' import { expect } from '../../../setup'
import { NON_ZERO_ADDRESS } from '../../../helpers' import { deploy, NON_ZERO_ADDRESS } from '../../../helpers'
describe('AddressDictator', () => { describe('AddressDictator', () => {
let signer: Signer let signer1: Signer
let otherSigner: Signer let signer2: Signer
let signerAddress: string
let Factory__AddressDictator: ContractFactory
let Factory__Lib_AddressManager: ContractFactory
before(async () => { before(async () => {
;[signer, otherSigner] = await ethers.getSigners() ;[signer1, signer2] = await ethers.getSigners()
Factory__AddressDictator = await ethers.getContractFactory(
'AddressDictator'
)
Factory__Lib_AddressManager = await ethers.getContractFactory(
'Lib_AddressManager'
)
signerAddress = await signer.getAddress()
}) })
let AddressDictator: Contract let AddressDictator: Contract
let Lib_AddressManager: Contract let Lib_AddressManager: Contract
beforeEach(async () => { beforeEach(async () => {
Lib_AddressManager = await Factory__Lib_AddressManager.connect( Lib_AddressManager = await deploy('Lib_AddressManager', {
signer signer: signer1,
).deploy() })
AddressDictator = await Factory__AddressDictator.connect(signer).deploy( AddressDictator = await deploy('AddressDictator', {
Lib_AddressManager.address, signer: signer1,
signerAddress, args: [
['addr1'], Lib_AddressManager.address,
[NON_ZERO_ADDRESS] await signer1.getAddress(),
) ['addr1'],
[NON_ZERO_ADDRESS],
],
})
Lib_AddressManager.transferOwnership(AddressDictator.address) Lib_AddressManager.connect(signer1).transferOwnership(
AddressDictator.address
)
}) })
describe('initialize', () => { describe('initialize', () => {
it('should revert when providing wrong arguments', async () => { it('should revert when providing wrong arguments', async () => {
await expect( await expect(
Factory__AddressDictator.connect(signer).deploy( deploy('AddressDictator', {
Lib_AddressManager.address, signer: signer1,
signerAddress, args: [
['addr1', 'addr2'], Lib_AddressManager.address,
[NON_ZERO_ADDRESS] await signer1.getAddress(),
) ['addr1', 'addr2'],
[NON_ZERO_ADDRESS],
],
})
).to.be.revertedWith( ).to.be.revertedWith(
'AddressDictator: Must provide an equal number of names and addresses.' 'AddressDictator: Must provide an equal number of names and addresses.'
) )
...@@ -61,7 +54,7 @@ describe('AddressDictator', () => { ...@@ -61,7 +54,7 @@ describe('AddressDictator', () => {
describe('setAddresses', async () => { describe('setAddresses', async () => {
it('should change the addresses associated with a name', async () => { it('should change the addresses associated with a name', async () => {
await AddressDictator.setAddresses() await AddressDictator.setAddresses()
expect(await Lib_AddressManager.getAddress('addr1')).to.be.equal( expect(await Lib_AddressManager.getAddress('addr1')).to.equal(
NON_ZERO_ADDRESS NON_ZERO_ADDRESS
) )
}) })
...@@ -69,7 +62,7 @@ describe('AddressDictator', () => { ...@@ -69,7 +62,7 @@ describe('AddressDictator', () => {
describe('getNamedAddresses', () => { describe('getNamedAddresses', () => {
it('should return all the addresses and their names', async () => { it('should return all the addresses and their names', async () => {
expect(await AddressDictator.getNamedAddresses()).to.be.deep.equal([ expect(await AddressDictator.getNamedAddresses()).to.deep.equal([
['addr1', NON_ZERO_ADDRESS], ['addr1', NON_ZERO_ADDRESS],
]) ])
}) })
...@@ -77,13 +70,13 @@ describe('AddressDictator', () => { ...@@ -77,13 +70,13 @@ describe('AddressDictator', () => {
describe('returnOwnership', () => { describe('returnOwnership', () => {
it('should transfer contract ownership to finalOwner', async () => { it('should transfer contract ownership to finalOwner', async () => {
await expect(AddressDictator.connect(signer).returnOwnership()).to.not.be await expect(AddressDictator.connect(signer1).returnOwnership()).to.not.be
.reverted .reverted
}) })
it('should revert when called by non-owner', async () => { it('should revert when called by non-owner', async () => {
await expect( await expect(
AddressDictator.connect(otherSigner).returnOwnership() AddressDictator.connect(signer2).returnOwnership()
).to.be.revertedWith('AddressDictator: only callable by finalOwner') ).to.be.revertedWith('AddressDictator: only callable by finalOwner')
}) })
}) })
......
/* External Imports */
import { ethers } from 'hardhat' import { ethers } from 'hardhat'
import { Contract, Signer, ContractFactory } from 'ethers' import { Contract, Signer } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup' import { expect } from '../../../setup'
import { deploy } from '../../../helpers'
describe('ChugSplashDictator', () => { describe('ChugSplashDictator', () => {
let signer: Signer let signer1: Signer
let otherSigner: Signer let signer2: Signer
let signerAddress: string
let Factory__L1ChugSplashProxy: ContractFactory
let Factory__ChugSplashDictator: ContractFactory
before(async () => { before(async () => {
;[signer, otherSigner] = await ethers.getSigners() ;[signer1, signer2] = await ethers.getSigners()
Factory__L1ChugSplashProxy = await ethers.getContractFactory(
'L1ChugSplashProxy'
)
Factory__ChugSplashDictator = await ethers.getContractFactory(
'ChugSplashDictator'
)
signerAddress = await signer.getAddress()
}) })
let L1ChugSplashProxy: Contract let L1ChugSplashProxy: Contract
let ChugSplashDictator: Contract let ChugSplashDictator: Contract
beforeEach(async () => { beforeEach(async () => {
L1ChugSplashProxy = await Factory__L1ChugSplashProxy.connect(signer).deploy( L1ChugSplashProxy = await deploy('L1ChugSplashProxy', {
signerAddress signer: signer1,
) args: [await signer1.getAddress()],
})
ChugSplashDictator = await Factory__ChugSplashDictator.connect( ChugSplashDictator = await deploy('ChugSplashDictator', {
signer signer: signer1,
).deploy( args: [
L1ChugSplashProxy.address, L1ChugSplashProxy.address,
signerAddress, await signer1.getAddress(),
ethers.utils.keccak256('0x1111'), ethers.utils.keccak256('0x1111'),
ethers.utils.keccak256('0x1234'), ethers.utils.keccak256('0x1234'),
ethers.utils.keccak256('0x5678'), ethers.utils.keccak256('0x5678'),
ethers.utils.keccak256('0x1234'), ethers.utils.keccak256('0x1234'),
ethers.utils.keccak256('0x1234') ethers.utils.keccak256('0x1234'),
) ],
})
await L1ChugSplashProxy.connect(signer).setOwner(ChugSplashDictator.address) await L1ChugSplashProxy.connect(signer1).setOwner(
ChugSplashDictator.address
)
}) })
describe('doActions', () => { describe('doActions', () => {
...@@ -56,20 +45,20 @@ describe('ChugSplashDictator', () => { ...@@ -56,20 +45,20 @@ describe('ChugSplashDictator', () => {
}) })
it('should set the proxy code, storage & owner', async () => { it('should set the proxy code, storage & owner', async () => {
await expect(ChugSplashDictator.connect(signer).doActions('0x1111')).to await expect(ChugSplashDictator.connect(signer1).doActions('0x1111')).to
.not.be.reverted .not.be.reverted
}) })
}) })
describe('returnOwnership', () => { describe('returnOwnership', () => {
it('should transfer contractc ownership to finalOwner', async () => { it('should transfer contractc ownership to finalOwner', async () => {
await expect(ChugSplashDictator.connect(signer).returnOwnership()).to.not await expect(ChugSplashDictator.connect(signer1).returnOwnership()).to.not
.be.reverted .be.reverted
}) })
it('should revert when called by non-owner', async () => { it('should revert when called by non-owner', async () => {
await expect( await expect(
ChugSplashDictator.connect(otherSigner).returnOwnership() ChugSplashDictator.connect(signer2).returnOwnership()
).to.be.revertedWith('ChugSplashDictator: only callable by finalOwner') ).to.be.revertedWith('ChugSplashDictator: only callable by finalOwner')
}) })
}) })
......
/* Imports: External */
import hre from 'hardhat' import hre from 'hardhat'
import { Contract, Signer } from 'ethers' import { Contract, Signer } from 'ethers'
import { smock } from '@defi-wonderland/smock' import { smock } from '@defi-wonderland/smock'
/* Imports: Internal */
import { expect } from '../../setup' import { expect } from '../../setup'
import { getContractInterface } from '../../../src' import { getContractInterface } from '../../../src'
import { deploy } from '../../helpers'
describe('L1ChugSplashProxy', () => { describe('L1ChugSplashProxy', () => {
let signer1: Signer let signer1: Signer
...@@ -16,12 +15,9 @@ describe('L1ChugSplashProxy', () => { ...@@ -16,12 +15,9 @@ describe('L1ChugSplashProxy', () => {
let L1ChugSplashProxy: Contract let L1ChugSplashProxy: Contract
beforeEach(async () => { beforeEach(async () => {
const Factory__L1ChugSplashProxy = await hre.ethers.getContractFactory( L1ChugSplashProxy = await deploy('L1ChugSplashProxy', {
'L1ChugSplashProxy' args: [await signer1.getAddress()],
) })
L1ChugSplashProxy = await Factory__L1ChugSplashProxy.deploy(
await signer1.getAddress()
)
}) })
describe('getOwner', () => { describe('getOwner', () => {
...@@ -173,14 +169,16 @@ describe('L1ChugSplashProxy', () => { ...@@ -173,14 +169,16 @@ describe('L1ChugSplashProxy', () => {
const owner = await smock.fake<Contract>( const owner = await smock.fake<Contract>(
getContractInterface('iL1ChugSplashDeployer') getContractInterface('iL1ChugSplashDeployer')
) )
const factory = await hre.ethers.getContractFactory('L1ChugSplashProxy')
const proxy = await factory.deploy(owner.address) L1ChugSplashProxy = await deploy('L1ChugSplashProxy', {
args: [owner.address],
})
owner.isUpgrading.returns(true) owner.isUpgrading.returns(true)
await expect( await expect(
owner.wallet.sendTransaction({ owner.wallet.sendTransaction({
to: proxy.address, to: L1ChugSplashProxy.address,
data: '0x', data: '0x',
}) })
).to.be.revertedWith( ).to.be.revertedWith(
......
import hre from 'hardhat'
export const deploy = async (
name: string,
opts?: {
args?: any[]
signer?: any
}
) => {
const factory = await hre.ethers.getContractFactory(name, opts?.signer)
return factory.deploy(...(opts?.args || []))
}
export * from './eth-time' export * from './eth-time'
export * from './deploy'
...@@ -20,29 +20,29 @@ export class DAIBridgeAdapter extends StandardBridgeAdapter { ...@@ -20,29 +20,29 @@ export class DAIBridgeAdapter extends StandardBridgeAdapter {
[ [
{ {
inputs: [], inputs: [],
name: 'l1Token', name: 'l1Token' as const,
outputs: [ outputs: [
{ {
internalType: 'address', internalType: 'address' as const,
name: '', name: '' as const,
type: 'address', type: 'address' as const,
}, },
], ],
stateMutability: 'view', stateMutability: 'view' as const,
type: 'function', type: 'function' as const,
}, },
{ {
inputs: [], inputs: [],
name: 'l2Token', name: 'l2Token' as const,
outputs: [ outputs: [
{ {
internalType: 'address', internalType: 'address' as const,
name: '', name: '' as const,
type: 'address', type: 'address' as const,
}, },
], ],
stateMutability: 'view', stateMutability: 'view' as const,
type: 'function', type: 'function' as const,
}, },
], ],
this.messenger.l1Provider this.messenger.l1Provider
......
...@@ -119,7 +119,7 @@ export class ETHBridgeAdapter extends StandardBridgeAdapter { ...@@ -119,7 +119,7 @@ export class ETHBridgeAdapter extends StandardBridgeAdapter {
opts?: { opts?: {
overrides?: Overrides overrides?: Overrides
} }
): Promise<TransactionRequest> => { ): Promise<never> => {
throw new Error(`approvals not necessary for ETH bridge`) throw new Error(`approvals not necessary for ETH bridge`)
}, },
......
...@@ -109,7 +109,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -109,7 +109,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
if (Provider.isProvider(this.l1SignerOrProvider)) { if (Provider.isProvider(this.l1SignerOrProvider)) {
return this.l1SignerOrProvider return this.l1SignerOrProvider
} else { } else {
return this.l1SignerOrProvider.provider as any return this.l1SignerOrProvider.provider
} }
} }
...@@ -117,7 +117,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -117,7 +117,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
if (Provider.isProvider(this.l2SignerOrProvider)) { if (Provider.isProvider(this.l2SignerOrProvider)) {
return this.l2SignerOrProvider return this.l2SignerOrProvider
} else { } else {
return this.l2SignerOrProvider.provider as any return this.l2SignerOrProvider.provider
} }
} }
...@@ -144,10 +144,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -144,10 +144,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
} = {} } = {}
): Promise<CrossChainMessage[]> { ): Promise<CrossChainMessage[]> {
// Wait for the transaction receipt if the input is waitable. // Wait for the transaction receipt if the input is waitable.
// TODO: Maybe worth doing this with more explicit typing but whatever for now. await (transaction as TransactionResponse).wait?.()
if (typeof (transaction as any).wait === 'function') {
await (transaction as any).wait()
}
// Convert the input to a transaction hash. // Convert the input to a transaction hash.
const txHash = toTransactionHash(transaction) const txHash = toTransactionHash(transaction)
...@@ -821,7 +818,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -821,7 +818,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
) )
const stateTrieProof = await makeStateTrieProof( const stateTrieProof = await makeStateTrieProof(
this.l2Provider as any, this.l2Provider as ethers.providers.JsonRpcProvider,
resolved.blockNumber, resolved.blockNumber,
this.contracts.l2.OVM_L2ToL1MessagePasser.address, this.contracts.l2.OVM_L2ToL1MessagePasser.address,
messageSlot messageSlot
......
...@@ -83,4 +83,10 @@ export type L2Provider<TProvider extends Provider> = TProvider & { ...@@ -83,4 +83,10 @@ export type L2Provider<TProvider extends Provider> = TProvider & {
* @returns Estimated total gas cost. * @returns Estimated total gas cost.
*/ */
estimateTotalGasCost(tx: TransactionRequest): Promise<BigNumber> estimateTotalGasCost(tx: TransactionRequest): Promise<BigNumber>
/**
* Internal property to determine if a provider is a L2Provider
* You are likely looking for the isL2Provider function
*/
_isL2Provider: true
} }
...@@ -9,6 +9,16 @@ import { Contract, BigNumber } from 'ethers' ...@@ -9,6 +9,16 @@ import { Contract, BigNumber } from 'ethers'
import { ICrossChainMessenger } from './cross-chain-messenger' import { ICrossChainMessenger } from './cross-chain-messenger'
import { IBridgeAdapter } from './bridge-adapter' import { IBridgeAdapter } from './bridge-adapter'
/**
* Commonly used Chain IDs
*/
export enum Chain {
MAINNET = 1,
GOERLI = 5,
KOVAN = 42,
HARDHAT_LOCAL = 31337,
}
/** /**
* L1 contract references. * L1 contract references.
*/ */
......
import assert from 'assert'
import { Provider, TransactionRequest } from '@ethersproject/abstract-provider' import { Provider, TransactionRequest } from '@ethersproject/abstract-provider'
import { serialize } from '@ethersproject/transactions' import { serialize } from '@ethersproject/transactions'
import { Contract, BigNumber } from 'ethers' import { Contract, BigNumber } from 'ethers'
...@@ -7,6 +9,8 @@ import cloneDeep from 'lodash/cloneDeep' ...@@ -7,6 +9,8 @@ import cloneDeep from 'lodash/cloneDeep'
import { L2Provider, ProviderLike, NumberLike } from './interfaces' import { L2Provider, ProviderLike, NumberLike } from './interfaces'
import { toProvider, toNumber, toBigNumber } from './utils' import { toProvider, toNumber, toBigNumber } from './utils'
type ProviderTypeIsWrong = any
/** /**
* Returns a Contract object for the GasPriceOracle. * Returns a Contract object for the GasPriceOracle.
* *
...@@ -115,6 +119,24 @@ export const estimateTotalGasCost = async ( ...@@ -115,6 +119,24 @@ export const estimateTotalGasCost = async (
return l1GasCost.add(l2GasCost) return l1GasCost.add(l2GasCost)
} }
/**
* Determines if a given Provider is an L2Provider. Will coerce type
* if true
*
* @param provider The provider to check
* @returns Boolean
* @example
* if (isL2Provider(provider)) {
* // typescript now knows it is of type L2Provider
* const gasPrice = await provider.estimateL2GasPrice(tx)
* }
*/
export const isL2Provider = <TProvider extends Provider>(
provider: TProvider
): provider is L2Provider<TProvider> => {
return Boolean((provider as L2Provider<TProvider>)._isL2Provider)
}
/** /**
* Returns an provider wrapped as an Optimism L2 provider. Adds a few extra helper functions to * Returns an provider wrapped as an Optimism L2 provider. Adds a few extra helper functions to
* simplify the process of estimating the gas usage for a transaction on Optimism. Returns a COPY * simplify the process of estimating the gas usage for a transaction on Optimism. Returns a COPY
...@@ -126,22 +148,21 @@ export const estimateTotalGasCost = async ( ...@@ -126,22 +148,21 @@ export const estimateTotalGasCost = async (
export const asL2Provider = <TProvider extends Provider>( export const asL2Provider = <TProvider extends Provider>(
provider: TProvider provider: TProvider
): L2Provider<TProvider> => { ): L2Provider<TProvider> => {
// Make a copy of the provider since we'll be modifying some internals and don't want to mess
// with the original object.
const l2Provider = cloneDeep(provider) as any
// Skip if we've already wrapped this provider. // Skip if we've already wrapped this provider.
if (l2Provider._isL2Provider) { if (isL2Provider(provider)) {
return l2Provider return provider
} }
// Make a copy of the provider since we'll be modifying some internals and don't want to mess
// with the original object.
const l2Provider = cloneDeep(provider) as L2Provider<TProvider>
// Not exactly sure when the provider wouldn't have a formatter function, but throw an error if // Not exactly sure when the provider wouldn't have a formatter function, but throw an error if
// it doesn't have one. The Provider type doesn't define it but every provider I've dealt with // it doesn't have one. The Provider type doesn't define it but every provider I've dealt with
// seems to have it. // seems to have it.
const formatter = l2Provider.formatter // TODO this may be fixed if library has gotten updated since
if (formatter === undefined) { const formatter = (l2Provider as ProviderTypeIsWrong).formatter
throw new Error(`provider.formatter must be defined`) assert(formatter, `provider.formatter must be defined`)
}
// Modify the block formatter to return the state root. Not strictly related to Optimism, just a // Modify the block formatter to return the state root. Not strictly related to Optimism, just a
// generally useful thing that really should've been on the Ethers block object to begin with. // generally useful thing that really should've been on the Ethers block object to begin with.
......
import { Chain } from '../interfaces'
export const DEPOSIT_CONFIRMATION_BLOCKS = { export const DEPOSIT_CONFIRMATION_BLOCKS = {
// Mainnet [Chain.MAINNET]: 50 as const,
1: 50, [Chain.GOERLI]: 12 as const,
// Goerli [Chain.KOVAN]: 12 as const,
5: 12,
// Kovan
42: 12,
// Hardhat Local
// 2 just for testing purposes // 2 just for testing purposes
31337: 2, [Chain.HARDHAT_LOCAL]: 2 as const,
} }
export const CHAIN_BLOCK_TIMES = { export const CHAIN_BLOCK_TIMES = {
// Mainnet [Chain.MAINNET]: 13 as const,
1: 13, [Chain.GOERLI]: 15 as const,
// Goerli [Chain.KOVAN]: 4 as const,
5: 15, [Chain.HARDHAT_LOCAL]: 1 as const,
// Kovan
42: 4,
// Hardhat Local
31337: 1,
} }
...@@ -29,9 +29,9 @@ export const toSignerOrProvider = ( ...@@ -29,9 +29,9 @@ export const toSignerOrProvider = (
if (typeof signerOrProvider === 'string') { if (typeof signerOrProvider === 'string') {
return new ethers.providers.JsonRpcProvider(signerOrProvider) return new ethers.providers.JsonRpcProvider(signerOrProvider)
} else if (Provider.isProvider(signerOrProvider)) { } else if (Provider.isProvider(signerOrProvider)) {
return signerOrProvider as Provider return signerOrProvider
} else if (Signer.isSigner(signerOrProvider)) { } else if (Signer.isSigner(signerOrProvider)) {
return signerOrProvider as Signer return signerOrProvider
} else { } else {
throw new Error('Invalid provider') throw new Error('Invalid provider')
} }
...@@ -48,7 +48,7 @@ export const toProvider = (provider: ProviderLike): Provider => { ...@@ -48,7 +48,7 @@ export const toProvider = (provider: ProviderLike): Provider => {
if (typeof provider === 'string') { if (typeof provider === 'string') {
return new ethers.providers.JsonRpcProvider(provider) return new ethers.providers.JsonRpcProvider(provider)
} else if (Provider.isProvider(provider)) { } else if (Provider.isProvider(provider)) {
return provider as Provider return provider
} else { } else {
throw new Error('Invalid provider') throw new Error('Invalid provider')
} }
...@@ -66,7 +66,6 @@ export const toTransactionHash = (transaction: TransactionLike): string => { ...@@ -66,7 +66,6 @@ export const toTransactionHash = (transaction: TransactionLike): string => {
ethers.utils.isHexString(transaction, 32), ethers.utils.isHexString(transaction, 32),
'Invalid transaction hash' 'Invalid transaction hash'
) )
return transaction return transaction
} else if ((transaction as TransactionReceipt).transactionHash) { } else if ((transaction as TransactionReceipt).transactionHash) {
return (transaction as TransactionReceipt).transactionHash return (transaction as TransactionReceipt).transactionHash
......
...@@ -13,6 +13,7 @@ import { ...@@ -13,6 +13,7 @@ import {
BridgeAdapters, BridgeAdapters,
BridgeAdapterData, BridgeAdapterData,
ICrossChainMessenger, ICrossChainMessenger,
Chain,
} from '../interfaces' } from '../interfaces'
import { import {
StandardBridgeAdapter, StandardBridgeAdapter,
...@@ -40,9 +41,9 @@ export const DEFAULT_L2_CONTRACT_ADDRESSES: OEL2ContractsLike = { ...@@ -40,9 +41,9 @@ export const DEFAULT_L2_CONTRACT_ADDRESSES: OEL2ContractsLike = {
* back to the original contract names so we can look them up. * back to the original contract names so we can look them up.
*/ */
const NAME_REMAPPING = { const NAME_REMAPPING = {
AddressManager: 'Lib_AddressManager', AddressManager: 'Lib_AddressManager' as const,
OVM_L1BlockNumber: 'iOVM_L1BlockNumber', OVM_L1BlockNumber: 'iOVM_L1BlockNumber' as const,
WETH: 'WETH9', WETH: 'WETH9' as const,
} }
/** /**
...@@ -53,51 +54,59 @@ const NAME_REMAPPING = { ...@@ -53,51 +54,59 @@ const NAME_REMAPPING = {
export const CONTRACT_ADDRESSES: { export const CONTRACT_ADDRESSES: {
[l1ChainId: number]: OEContractsLike [l1ChainId: number]: OEContractsLike
} = { } = {
// Mainnet [Chain.MAINNET]: {
1: {
l1: { l1: {
AddressManager: '0xdE1FCfB0851916CA5101820A69b13a4E276bd81F', AddressManager: '0xdE1FCfB0851916CA5101820A69b13a4E276bd81F' as const,
L1CrossDomainMessenger: '0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1', L1CrossDomainMessenger:
L1StandardBridge: '0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1', '0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1' as const,
StateCommitmentChain: '0xBe5dAb4A2e9cd0F27300dB4aB94BeE3A233AEB19', L1StandardBridge: '0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1' as const,
CanonicalTransactionChain: '0x5E4e65926BA27467555EB562121fac00D24E9dD2', StateCommitmentChain:
BondManager: '0xcd626E1328b41fCF24737F137BcD4CE0c32bc8d1', '0xBe5dAb4A2e9cd0F27300dB4aB94BeE3A233AEB19' as const,
CanonicalTransactionChain:
'0x5E4e65926BA27467555EB562121fac00D24E9dD2' as const,
BondManager: '0xcd626E1328b41fCF24737F137BcD4CE0c32bc8d1' as const,
}, },
l2: DEFAULT_L2_CONTRACT_ADDRESSES, l2: DEFAULT_L2_CONTRACT_ADDRESSES,
}, },
// Kovan [Chain.KOVAN]: {
42: {
l1: { l1: {
AddressManager: '0x100Dd3b414Df5BbA2B542864fF94aF8024aFdf3a', AddressManager: '0x100Dd3b414Df5BbA2B542864fF94aF8024aFdf3a' as const,
L1CrossDomainMessenger: '0x4361d0F75A0186C05f971c566dC6bEa5957483fD', L1CrossDomainMessenger:
L1StandardBridge: '0x22F24361D548e5FaAfb36d1437839f080363982B', '0x4361d0F75A0186C05f971c566dC6bEa5957483fD' as const,
StateCommitmentChain: '0xD7754711773489F31A0602635f3F167826ce53C5', L1StandardBridge: '0x22F24361D548e5FaAfb36d1437839f080363982B' as const,
CanonicalTransactionChain: '0xf7B88A133202d41Fe5E2Ab22e6309a1A4D50AF74', StateCommitmentChain:
BondManager: '0xc5a603d273E28185c18Ba4d26A0024B2d2F42740', '0xD7754711773489F31A0602635f3F167826ce53C5' as const,
CanonicalTransactionChain:
'0xf7B88A133202d41Fe5E2Ab22e6309a1A4D50AF74' as const,
BondManager: '0xc5a603d273E28185c18Ba4d26A0024B2d2F42740' as const,
}, },
l2: DEFAULT_L2_CONTRACT_ADDRESSES, l2: DEFAULT_L2_CONTRACT_ADDRESSES,
}, },
// Goerli [Chain.GOERLI]: {
5: {
l1: { l1: {
AddressManager: '0x2F7E3cAC91b5148d336BbffB224B4dC79F09f01D', AddressManager: '0x2F7E3cAC91b5148d336BbffB224B4dC79F09f01D' as const,
L1CrossDomainMessenger: '0xEcC89b9EDD804850C4F343A278Be902be11AaF42', L1CrossDomainMessenger:
L1StandardBridge: '0x73298186A143a54c20ae98EEE5a025bD5979De02', '0xEcC89b9EDD804850C4F343A278Be902be11AaF42' as const,
StateCommitmentChain: '0x1afcA918eff169eE20fF8AB6Be75f3E872eE1C1A', L1StandardBridge: '0x73298186A143a54c20ae98EEE5a025bD5979De02' as const,
CanonicalTransactionChain: '0x2ebA8c4EfDB39A8Cd8f9eD65c50ec079f7CEBD81', StateCommitmentChain:
BondManager: '0xE5AE60bD6F8DEe4D0c2BC9268e23B92F1cacC58F', '0x1afcA918eff169eE20fF8AB6Be75f3E872eE1C1A' as const,
CanonicalTransactionChain:
'0x2ebA8c4EfDB39A8Cd8f9eD65c50ec079f7CEBD81' as const,
BondManager: '0xE5AE60bD6F8DEe4D0c2BC9268e23B92F1cacC58F' as const,
}, },
l2: DEFAULT_L2_CONTRACT_ADDRESSES, l2: DEFAULT_L2_CONTRACT_ADDRESSES,
}, },
// Hardhat local [Chain.HARDHAT_LOCAL]: {
31337: {
l1: { l1: {
AddressManager: '0x5FbDB2315678afecb367f032d93F642f64180aa3', AddressManager: '0x5FbDB2315678afecb367f032d93F642f64180aa3' as const,
L1CrossDomainMessenger: '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318', L1CrossDomainMessenger:
L1StandardBridge: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788', '0x8A791620dd6260079BF849Dc5567aDC3F2FdC318' as const,
StateCommitmentChain: '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9', L1StandardBridge: '0x610178dA211FEF7D417bC0e6FeD39F05609AD788' as const,
CanonicalTransactionChain: '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9', StateCommitmentChain:
BondManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707', '0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9' as const,
CanonicalTransactionChain:
'0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9' as const,
BondManager: '0x5FC8d32690cc91D4c39d9d3abcBD16989F875707' as const,
}, },
l2: DEFAULT_L2_CONTRACT_ADDRESSES, l2: DEFAULT_L2_CONTRACT_ADDRESSES,
}, },
...@@ -111,7 +120,7 @@ export const BRIDGE_ADAPTER_DATA: { ...@@ -111,7 +120,7 @@ export const BRIDGE_ADAPTER_DATA: {
} = { } = {
// TODO: Maybe we can pull these automatically from the token list? // TODO: Maybe we can pull these automatically from the token list?
// Alternatively, check against the token list in CI. // Alternatively, check against the token list in CI.
1: { [Chain.MAINNET]: {
Standard: { Standard: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: CONTRACT_ADDRESSES[1].l1.L1StandardBridge, l1Bridge: CONTRACT_ADDRESSES[1].l1.L1StandardBridge,
...@@ -124,16 +133,16 @@ export const BRIDGE_ADAPTER_DATA: { ...@@ -124,16 +133,16 @@ export const BRIDGE_ADAPTER_DATA: {
}, },
BitBTC: { BitBTC: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: '0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128', l1Bridge: '0xaBA2c5F108F7E820C049D5Af70B16ac266c8f128' as const,
l2Bridge: '0x158F513096923fF2d3aab2BcF4478536de6725e2', l2Bridge: '0x158F513096923fF2d3aab2BcF4478536de6725e2' as const,
}, },
DAI: { DAI: {
Adapter: DAIBridgeAdapter, Adapter: DAIBridgeAdapter,
l1Bridge: '0x10E6593CDda8c58a1d0f14C5164B376352a55f2F', l1Bridge: '0x10E6593CDda8c58a1d0f14C5164B376352a55f2F' as const,
l2Bridge: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65', l2Bridge: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65' as const,
}, },
}, },
42: { [Chain.KOVAN]: {
Standard: { Standard: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: CONTRACT_ADDRESSES[42].l1.L1StandardBridge, l1Bridge: CONTRACT_ADDRESSES[42].l1.L1StandardBridge,
...@@ -146,21 +155,21 @@ export const BRIDGE_ADAPTER_DATA: { ...@@ -146,21 +155,21 @@ export const BRIDGE_ADAPTER_DATA: {
}, },
BitBTC: { BitBTC: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: '0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746', l1Bridge: '0x0b651A42F32069d62d5ECf4f2a7e5Bd3E9438746' as const,
l2Bridge: '0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e', l2Bridge: '0x0CFb46528a7002a7D8877a5F7a69b9AaF1A9058e' as const,
}, },
USX: { USX: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: '0x40E862341b2416345F02c41Ac70df08525150dC7', l1Bridge: '0x40E862341b2416345F02c41Ac70df08525150dC7' as const,
l2Bridge: '0xB4d37826b14Cd3CB7257A2A5094507d701fe715f', l2Bridge: '0xB4d37826b14Cd3CB7257A2A5094507d701fe715f' as const,
}, },
DAI: { DAI: {
Adapter: DAIBridgeAdapter, Adapter: DAIBridgeAdapter,
l1Bridge: '0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3', l1Bridge: '0xb415e822C4983ecD6B1c1596e8a5f976cf6CD9e3' as const,
l2Bridge: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65', l2Bridge: '0x467194771dAe2967Aef3ECbEDD3Bf9a310C76C65' as const,
}, },
}, },
5: { [Chain.GOERLI]: {
Standard: { Standard: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: CONTRACT_ADDRESSES[5].l1.L1StandardBridge, l1Bridge: CONTRACT_ADDRESSES[5].l1.L1StandardBridge,
...@@ -172,7 +181,7 @@ export const BRIDGE_ADAPTER_DATA: { ...@@ -172,7 +181,7 @@ export const BRIDGE_ADAPTER_DATA: {
l2Bridge: predeploys.L2StandardBridge, l2Bridge: predeploys.L2StandardBridge,
}, },
}, },
31337: { [Chain.HARDHAT_LOCAL]: {
Standard: { Standard: {
Adapter: StandardBridgeAdapter, Adapter: StandardBridgeAdapter,
l1Bridge: CONTRACT_ADDRESSES[31337].l1.L1StandardBridge, l1Bridge: CONTRACT_ADDRESSES[31337].l1.L1StandardBridge,
...@@ -274,21 +283,29 @@ export const getAllOEContracts = ( ...@@ -274,21 +283,29 @@ export const getAllOEContracts = (
} }
// Attach all L1 contracts. // Attach all L1 contracts.
const l1Contracts: OEL1Contracts = {} as any const l1Contracts = {} as OEL1Contracts
for (const [contractName, contractAddress] of Object.entries(addresses.l1)) { for (const [contractName, contractAddress] of Object.entries(addresses.l1)) {
l1Contracts[contractName] = getOEContract(contractName as any, l1ChainId, { l1Contracts[contractName] = getOEContract(
address: opts.overrides?.l1?.[contractName] || contractAddress, contractName as keyof OEL1Contracts,
signerOrProvider: opts.l1SignerOrProvider, l1ChainId,
}) {
address: opts.overrides?.l1?.[contractName] || contractAddress,
signerOrProvider: opts.l1SignerOrProvider,
}
)
} }
// Attach all L2 contracts. // Attach all L2 contracts.
const l2Contracts: OEL2Contracts = {} as any const l2Contracts = {} as OEL2Contracts
for (const [contractName, contractAddress] of Object.entries(addresses.l2)) { for (const [contractName, contractAddress] of Object.entries(addresses.l2)) {
l2Contracts[contractName] = getOEContract(contractName as any, l1ChainId, { l2Contracts[contractName] = getOEContract(
address: opts.overrides?.l2?.[contractName] || contractAddress, contractName as keyof OEL2Contracts,
signerOrProvider: opts.l2SignerOrProvider, l1ChainId,
}) {
address: opts.overrides?.l2?.[contractName] || contractAddress,
signerOrProvider: opts.l2SignerOrProvider,
}
)
} }
return { return {
......
...@@ -8,10 +8,13 @@ ...@@ -8,10 +8,13 @@
* @param keys Keys to omit from the returned object. * @param keys Keys to omit from the returned object.
* @returns A copy of the given object with the given keys omitted. * @returns A copy of the given object with the given keys omitted.
*/ */
export const omit = (obj: any, ...keys: string[]) => { export const omit = <T extends object, K extends string | number | symbol>(
obj: T,
...keys: K[]
): Omit<T, K> => {
const copy = { ...obj } const copy = { ...obj }
for (const key of keys) { for (const key of keys) {
delete copy[key] delete copy[key as string]
} }
return copy return copy
} }
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