2022-12-09 18:15:16 +08:00

467 lines
12 KiB
TypeScript

require('dotenv').config()
import { ethers } from 'hardhat'
import {
ContractFactory,
Signer,
Contract,
BigNumber,
providers
} from 'ethers'
import {
getContractFactories,
updateConfigFile,
readConfigFile,
waitAfterTransaction,
doesNeedExplicitGasLimit,
Logger
} from '../shared/utils'
import {
isChainIdPolygon,
isChainIdOptimism,
getPolygonFxChildAddress,
getL2ConnectorDefaults
} from '../../config/utils'
import {
CHAIN_IDS,
DEFAULT_ETHERS_OVERRIDES,
DEFAULT_SWAP_A,
DEFAULT_SWAP_FEE,
DEFAULT_SWAP_ADMIN_FEE,
DEFAULT_SWAP_WITHDRAWAL_FEE,
DEFAULT_MESSENGER_WRAPPER_GAS_LIMIT
} from '../../config/constants'
const logger = Logger('deployL2')
let overrides = {}
interface Config {
l1ChainId: BigNumber
l2ChainId: BigNumber
l1BridgeAddress: string
l2CanonicalTokenAddress: string
l2MessengerAddress: string
l2HBridgeTokenName: string
l2HBridgeTokenSymbol: string
l2HBridgeTokenDecimals: number
l2SwapLpTokenName: string
l2SwapLpTokenSymbol: string
bonderAddress: string
l2CanonicalTokenIsEth: boolean
}
export async function deployL2 (config: Config) {
logger.log('deploy L2')
let {
l1ChainId,
l2ChainId,
l1BridgeAddress,
l2CanonicalTokenAddress,
l2MessengerAddress,
l2HBridgeTokenName,
l2HBridgeTokenSymbol,
l2HBridgeTokenDecimals,
l2SwapLpTokenName,
l2SwapLpTokenSymbol,
bonderAddress,
l2CanonicalTokenIsEth
} = config
logger.log(`config:
l1ChainId: ${l1ChainId}
l2ChainId: ${l2ChainId}
l1BridgeAddress: ${l1BridgeAddress}
l2CanonicalTokenAddress: ${l2CanonicalTokenAddress}
l2MessengerAddress: ${l2MessengerAddress}
l2HBridgeTokenName: ${l2HBridgeTokenName}
l2HBridgeTokenSymbol: ${l2HBridgeTokenSymbol}
l2HBridgeTokenDecimals: ${l2HBridgeTokenDecimals}
bonderAddress: ${bonderAddress},
l2CanonicalTokenIsEth: ${l2CanonicalTokenIsEth}`
)
l1ChainId = BigNumber.from(l1ChainId)
l2ChainId = BigNumber.from(l2ChainId)
// Signers
let accounts: Signer[]
let deployer: Signer
let governance: Signer
// Factories
let L1_Bridge: ContractFactory
let L2_MockERC20: ContractFactory
let L2_HopBridgeToken: ContractFactory
let L2_Bridge: ContractFactory
let L2_AmmWrapper: ContractFactory
// Contracts
let l1_bridge: Contract
let l2_bridge: Contract
let l2_canonicalToken: Contract
let l2_hopBridgeToken: Contract
let l2_swap: Contract
let l2_ammWrapper: Contract
let l2_messengerProxy: Contract
// Instantiate the wallets
accounts = await ethers.getSigners()
deployer = accounts[0]
governance = accounts[1]
logger.log('deployer:', await deployer.getAddress())
logger.log('governance:', await governance.getAddress())
// Transaction
let tx: providers.TransactionResponse
logger.log('getting contract factories')
// Get the contract Factories
;({
L1_Bridge,
L2_MockERC20,
L2_HopBridgeToken,
L2_Bridge,
L2_AmmWrapper
} = await getContractFactories(l2ChainId, deployer, ethers))
logger.log('attaching deployed contracts')
// Attach already deployed contracts
l1_bridge = L1_Bridge.attach(l1BridgeAddress)
l2_canonicalToken = L2_MockERC20.attach(l2CanonicalTokenAddress)
if (!isChainIdOptimism(l2ChainId)) {
overrides = DEFAULT_ETHERS_OVERRIDES
}
/**
* Deployments
*/
let l2MessengerProxyAddress: string = ''
if (isChainIdPolygon(l2ChainId)) {
logger.log('deploying Polygon messenger proxy')
// ToDo: Fix deploy scripts
// const fxChild: string = getPolygonFxChildAddress(l1ChainId)
// l2_messengerProxy = await L2_MessengerProxy.deploy(fxChild, overrides)
// await waitAfterTransaction(l2_messengerProxy, ethers)
l2MessengerAddress = l2_messengerProxy.address
l2MessengerProxyAddress = l2_messengerProxy.address
}
logger.log('deploying L2 hop bridge token')
logger.log('params:', l2HBridgeTokenName, l2HBridgeTokenSymbol, l2HBridgeTokenDecimals)
l2_hopBridgeToken = await L2_HopBridgeToken.deploy(
l2HBridgeTokenName,
l2HBridgeTokenSymbol,
l2HBridgeTokenDecimals
)
await waitAfterTransaction(l2_hopBridgeToken, ethers)
logger.log('deploying L2 swap contract')
;({ l2_swap } = await deployAmm(
deployer,
ethers,
l2ChainId,
l2_canonicalToken,
l2_hopBridgeToken,
l2SwapLpTokenName,
l2SwapLpTokenSymbol,
logger
))
logger.log('deploying L2 bridge and L2 amm wrapper')
;({ l2_bridge, l2_ammWrapper } = await deployBridge(
l2ChainId,
l1ChainId,
ethers,
deployer,
governance,
bonderAddress,
L2_Bridge,
L2_AmmWrapper,
l1_bridge,
l2_bridge,
l2_hopBridgeToken,
l2_canonicalToken,
l2_swap,
l2_ammWrapper,
l2MessengerAddress,
l2MessengerProxyAddress,
l2CanonicalTokenIsEth,
logger
))
logger.log('deploying network specific contracts')
// Transfer ownership of the Hop Bridge Token to the L2 Bridge
let transferOwnershipParams: any[] = [l2_bridge.address]
if (doesNeedExplicitGasLimit(l2ChainId)) {
transferOwnershipParams.push(overrides)
}
logger.log('transferring ownership of L2 hop bridge token')
tx = await l2_hopBridgeToken.transferOwnership(...transferOwnershipParams)
await tx.wait()
await waitAfterTransaction()
if (isChainIdPolygon(l2ChainId)) {
logger.log('setting Polygon-specific state')
let tx = await l2_messengerProxy.setL2Bridge(l2_bridge.address, overrides)
await tx.wait()
await waitAfterTransaction()
// Technically, setFxRootTunnel should be called here but we cannot do so because
// we need the address of the L1 Messenger Wrapper. Because of this, we call setFxRootTunnel
// in setupL1.
}
const l2HopBridgeTokenAddress: string = l2_hopBridgeToken.address
const l2BridgeAddress: string = l2_bridge.address
const l2SwapAddress: string = l2_swap.address
const l2AmmWrapperAddress: string = l2_ammWrapper.address
logger.log('L2 Deployments Complete')
logger.log('L2 Hop Bridge Token :', l2HopBridgeTokenAddress)
logger.log('L2 Bridge :', l2BridgeAddress)
logger.log('L2 Swap :', l2SwapAddress)
logger.log('L2 Amm Wrapper :', l2AmmWrapperAddress)
logger.log('L2 Messenger :', l2MessengerAddress)
logger.log('L2 Messenger Proxy :', l2MessengerProxyAddress)
updateConfigFile({
l2HopBridgeTokenAddress,
l2BridgeAddress,
l2SwapAddress,
l2AmmWrapperAddress,
l2MessengerAddress,
l2MessengerProxyAddress
})
return {
l2HopBridgeTokenAddress,
l2BridgeAddress,
l2SwapAddress,
l2AmmWrapperAddress,
l2MessengerAddress,
l2MessengerProxyAddress
}
}
const deployAmm = async (
deployer: Signer,
ethers: any,
l2ChainId: BigNumber,
l2_canonicalToken: Contract,
l2_hopBridgeToken: Contract,
l2SwapLpTokenName: string,
l2SwapLpTokenSymbol: string,
logger: any
) => {
// Deploy AMM contracts
logger.log('Deploying L2 Swap Libs')
const L2_SwapContractFactory: ContractFactory = await deployL2SwapLibs(deployer, ethers, logger)
logger.log('Deploying L2 Swap')
const l2_swap = await L2_SwapContractFactory.deploy(overrides)
await waitAfterTransaction(l2_swap, ethers)
let decimalParams: any[] = []
if (doesNeedExplicitGasLimit(l2ChainId)) {
decimalParams.push(overrides)
}
logger.log('l2_canonicalToken.decimals start...', decimalParams)
logger.log('addr:',l2_canonicalToken.address)
// let name = await l2_canonicalToken.name()
// logger.log(name)
const l2CanonicalTokenDecimals = await l2_canonicalToken.decimals(...decimalParams) // 2022.12.9 YX
// const l2CanonicalTokenDecimals = await l2_canonicalToken.decimals()
logger.log('l2_hopBridgeToken.decimals start...', decimalParams)
const l2HopBridgeTokenDecimals = await l2_hopBridgeToken.decimals(...decimalParams) // 2022.12.9 YX
// const l2HopBridgeTokenDecimals = await l2_hopBridgeToken.decimals()
let initializeParams: any[] = [
[l2_canonicalToken.address, l2_hopBridgeToken.address],
[l2CanonicalTokenDecimals, l2HopBridgeTokenDecimals],
l2SwapLpTokenName,
l2SwapLpTokenSymbol,
DEFAULT_SWAP_A,
DEFAULT_SWAP_FEE,
DEFAULT_SWAP_ADMIN_FEE,
DEFAULT_SWAP_WITHDRAWAL_FEE
]
if (doesNeedExplicitGasLimit(l2ChainId)) {
initializeParams.push(overrides)
}
logger.log('Initializing Swap')
const tx = await l2_swap.initialize(...initializeParams)
await tx.wait()
await waitAfterTransaction()
return {
l2_swap
}
}
const deployL2SwapLibs = async (
signer: Signer,
ethers: any,
logger: any
) => {
const L2_MathUtils: ContractFactory = await ethers.getContractFactory('MathUtils', { signer })
logger.log('Deploying L2 Math Utils')
const l2_mathUtils = await L2_MathUtils.deploy(overrides)
await waitAfterTransaction(l2_mathUtils, ethers)
const L2_SwapUtils = await ethers.getContractFactory(
'SwapUtils',
{
libraries: {
'MathUtils': l2_mathUtils.address
}
}
)
logger.log('Deploying L2 Swap Utils')
logger.log('IMPORTANT: This transaction needs 4.5 million gas to be deployed on Polygon')
const l2_swapUtils = await L2_SwapUtils.deploy(overrides)
await waitAfterTransaction(l2_swapUtils, ethers)
return await ethers.getContractFactory(
'Swap',
{
libraries: {
'SwapUtils': l2_swapUtils.address
}
}
)
}
const deployBridge = async (
chainId: BigNumber,
l1ChainId: BigNumber,
ethers: any,
deployer: Signer,
governance: Signer,
bonderAddress: string,
L2_Bridge: ContractFactory,
L2_AmmWrapper: ContractFactory,
l1_bridge: Contract,
l2_bridge: Contract,
l2_hopBridgeToken: Contract,
l2_canonicalToken: Contract,
l2_swap: Contract,
l2_ammWrapper: Contract,
l2MessengerAddress: string,
l2MessengerProxyAddress: string,
l2CanonicalTokenIsEth: boolean,
logger: any
) => {
// NOTE: Adding more CHAIN_IDs here will push the OVM deployment over the contract size limit
// If additional CHAIN_IDs must be added, do so after the deployment.
// ToDo: Fix deployments
/**
* constructor (
iOVM_L2CrossDomainMessenger _messenger,
address l1Governance,
HopBridgeToken hToken,
address l1BridgeAddress,
uint256[] memory activeChainIds,
address[] memory bonders,
uint32 _defaultGasLimit
)
*/
const l2BridgeDeploymentParams = [
l2MessengerAddress,
// '0x0000000000000000000000000000000000000000',
await governance.getAddress(),
l2_hopBridgeToken.address,
l1_bridge.address,
[chainId.toNumber(), l1ChainId.toNumber()],
[bonderAddress],
DEFAULT_MESSENGER_WRAPPER_GAS_LIMIT
]
logger.log('Deploying L2 Bridge')
l2_bridge = await L2_Bridge.connect(deployer).deploy(...l2BridgeDeploymentParams, overrides)
// l2_bridge = await L2_Bridge.connect(deployer).deploy(...l2BridgeDeploymentParams)
await waitAfterTransaction(l2_bridge, ethers)
/**
* constructor(
L2_Bridge _bridge,
IERC20 _l2CanonicalToken,
bool _l2CanonicalTokenIsEth,
IERC20 _hToken,
Swap _exchangeAddress
)
*/
logger.log('Deploying L2 AMM Wrapper')
l2_ammWrapper = await L2_AmmWrapper.connect(deployer).deploy(
l2_bridge.address,
l2_canonicalToken.address,
l2CanonicalTokenIsEth,
l2_hopBridgeToken.address,
l2_swap.address,
overrides
)
await waitAfterTransaction(l2_ammWrapper, ethers)
return {
l2_bridge,
l2_ammWrapper
}
}
if (require.main === module) {
const {
l1ChainId,
l2ChainId,
l1BridgeAddress,
l2CanonicalTokenAddress,
l2MessengerAddress,
l2HBridgeTokenName,
l2HBridgeTokenSymbol,
l2HBridgeTokenDecimals,
l2SwapLpTokenName,
l2SwapLpTokenSymbol,
bonderAddress,
l2CanonicalTokenIsEth
} = readConfigFile()
deployL2({
l1ChainId,
l2ChainId,
l1BridgeAddress,
l2CanonicalTokenAddress,
l2MessengerAddress,
l2HBridgeTokenName,
l2HBridgeTokenSymbol,
l2HBridgeTokenDecimals,
l2SwapLpTokenName,
l2SwapLpTokenSymbol,
bonderAddress,
l2CanonicalTokenIsEth
})
.then(() => {
process.exit(0)
})
.catch(error => {
logger.error(error)
process.exit(1)
})
}