1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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}`,
])
)
// helper for finding the right artifact from the deployed name
const locateArtifact = (name: string) => {
return {
'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',
}[name]
}
export const getArtifactFromManagedName = (name: string) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
return require(`../artifacts/contracts/${locateArtifact(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 printSectionHead = (msg: string) => {
console.log(color.cyan(msg))
console.log(
color.cyan('='.repeat(Math.max(...msg.split('\n').map((s) => s.length))))
)
}
export const printComparison = (
action: string,
description: string,
expected: { name: string; value: any },
deployed: { name: string; value: any }
) => {
console.log(`\n${action}:`)
if (hexStringEquals(expected.value, deployed.value)) {
console.log(
color.green(`${expected.name}: ${truncateLongString(expected.value)}`)
)
console.log('matches')
console.log(
color.green(`${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}.`
)
}
}