Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
/* External Imports */
import hre, { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
import { applyL1ToL2Alias } from '@eth-optimism/core-utils'
import {
smock,
MockContractFactory,
FakeContract,
} from '@defi-wonderland/smock'
import { smock, FakeContract, MockContract } from '@defi-wonderland/smock'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'

/* Internal Imports */
import { expect } from '../../../setup'
import { predeploys } from '../../../../src'
import {
impersonate,
deploy,
NON_NULL_BYTES32,
NON_ZERO_ADDRESS,
encodeXDomainCalldata,
} from '../../../helpers'
import { predeploys } from '../../../../src'

describe('L2CrossDomainMessenger', () => {
let signer: Signer
let signer: SignerWithAddress
before(async () => {
;[signer] = await ethers.getSigners()
})
Expand All @@ -37,106 +34,89 @@ describe('L2CrossDomainMessenger', () => {
)
})

let impersonatedL1CrossDomainMessengerSender: Signer
before(async () => {
const impersonatedAddress = applyL1ToL2Alias(
Fake__L1CrossDomainMessenger.address
)
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [impersonatedAddress],
})
await hre.network.provider.request({
method: 'hardhat_setBalance',
params: [impersonatedAddress, '0xFFFFFFFFFFFFFFFFF'],
})
impersonatedL1CrossDomainMessengerSender = await ethers.getSigner(
impersonatedAddress
)
})

