import { Watcher } from '@eth-optimism/core-utils' import { getMessagesAndProofsForL2Transaction } from '@eth-optimism/message-relayer' import { ethers, providers, Signer } from 'ethers' import { getL1Url, getL2Url } from '.' import { artifacts } from './artifacts' import { optimismConfig } from './optimismConfig' export const ZERO_GAS_OPTS = { gasPrice: 0 } export async function waitToRelayTxsToL2(l1OriginatingTx: Promise<any>, watcher: Watcher) { console.log('Using watcher to wait for L1->L2 relay...') const res = await l1OriginatingTx await res.wait() const [l2ToL1XDomainMsgHash] = await watcher.getMessageHashesFromL1Tx(res.hash) console.log(`Found cross-domain message ${l2ToL1XDomainMsgHash} in L1 tx. Waiting for relay to L2...`) await watcher.getL2TransactionReceipt(l2ToL1XDomainMsgHash) } // manually relies L2 -> L1 messages as dockerized optimism doesnt do it anymore export async function relayMessagesToL1(l2OriginatingTx: Promise<any>, watcher: Watcher, l1Signer: Signer) { console.log('Using watcher to wait for L2->L1 relay...') const res = await l2OriginatingTx await res.wait() const [l2ToL1XDomainMsgHash] = await watcher.getMessageHashesFromL2Tx(res.hash) console.log(`Found cross-domain message ${l2ToL1XDomainMsgHash} in L2 tx. Waiting for relay to L1...`) await relayMessages(l1Signer, res.hash) await watcher.getL1TransactionReceipt(l2ToL1XDomainMsgHash) } export async function printRollupStatus(l1Provider: providers.BaseProvider) { const CTC = new ethers.Contract( optimismConfig.CanonicalTransactionChain, artifacts.l1.canonicalTxChain.abi, l1Provider, ) const STC = new ethers.Contract( optimismConfig.StateCommitmentChain, artifacts.l1.stateCommitmentChain.abi, l1Provider, ) const ctcAllElements = await CTC.getTotalElements() const ctcQueuedElement = await CTC.getNumPendingQueueElements() const stcAllElements = await STC.getTotalElements() console.log('Canonical Tx Chain all elements: ', ctcAllElements.toString()) console.log('Canonical Tx Chain queued elements: ', ctcQueuedElement.toString()) console.log('State Commitment Chain all elements: ', stcAllElements.toString()) } export async function relayMessages(l1Deployer: Signer, l2TxHash: string) { const messagePairs = await retry( () => getMessagesAndProofsForL2Transaction( getL1Url(), getL2Url(), optimismConfig.StateCommitmentChain, optimismConfig._L2_OVM_L2CrossDomainMessenger, l2TxHash, ), 15, ) const l1XdomainMessenger = new ethers.Contract( optimismConfig.Proxy__OVM_L1CrossDomainMessenger, artifacts.l1.crossDomainMessenger.abi, l1Deployer, ) for (const { message, proof } of messagePairs) { console.log('Relaying L2 -> L1 message...') await l1XdomainMessenger.relayMessage(message.target, message.sender, message.message, message.messageNonce, proof) } } function delay(duration: number) { return new Promise<void>((resolve) => setTimeout(resolve, duration)) } async function retry<T>(fn: () => Promise<T>, maxRetries: number = 5): Promise<T> { const sleepBetweenRetries = 1000 let retryCount = 0 do { try { return await fn() } catch (error) { const isLastAttempt = retryCount === maxRetries if (isLastAttempt) { throw error } console.log('retry...') } await delay(sleepBetweenRetries) } while (retryCount++ < maxRetries) throw new Error('Unreachable') }