Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
da85652d
Unverified
Commit
da85652d
authored
Nov 11, 2021
by
smartcontracts
Committed by
GitHub
Nov 11, 2021
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into fix-batch-submitter-warn-same-address
parents
0f21afa2
d59341a2
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
403 additions
and
1 deletion
+403
-1
three-cheetahs-tie.md
.changeset/three-cheetahs-tie.md
+5
-0
fee-payment.spec.ts
integration-tests/test/fee-payment.spec.ts
+1
-1
hardhat.config.ts
packages/contracts/hardhat.config.ts
+2
-0
validation-utils.ts
packages/contracts/src/validation-utils.ts
+88
-0
validate-address-dictator.ts
packages/contracts/tasks/validate-address-dictator.ts
+155
-0
validate-chugsplash-dictator.ts
packages/contracts/tasks/validate-chugsplash-dictator.ts
+152
-0
No files found.
.changeset/three-cheetahs-tie.md
0 → 100644
View file @
da85652d
---
'
@eth-optimism/contracts'
:
patch
---
Add AddressDictator validation script
integration-tests/test/fee-payment.spec.ts
View file @
da85652d
...
...
@@ -8,7 +8,7 @@ import { serialize } from '@ethersproject/transactions'
import
{
predeploys
,
getContractFactory
}
from
'
@eth-optimism/contracts
'
/* Imports: Internal */
import
{
gasPriceForL2
,
isLiveNetwork
}
from
'
./shared/utils
'
import
{
gasPriceForL2
,
isLiveNetwork
}
from
'
./shared/utils
'
import
{
OptimismEnv
}
from
'
./shared/env
'
import
{
Direction
}
from
'
./shared/watcher-utils
'
...
...
packages/contracts/hardhat.config.ts
View file @
da85652d
...
...
@@ -16,6 +16,8 @@ import '@typechain/hardhat'
import
'
./tasks/deploy
'
import
'
./tasks/l2-gasprice
'
import
'
./tasks/set-owner
'
import
'
./tasks/validate-address-dictator
'
import
'
./tasks/validate-chugsplash-dictator
'
import
'
./tasks/whitelist
'
import
'
./tasks/withdraw-fees
'
import
'
hardhat-gas-reporter
'
...
...
packages/contracts/src/validation-utils.ts
0 → 100644
View file @
da85652d
import
{
createInterface
}
from
'
readline
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
export
const
getInput
=
(
query
)
=>
{
const
rl
=
createInterface
({
input
:
process
.
stdin
,
output
:
process
.
stdout
,
})
return
new
Promise
((
resolve
)
=>
rl
.
question
(
query
,
(
ans
)
=>
{
rl
.
close
()
resolve
(
ans
)
})
)
}
const
codes
=
{
reset
:
'
\
x1b[0m
'
,
red
:
'
\
x1b[0;31m
'
,
green
:
'
\
x1b[0;32m
'
,
cyan
:
'
\
x1b[0;36m
'
,
yellow
:
'
\
x1b[1;33m
'
,
}
export
const
color
=
Object
.
fromEntries
(
Object
.
entries
(
codes
).
map
(([
k
])
=>
[
k
,
(
msg
:
string
)
=>
`
${
codes
[
k
]}${
msg
}${
codes
.
reset
}
`
,
])
)
export
const
getArtifact
=
(
name
:
string
)
=>
{
// Paths to artifacts relative to artifacts/contracts
const
locations
=
{
'
ChainStorageContainer-CTC-batches
'
:
'
L1/rollup/ChainStorageContainer.sol/ChainStorageContainer.json
'
,
'
ChainStorageContainer-SCC-batches
'
:
'
L1/rollup/ChainStorageContainer.sol/ChainStorageContainer.json
'
,
CanonicalTransactionChain
:
'
L1/rollup/CanonicalTransactionChain.sol/CanonicalTransactionChain.json
'
,
StateCommitmentChain
:
'
L1/rollup/StateCommitmentChain.sol/StateCommitmentChain.json
'
,
BondManager
:
'
L1/verification/BondManager.sol/BondManager.json
'
,
OVM_L1CrossDomainMessenger
:
'
L1/messaging/L1CrossDomainMessenger.sol/L1CrossDomainMessenger.json
'
,
Proxy__OVM_L1CrossDomainMessenger
:
'
libraries/resolver/Lib_ResolvedDelegateProxy.sol/Lib_ResolvedDelegateProxy.json
'
,
Proxy__OVM_L1StandardBridge
:
'
chugsplash/L1ChugSplashProxy.sol/L1ChugSplashProxy.json
'
,
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
return
require
(
`../artifacts/contracts/
${
locations
[
name
]}
`
)
}
export
const
getEtherscanUrl
=
(
network
,
address
:
string
)
=>
{
const
escPrefix
=
network
.
chainId
!==
1
?
`
${
network
.
name
}
.`
:
''
return
`https://
${
escPrefix
}
etherscan.io/address/
${
address
}
`
}
// Reduces a byte string to first 32 bytes, with a '...' to indicate when it was shortened
const
truncateLongString
=
(
value
:
string
):
string
=>
{
return
value
.
length
>
66
?
`
${
value
.
slice
(
0
,
66
)}
...`
:
value
}
export
const
printComparison
=
(
action
:
string
,
description
:
string
,
expected
:
{
name
:
string
;
value
:
string
},
deployed
:
{
name
:
string
;
value
:
string
}
)
=>
{
console
.
log
(
action
+
'
:
'
)
if
(
hexStringEquals
(
expected
.
value
,
deployed
.
value
))
{
console
.
log
(
color
.
green
(
`
${
expected
.
name
}
:
${
truncateLongString
(
expected
.
value
)}
matches
${
deployed
.
name
}
:
${
truncateLongString
(
deployed
.
value
)}
`
)
)
console
.
log
(
color
.
green
(
`
${
description
}
looks good! 😎`
))
}
else
{
throw
new
Error
(
`
${
description
}
looks wrong.
${
expected
.
value
}
\ndoes not match\n
${
deployed
.
value
}
.
`
)
}
console
.
log
()
// Add some whitespace
}
packages/contracts/tasks/validate-address-dictator.ts
0 → 100644
View file @
da85652d
'
use strict
'
import
{
ethers
}
from
'
ethers
'
import
{
task
}
from
'
hardhat/config
'
import
*
as
types
from
'
hardhat/internal/core/params/argumentTypes
'
import
{
hexStringEquals
}
from
'
@eth-optimism/core-utils
'
import
{
getContractFactory
}
from
'
../src/contract-defs
'
import
{
getInput
,
color
as
c
,
getArtifact
,
getEtherscanUrl
,
printComparison
,
}
from
'
../src/validation-utils
'
task
(
'
validate:address-dictator
'
)
.
addParam
(
'
dictator
'
,
'
Address of the AddressDictator to validate.
'
,
undefined
,
types
.
string
)
.
addParam
(
'
manager
'
,
'
Address of the Address Manager contract which would be updated by the Dictator.
'
,
undefined
,
types
.
string
)
.
addParam
(
'
multisig
'
,
'
Address of the multisig contract which should be the final owner
'
,
undefined
,
types
.
string
)
.
addOptionalParam
(
'
contractsRpcUrl
'
,
'
RPC Endpoint to query for data
'
,
process
.
env
.
CONTRACTS_RPC_URL
,
types
.
string
)
.
setAction
(
async
(
args
)
=>
{
if
(
!
args
.
contractsRpcUrl
)
{
throw
new
Error
(
c
.
red
(
'
RPC URL must be set in your env, or passed as an argument.
'
)
)
}
const
provider
=
new
ethers
.
providers
.
JsonRpcProvider
(
args
.
contractsRpcUrl
)
const
network
=
await
provider
.
getNetwork
()
console
.
log
()
console
.
log
(
c
.
cyan
(
"
First make sure you're on the right chain:
"
))
console
.
log
(
`Reading from the
${
c
.
red
(
network
.
name
)}
network (Chain ID:
${
c
.
red
(
''
+
network
.
chainId
)}
)`
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
// eslint-disable-next-line @typescript-eslint/no-var-requires
const
dictatorArtifact
=
require
(
'
../artifacts/contracts/L1/deployment/AddressDictator.sol/AddressDictator.json
'
)
const
dictatorCode
=
await
provider
.
getCode
(
args
.
dictator
)
console
.
log
(
c
.
cyan
(
`
Now validating the Address Dictator deployment at\n
${
getEtherscanUrl
(
network
,
args
.
dictator
)}
`
)
)
printComparison
(
'
Comparing deployed AddressDictator bytecode against local build artifacts
'
,
'
Deployed AddressDictator code
'
,
{
name
:
'
Compiled bytecode
'
,
value
:
dictatorArtifact
.
deployedBytecode
},
{
name
:
'
Deployed bytecode
'
,
value
:
dictatorCode
}
)
// Connect to the deployed AddressDictator.
const
dictatorContract
=
getContractFactory
(
'
AddressDictator
'
)
.
attach
(
args
.
dictator
)
.
connect
(
provider
)
const
finalOwner
=
await
dictatorContract
.
finalOwner
()
printComparison
(
'
Comparing the finalOwner address in the AddressDictator to the multisig address
'
,
'
finalOwner
'
,
{
name
:
'
multisig address
'
,
value
:
args
.
multisig
},
{
name
:
'
finalOwner
'
,
value
:
finalOwner
}
)
const
manager
=
await
dictatorContract
.
manager
()
printComparison
(
'
Validating the AddressManager address in the AddressDictator
'
,
'
addressManager
'
,
{
name
:
'
manager
'
,
value
:
args
.
manager
},
{
name
:
'
Address Manager
'
,
value
:
manager
}
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
// Get names and addresses from the Dictator.
const
namedAddresses
=
await
dictatorContract
.
getNamedAddresses
()
// In order to reduce noise for the user, we query the AddressManager identify addresses that
// will not be changed, and skip over them in this block.
const
managerContract
=
getContractFactory
(
'
Lib_AddressManager
'
)
.
attach
(
args
.
manager
)
.
connect
(
provider
)
// Now we loop over those and compare the addresses/deployedBytecode to deployment artifacts.
for
(
const
pair
of
namedAddresses
)
{
const
currentAddress
=
await
managerContract
.
getAddress
(
pair
.
name
)
const
artifact
=
getArtifact
(
pair
.
name
)
const
addressChanged
=
!
hexStringEquals
(
currentAddress
,
pair
.
addr
)
if
(
addressChanged
)
{
console
.
log
(
c
.
cyan
(
`
Now validating the
${
pair
.
name
}
deployment.
Current address:
${
getEtherscanUrl
(
network
,
currentAddress
)}
Upgraded address
${
getEtherscanUrl
(
network
,
pair
.
addr
)}
`
)
)
const
code
=
await
provider
.
getCode
(
pair
.
addr
)
printComparison
(
`Verifying
${
pair
.
name
}
source code against local deployment artifacts`
,
`Deployed
${
pair
.
name
}
code`
,
{
name
:
'
artifact.deployedBytecode
'
,
value
:
artifact
.
deployedBytecode
,
},
{
name
:
'
Deployed bytecode
'
,
value
:
code
}
)
// Identify contracts which inherit from Lib_AddressResolver, and check that they
// have the right manager address.
if
(
Object
.
keys
(
artifact
))
{
if
(
artifact
.
abi
.
some
((
el
)
=>
el
.
name
===
'
libAddressManager
'
))
{
const
libAddressManager
=
await
getContractFactory
(
'
Lib_AddressResolver
'
)
.
attach
(
pair
.
addr
)
.
connect
(
provider
)
.
libAddressManager
()
printComparison
(
`Verifying
${
pair
.
name
}
has the correct AddressManager address`
,
`The AddressManager address in
${
pair
.
name
}
`
,
{
name
:
'
Deployed value
'
,
value
:
libAddressManager
},
{
name
:
'
Expected value
'
,
value
:
manager
}
)
}
}
}
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
}
console
.
log
(
c
.
green
(
'
AddressManager Validation complete!
'
))
})
packages/contracts/tasks/validate-chugsplash-dictator.ts
0 → 100644
View file @
da85652d
'
use strict
'
import
{
ethers
}
from
'
ethers
'
import
{
task
}
from
'
hardhat/config
'
import
*
as
types
from
'
hardhat/internal/core/params/argumentTypes
'
import
{
getContractFactory
}
from
'
../src/contract-defs
'
import
{
getInput
,
color
as
c
,
getEtherscanUrl
,
printComparison
,
}
from
'
../src/validation-utils
'
task
(
'
validate:chugsplash-dictator
'
)
.
addParam
(
'
dictator
'
,
'
Address of the ChugSplashDictator to validate.
'
,
undefined
,
types
.
string
)
.
addParam
(
'
proxy
'
,
'
Address of the L1ChugSplashProxy to validate.
'
,
undefined
,
types
.
string
)
.
addParam
(
'
multisig
'
,
'
Address of the multisig contract which should be the final owner
'
,
undefined
,
types
.
string
)
.
addOptionalParam
(
'
contractsRpcUrl
'
,
'
RPC Endpoint to query for data
'
,
process
.
env
.
CONTRACTS_RPC_URL
,
types
.
string
)
.
setAction
(
async
(
args
)
=>
{
if
(
!
args
.
contractsRpcUrl
)
{
throw
new
Error
(
c
.
red
(
'
RPC URL must be set in your env, or passed as an argument.
'
)
)
}
const
provider
=
new
ethers
.
providers
.
JsonRpcProvider
(
args
.
contractsRpcUrl
)
const
network
=
await
provider
.
getNetwork
()
console
.
log
()
// the whitespacooooooor
console
.
log
(
c
.
cyan
(
"
First make sure you're on the right chain:
"
))
console
.
log
(
`Reading from the
${
c
.
red
(
network
.
name
)}
network (Chain ID:
${
c
.
red
(
''
+
network
.
chainId
)}
)`
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
// eslint-disable-next-line @typescript-eslint/no-var-requires
const
dictatorArtifact
=
require
(
'
../artifacts/contracts/L1/deployment/ChugSplashDictator.sol/ChugSplashDictator.json
'
)
const
dictatorCode
=
await
provider
.
getCode
(
args
.
dictator
)
console
.
log
(
c
.
cyan
(
`
Now validating the Chugsplash Dictator deployment at\n
${
getEtherscanUrl
(
network
,
args
.
dictator
)}
`
)
)
printComparison
(
'
Comparing deployed ChugSplashDictator bytecode against local build artifacts
'
,
'
Deployed ChugSplashDictator code
'
,
{
name
:
'
Compiled bytecode
'
,
value
:
dictatorArtifact
.
deployedBytecode
},
{
name
:
'
Deployed bytecode
'
,
value
:
dictatorCode
}
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
console
.
log
(
c
.
cyan
(
"
The next 4 checks will validate the ChugSplashDictator's config
"
)
)
// Connect to the deployed ChugSplashDictator.
const
dictatorContract
=
getContractFactory
(
'
ChugSplashDictator
'
)
.
attach
(
args
.
dictator
)
.
connect
(
provider
)
const
finalOwner
=
await
dictatorContract
.
finalOwner
()
printComparison
(
'
1. Comparing the finalOwner address in the ChugSplashDictator to the multisig address
'
,
'
finalOwner
'
,
{
name
:
'
multisig address
'
,
value
:
args
.
multisig
},
{
name
:
'
finalOwner
'
,
value
:
finalOwner
}
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
const
dictatorMessengerSlotKey
=
await
dictatorContract
.
messengerSlotKey
()
const
dictatorMessengerSlotVal
=
await
dictatorContract
.
messengerSlotVal
()
const
proxyMessengerSlotVal
=
await
provider
.
getStorageAt
(
args
.
proxy
,
dictatorMessengerSlotKey
)
printComparison
(
'
2. Comparing the messenger slot key/value to be set, with the current values in the proxy
'
,
`Storage slot key
${
dictatorMessengerSlotKey
}
`
,
{
name
:
`Value in the proxy at slot key\n
${
dictatorMessengerSlotKey
}
`
,
value
:
proxyMessengerSlotVal
,
},
{
name
:
`Dictator will setStorage at slot key\n
${
dictatorMessengerSlotKey
}
`
,
value
:
dictatorMessengerSlotVal
,
}
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
const
dictatorBridgeSlotKey
=
await
dictatorContract
.
bridgeSlotKey
()
const
dictatorBridgeSlotVal
=
await
dictatorContract
.
bridgeSlotVal
()
const
proxyBridgeSlotVal
=
await
provider
.
getStorageAt
(
args
.
proxy
,
dictatorBridgeSlotKey
)
printComparison
(
'
3. Comparing the _Bridge_ slot key/value to be set, with the current values in the proxy
'
,
`Storage slot key
${
dictatorBridgeSlotKey
}
`
,
{
name
:
`Value currently in the proxy at slot key\n
${
dictatorBridgeSlotKey
}
`
,
value
:
proxyBridgeSlotVal
,
},
{
name
:
`Dictator will setStorage in the proxy at slot key\n
${
dictatorBridgeSlotKey
}
`
,
value
:
dictatorBridgeSlotVal
,
}
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
// eslint-disable-next-line @typescript-eslint/no-var-requires
const
bridgeArtifact
=
require
(
'
../artifacts/contracts/L1/messaging/L1StandardBridge.sol/L1StandardBridge.json
'
)
const
expectedCodeHash
=
ethers
.
utils
.
keccak256
(
bridgeArtifact
.
deployedBytecode
)
const
actualCodeHash
=
await
dictatorContract
.
codeHash
()
printComparison
(
"
4. Comparing the Dictator's codeHash against hash of the local L1StandardBridge build artifacts
"
,
"
Dictator's codeHash
"
,
{
name
:
'
Expected codeHash
'
,
value
:
expectedCodeHash
,
},
{
name
:
'
Actual codeHash
'
,
value
:
actualCodeHash
,
}
)
await
getInput
(
c
.
yellow
(
'
OK? Hit enter to continue.
'
))
console
.
log
(
c
.
green
(
'
Chugsplash Dictator Validation complete!
'
))
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment