2022-12-09 18:11:04 +08:00

378 lines
10 KiB
TypeScript

require('dotenv').config()
import { ethers as l2Ethers } from 'ethers'
import { ethers } from 'hardhat'
import { BigNumber, ContractFactory, Signer, Contract, providers } from 'ethers'
import {
getContractFactories,
readConfigFile,
waitAfterTransaction,
updateConfigFile,
getModifiedGasPrice,
Logger
} from '../shared/utils'
import {
getMessengerWrapperDefaults,
getPolygonRpcEndpoint,
} from '../../config/utils'
import {
ALL_SUPPORTED_CHAIN_IDS,
ZERO_ADDRESS
} from '../../config/constants'
import {
isChainIdMainnet,
isChainIdPolygon
} from '../../config/utils'
import {
getSetL1BridgeCallerMessage,
executeCanonicalMessengerSendMessage,
getAddActiveChainIdsMessage,
getSetFxRootTunnelMessage,
getSetAmmWrapperMessage
} from '../../test/shared/contractFunctionWrappers'
const logger = Logger('setupL1')
interface Config {
l1ChainId: BigNumber
l2ChainId: BigNumber
l1MessengerAddress: string
l1CanonicalTokenAddress: string
l1BridgeAddress: string
l2CanonicalTokenAddress: string
l2BridgeAddress: string
l2MessengerProxyAddress: string
l2AmmWrapperAddress: string
liquidityProviderSendAmount: BigNumber
}
export async function setupL1 (config: Config) {
logger.log('setup L1')
let {
l1ChainId,
l2ChainId,
l1MessengerAddress,
l1CanonicalTokenAddress,
l1BridgeAddress,
l2CanonicalTokenAddress,
l2BridgeAddress,
l2MessengerProxyAddress,
l2AmmWrapperAddress,
liquidityProviderSendAmount
} = config
logger.log(`config:
l1ChainId: ${l1ChainId}
l2ChainId: ${l2ChainId}
l1MessengerAddress: ${l1MessengerAddress}
l1CanonicalTokenAddress: ${l1CanonicalTokenAddress}
l1BridgeAddress: ${l1BridgeAddress}
l2CanonicalTokenAddress: ${l2CanonicalTokenAddress}
l2BridgeAddress: ${l2BridgeAddress}
l2MessengerProxyAddress: ${l2MessengerProxyAddress}
l2AmmWrapperAddress: ${l2AmmWrapperAddress}
liquidityProviderSendAmount: ${liquidityProviderSendAmount}`)
l1ChainId = BigNumber.from(l1ChainId)
l2ChainId = BigNumber.from(l2ChainId)
liquidityProviderSendAmount = BigNumber.from(liquidityProviderSendAmount)
// Signers
let accounts: Signer[]
let deployer: Signer
let governance: Signer
// Factories
let L1_MockERC20: ContractFactory
let L1_TokenBridge: ContractFactory
let L1_Bridge: ContractFactory
let L1_MessengerWrapper: ContractFactory
let L1_Messenger: ContractFactory
let L2_Bridge: ContractFactory
let L2_MessengerProxy: ContractFactory
// Contracts
let l1_canonicalToken: Contract
let l1_tokenBridge: Contract
let l1_messengerWrapper: Contract
let l1_bridge: Contract
let l1_messenger: Contract
let l2_canonicalToken: Contract
let l2_bridge: 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_MockERC20,
L1_TokenBridge,
L1_Bridge,
L1_Messenger,
L1_MessengerWrapper,
L2_Bridge,
L2_MessengerProxy
} = await getContractFactories(l2ChainId, deployer, ethers))
logger.log('attaching deployed contracts')
// Attach already deployed contracts
l1_messenger = L1_Messenger.attach(l1MessengerAddress)
l1_canonicalToken = L1_MockERC20.attach(l1CanonicalTokenAddress)
l2_canonicalToken = L1_MockERC20.attach(l2CanonicalTokenAddress)
l1_bridge = L1_Bridge.attach(l1BridgeAddress)
l2_bridge = L2_Bridge.attach(l2BridgeAddress)
/**
* Setup deployments
*/
// Assert that the messenger proxy address was set during deployments
if (isChainIdPolygon(l2ChainId) && l2MessengerProxyAddress === ZERO_ADDRESS) {
throw new Error('L2 Messenger Proxy address is not set')
}
// Deploy messenger wrapper
const fxChildTunnelAddress: string = l2MessengerProxyAddress || '0x'
const messengerWrapperDefaults: any[] = getMessengerWrapperDefaults(
l1ChainId,
l2ChainId,
l1_bridge.address,
l2_bridge.address,
l1_messenger?.address || '0x',
fxChildTunnelAddress
)
logger.log('deploying L1 messenger wrapper')
let modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
l1_messengerWrapper = await L1_MessengerWrapper.connect(deployer).deploy(
...messengerWrapperDefaults,
modifiedGasPrice
)
await waitAfterTransaction(l1_messengerWrapper)
if (isChainIdPolygon(l2ChainId)) {
logger.log('make polygon specific changes')
l1_messenger = L1_MessengerWrapper.attach(l1_messenger.address)
l2_messengerProxy = L2_MessengerProxy.attach(l2MessengerProxyAddress)
logger.log(
`IMPORTANT: this tx will fail if it is being called a second time (i.e. restarting a deployment halfway through).`,
`The value can only be set once.`
)
await updatePolygonState(l1ChainId, l1_messengerWrapper, l2_messengerProxy)
}
/**
* Setup invocations
*/
logger.log('setting cross domain messenger wrapper on L1 bridge')
// Set up the L1 bridge
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await l1_bridge.connect(governance).setXDomainConnector(
l2ChainId,
l1_messengerWrapper.address,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
// Set up L2 Bridge state (through the L1 Canonical Messenger)
let setL1BridgeCallerParams: string
if (isChainIdPolygon(l2ChainId)) {
setL1BridgeCallerParams = l1_bridge.address
} else {
setL1BridgeCallerParams = l1_messengerWrapper.address
}
let message: string = getSetL1BridgeCallerMessage(
setL1BridgeCallerParams
)
logger.log('setting L1 messenger wrapper address on L2 bridge')
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await executeCanonicalMessengerSendMessage(
l1_messenger,
l1_messengerWrapper,
l2_bridge,
ZERO_ADDRESS,
governance,
message,
l2ChainId,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
let addActiveChainIdsParams: any[] = ALL_SUPPORTED_CHAIN_IDS
message = getAddActiveChainIdsMessage(addActiveChainIdsParams)
logger.log('setting supported chain IDs on L2 bridge')
logger.log(
'chain IDs:',
ALL_SUPPORTED_CHAIN_IDS.map(v => v.toString()).join(', ')
)
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await executeCanonicalMessengerSendMessage(
l1_messenger,
l1_messengerWrapper,
l2_bridge,
ZERO_ADDRESS,
governance,
message,
l2ChainId,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
message = getSetAmmWrapperMessage(l2AmmWrapperAddress)
logger.log('setting amm wrapper address on L2 bridge')
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await executeCanonicalMessengerSendMessage(
l1_messenger,
l1_messengerWrapper,
l2_bridge,
ZERO_ADDRESS,
governance,
message,
l2ChainId,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
// Get hop token on L2
if (!isChainIdMainnet(l1ChainId)) {
logger.log('minting L1 canonical token')
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await l1_canonicalToken
.connect(deployer)
.mint(
await deployer.getAddress(),
liquidityProviderSendAmount,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
}
logger.log('approving L1 canonical token')
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await l1_canonicalToken
.connect(deployer)
.approve(
l1_bridge.address,
liquidityProviderSendAmount,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
const amountOutMin: BigNumber = BigNumber.from('0')
const deadline: BigNumber = BigNumber.from('0')
const relayerFee: BigNumber = BigNumber.from('0')
logger.log('sending token to L2')
logger.log(
`IMPORTANT: if this transaction fails, it may be one of two things. (1) You are using a patched OZ. Reinstall`,
`node modules & redeploy the L1 bridge. A failed transaction here will not show any internal calls and use very`,
`little gas. (2) The L1 deployer does not have tokens to send over the bridge.`
)
modifiedGasPrice = await getModifiedGasPrice(ethers, l1ChainId)
tx = await l1_bridge
.connect(deployer)
.sendToL2(
l2ChainId,
await deployer.getAddress(),
liquidityProviderSendAmount,
[
'1',
amountOutMin,
deadline
],
ZERO_ADDRESS,
relayerFee,
modifiedGasPrice
)
await tx.wait()
await waitAfterTransaction()
updateConfigFile({
l1MessengerWrapperAddress: l1_messengerWrapper.address
})
logger.log('L1 Setup Complete')
logger.log(`L1 Messenger Wrapper: ${l1_messengerWrapper.address}`)
}
const updatePolygonState = async (
l1ChainId: BigNumber,
l1_messengerWrapper: Contract,
l2_messengerProxy: Contract
) => {
const polygonRpcEndpoint = getPolygonRpcEndpoint(l1ChainId)
const l2EthersProvider = new l2Ethers.providers.JsonRpcProvider(polygonRpcEndpoint)
const l2EthersWallet = new l2Ethers.Wallet(process.env.DEPLOYER_PRIVATE_KEY, l2EthersProvider)
const polygonTransactionData: string = getSetFxRootTunnelMessage(l1_messengerWrapper.address)
const gasLimit: number = 100000
const gasPrice: number = 10000000000
const setFxRootTunnelTransaction = {
to: l2_messengerProxy.address,
gasLimit,
gasPrice,
data: polygonTransactionData
}
const transaction = await l2EthersWallet.sendTransaction(setFxRootTunnelTransaction)
return transaction.wait()
}
if (require.main === module) {
const {
l1ChainId,
l2ChainId,
l1MessengerAddress,
l1CanonicalTokenAddress,
l1BridgeAddress,
l2CanonicalTokenAddress,
l2BridgeAddress,
l2MessengerProxyAddress,
l2AmmWrapperAddress,
liquidityProviderSendAmount
} = readConfigFile()
setupL1({
l1ChainId,
l2ChainId,
l1MessengerAddress,
l1CanonicalTokenAddress,
l2CanonicalTokenAddress,
l1BridgeAddress,
l2BridgeAddress,
l2MessengerProxyAddress,
l2AmmWrapperAddress,
liquidityProviderSendAmount
})
.then(() => {
process.exit(0)
})
.catch(error => {
logger.error(error)
process.exit(1)
})
}