let Factory__L2CrossDomainMessenger: ContractFactory
let impersonatedL1CrossDomainMessengerSender: SignerWithAddress
before(async () => {
Factory__L2CrossDomainMessenger = await ethers.getContractFactory(
'L2CrossDomainMessenger'
impersonatedL1CrossDomainMessengerSender = await impersonate(
applyL1ToL2Alias(Fake__L1CrossDomainMessenger.address),
'0xFFFFFFFFFFFFFFFFF'
)
})

let L2CrossDomainMessenger: Contract
beforeEach(async () => {
L2CrossDomainMessenger = await Factory__L2CrossDomainMessenger.deploy(
Fake__L1CrossDomainMessenger.address
)
L2CrossDomainMessenger = await deploy('L2CrossDomainMessenger', {
args: [Fake__L1CrossDomainMessenger.address],
})
})

describe('xDomainMessageSender', () => {
let Mock__Factory__L2CrossDomainMessenger: MockContractFactory<ContractFactory>
let Mock__L2CrossDomainMessenger
let Mock__L2CrossDomainMessenger: MockContract<Contract>
before(async () => {
Mock__Factory__L2CrossDomainMessenger = await smock.mock(
'L2CrossDomainMessenger'
)
Mock__L2CrossDomainMessenger =
await Mock__Factory__L2CrossDomainMessenger.deploy(
Fake__L1CrossDomainMessenger.address
)
Mock__L2CrossDomainMessenger = await (
await smock.mock('L2CrossDomainMessenger')
).deploy(Fake__L1CrossDomainMessenger.address)
})

it('should return the xDomainMsgSender address', async () => {
await Mock__L2CrossDomainMessenger.setVariable(
'xDomainMsgSender',
'0x0000000000000000000000000000000000000000'
)

expect(
await Mock__L2CrossDomainMessenger.xDomainMessageSender()
).to.equal('0x0000000000000000000000000000000000000000')
})
})

describe('sendMessage', () => {
const target = NON_ZERO_ADDRESS
const message = NON_NULL_BYTES32
const gasLimit = 100_000

it('should be able to send a single message', async () => {
await expect(
L2CrossDomainMessenger.sendMessage(target, message, gasLimit)
L2CrossDomainMessenger.sendMessage(
NON_ZERO_ADDRESS,
NON_NULL_BYTES32,
100_000
)
).to.not.be.reverted

expect(
Fake__OVM_L2ToL1MessagePasser.passMessageToL1.getCall(0).args[0]
).to.deep.equal(
encodeXDomainCalldata(target, await signer.getAddress(), message, 0)
encodeXDomainCalldata(
NON_ZERO_ADDRESS,
await signer.getAddress(),
NON_NULL_BYTES32,
0
)
)
})

it('should be able to send the same message twice', async () => {
await L2CrossDomainMessenger.sendMessage(target, message, gasLimit)
await L2CrossDomainMessenger.sendMessage(
NON_ZERO_ADDRESS,
NON_NULL_BYTES32,
100_000
)

await expect(
L2CrossDomainMessenger.sendMessage(target, message, gasLimit)
L2CrossDomainMessenger.sendMessage(
NON_ZERO_ADDRESS,
NON_NULL_BYTES32,
100_000
)
).to.not.be.reverted
})
})

describe('relayMessage', () => {
let target: string
let message: string
let sender: string
before(async () => {
target = Fake__TargetContract.address
message = Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
])
sender = await signer.getAddress()
})

it('should revert if the L1 message sender is not the L1CrossDomainMessenger', async () => {
await expect(
L2CrossDomainMessenger.connect(signer).relayMessage(
target,
sender,
message,
Fake__TargetContract.address,
signer.address,
Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
]),
0
)
).to.be.revertedWith('Provided message could not be verified.')
Expand All @@ -145,7 +125,14 @@ describe('L2CrossDomainMessenger', () => {
it('should send a call to the target contract', async () => {
await L2CrossDomainMessenger.connect(
impersonatedL1CrossDomainMessengerSender
).relayMessage(target, sender, message, 0)
).relayMessage(
Fake__TargetContract.address,
signer.address,
Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
]),
0
)

expect(Fake__TargetContract.setTarget.getCall(0).args[0]).to.deep.equal(
NON_ZERO_ADDRESS
Expand All @@ -159,7 +146,14 @@ describe('L2CrossDomainMessenger', () => {

await L2CrossDomainMessenger.connect(
impersonatedL1CrossDomainMessengerSender
).relayMessage(target, sender, message, 0)
).relayMessage(
Fake__TargetContract.address,
signer.address,
Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
]),
0
)

await expect(
L2CrossDomainMessenger.xDomainMessageSender()
Expand All @@ -169,45 +163,72 @@ describe('L2CrossDomainMessenger', () => {
it('should revert if trying to send the same message twice', async () => {
await L2CrossDomainMessenger.connect(
impersonatedL1CrossDomainMessengerSender
).relayMessage(target, sender, message, 0)
).relayMessage(
Fake__TargetContract.address,
signer.address,
Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
]),
0
)

await expect(
L2CrossDomainMessenger.connect(
impersonatedL1CrossDomainMessengerSender
).relayMessage(target, sender, message, 0)
).relayMessage(
Fake__TargetContract.address,
signer.address,
Fake__TargetContract.interface.encodeFunctionData('setTarget', [
NON_ZERO_ADDRESS,
]),
0
)
).to.be.revertedWith('Provided message has already been received.')
})

it('should not make a call if the target is the L2 MessagePasser', async () => {
target = predeploys.OVM_L2ToL1MessagePasser
message = Fake__OVM_L2ToL1MessagePasser.interface.encodeFunctionData(
'passMessageToL1(bytes)',
[NON_NULL_BYTES32]
)

const resProm = L2CrossDomainMessenger.connect(
impersonatedL1CrossDomainMessengerSender
).relayMessage(target, sender, message, 0)
).relayMessage(
predeploys.OVM_L2ToL1MessagePasser,
signer.address,
Fake__OVM_L2ToL1MessagePasser.interface.encodeFunctionData(
'passMessageToL1(bytes)',
[NON_NULL_BYTES32]
),
0
)

// The call to relayMessage() should succeed.
await expect(resProm).to.not.be.reverted

// There should be no 'relayedMessage' event logged in the receipt.
const logs = (
await Fake__OVM_L2ToL1MessagePasser.provider.getTransactionReceipt(
(
await resProm
).hash
)
).logs
expect(logs).to.deep.equal([])
expect(
(
await Fake__OVM_L2ToL1MessagePasser.provider.getTransactionReceipt(
(
await resProm
).hash
)
).logs
).to.deep.equal([])

// The message should be registered as successful.
expect(
await L2CrossDomainMessenger.successfulMessages(
ethers.utils.solidityKeccak256(
['bytes'],
[encodeXDomainCalldata(target, sender, message, 0)]
[
encodeXDomainCalldata(
predeploys.OVM_L2ToL1MessagePasser,
signer.address,
Fake__OVM_L2ToL1MessagePasser.interface.encodeFunctionData(
'passMessageToL1(bytes)',
[NON_NULL_BYTES32]
),
0
),
]
)
)
).to.be.true
Expand Down
23 changes: 23 additions & 0 deletions packages/contracts/test/helpers/utils/impersonation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { toRpcHexString } from '@eth-optimism/core-utils'
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
import { BigNumber } from 'ethers'
import hre from 'hardhat'

export const impersonate = async (
address: string,
balance?: string | number | BigNumber
): Promise<SignerWithAddress> => {
await hre.network.provider.request({
method: 'hardhat_impersonateAccount',
params: [address],
})

if (balance !== undefined) {
await hre.network.provider.request({
method: 'hardhat_setBalance',
params: [address, toRpcHexString(BigNumber.from(balance))],
})
}

return hre.ethers.getSigner(address)
}
1 change: 1 addition & 0 deletions packages/contracts/test/helpers/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './eth-time'
export * from './deploy'
export * from './impersonation'