Commit 5b966580 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Merge pull request #2209 from tonykogias/increase-codecov-contracts-package

increase coverage of contracts package
parents aa726e84 60658a23
......@@ -9,6 +9,7 @@ import { Lib_Buffer } from "../../libraries/utils/Lib_Buffer.sol";
*/
contract TestLib_Buffer {
using Lib_Buffer for Lib_Buffer.Buffer;
using Lib_Buffer for Lib_Buffer.BufferContext;
Lib_Buffer.Buffer internal buf;
......@@ -16,6 +17,10 @@ contract TestLib_Buffer {
buf.push(_value, _extraData);
}
function push(bytes32 _value) public {
buf.push(_value);
}
function get(uint256 _index) public view returns (bytes32) {
return buf.get(_index);
}
......@@ -39,4 +44,16 @@ contract TestLib_Buffer {
function getExtraData() public view returns (bytes27) {
return buf.getExtraData();
}
function getContext() public view returns (Lib_Buffer.BufferContext memory) {
return buf.getContext();
}
function setContext(uint40 _index, bytes27 _extraData) public {
Lib_Buffer.BufferContext memory _ctx = Lib_Buffer.BufferContext({
length: _index,
extraData: _extraData
});
return buf.setContext(_ctx);
}
}
/* External Imports */
import { ethers } from 'hardhat'
import { Contract, Signer, ContractFactory } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup'
import { NON_ZERO_ADDRESS } from '../../../helpers'
describe('AddressDictator', () => {
let signer: Signer
let otherSigner: Signer
let signerAddress: string
let Factory__AddressDictator: ContractFactory
let Factory__Lib_AddressManager: ContractFactory
before(async () => {
;[signer, otherSigner] = await ethers.getSigners()
Factory__AddressDictator = await ethers.getContractFactory(
'AddressDictator'
)
Factory__Lib_AddressManager = await ethers.getContractFactory(
'Lib_AddressManager'
)
signerAddress = await signer.getAddress()
})
let AddressDictator: Contract
let Lib_AddressManager: Contract
beforeEach(async () => {
Lib_AddressManager = await Factory__Lib_AddressManager.connect(
signer
).deploy()
AddressDictator = await Factory__AddressDictator.connect(signer).deploy(
Lib_AddressManager.address,
signerAddress,
['addr1'],
[NON_ZERO_ADDRESS]
)
Lib_AddressManager.transferOwnership(AddressDictator.address)
})
describe('initialize', () => {
it('should revert when providing wrong arguments', async () => {
await expect(
Factory__AddressDictator.connect(signer).deploy(
Lib_AddressManager.address,
signerAddress,
['addr1', 'addr2'],
[NON_ZERO_ADDRESS]
)
).to.be.revertedWith(
'AddressDictator: Must provide an equal number of names and addresses.'
)
})
})
describe('setAddresses', async () => {
it('should change the addresses associated with a name', async () => {
await AddressDictator.setAddresses()
expect(await Lib_AddressManager.getAddress('addr1')).to.be.equal(
NON_ZERO_ADDRESS
)
})
})
describe('getNamedAddresses', () => {
it('should return all the addresses and their names', async () => {
expect(await AddressDictator.getNamedAddresses()).to.be.deep.equal([
['addr1', NON_ZERO_ADDRESS],
])
})
})
describe('returnOwnership', () => {
it('should transfer contract ownership to finalOwner', async () => {
await expect(AddressDictator.connect(signer).returnOwnership()).to.not.be
.reverted
})
it('should revert when called by non-owner', async () => {
await expect(
AddressDictator.connect(otherSigner).returnOwnership()
).to.be.revertedWith('AddressDictator: only callable by finalOwner')
})
})
})
/* External Imports */
import { ethers } from 'hardhat'
import { Contract, Signer, ContractFactory } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup'
describe('ChugSplashDictator', () => {
let signer: Signer
let otherSigner: Signer
let signerAddress: string
let Factory__L1ChugSplashProxy: ContractFactory
let Factory__ChugSplashDictator: ContractFactory
before(async () => {
;[signer, otherSigner] = await ethers.getSigners()
Factory__L1ChugSplashProxy = await ethers.getContractFactory(
'L1ChugSplashProxy'
)
Factory__ChugSplashDictator = await ethers.getContractFactory(
'ChugSplashDictator'
)
signerAddress = await signer.getAddress()
})
let L1ChugSplashProxy: Contract
let ChugSplashDictator: Contract
beforeEach(async () => {
L1ChugSplashProxy = await Factory__L1ChugSplashProxy.connect(signer).deploy(
signerAddress
)
ChugSplashDictator = await Factory__ChugSplashDictator.connect(
signer
).deploy(
L1ChugSplashProxy.address,
signerAddress,
ethers.utils.keccak256('0x1111'),
ethers.utils.keccak256('0x1234'),
ethers.utils.keccak256('0x5678'),
ethers.utils.keccak256('0x1234'),
ethers.utils.keccak256('0x1234')
)
await L1ChugSplashProxy.connect(signer).setOwner(ChugSplashDictator.address)
})
describe('doActions', () => {
it('should revert when sent wrong code', async () => {
await expect(ChugSplashDictator.doActions('0x2222')).to.be.revertedWith(
'ChugSplashDictator: Incorrect code hash.'
)
})
it('should set the proxy code, storage & owner', async () => {
await expect(ChugSplashDictator.connect(signer).doActions('0x1111')).to
.not.be.reverted
})
})
describe('returnOwnership', () => {
it('should transfer contractc ownership to finalOwner', async () => {
await expect(ChugSplashDictator.connect(signer).returnOwnership()).to.not
.be.reverted
})
it('should revert when called by non-owner', async () => {
await expect(
ChugSplashDictator.connect(otherSigner).returnOwnership()
).to.be.revertedWith('ChugSplashDictator: only callable by finalOwner')
})
})
})
......@@ -2,6 +2,7 @@
import { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract, BigNumber } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { smock, MockContractFactory } from '@defi-wonderland/smock'
import {
remove0x,
toHexString,
......@@ -347,6 +348,28 @@ describe('L1CrossDomainMessenger', () => {
})
})
describe('xDomainMessageSender', () => {
let Mock__Factory__L1CrossDomainMessenger: MockContractFactory<ContractFactory>
let Mock__L1CrossDomainMessenger
before(async () => {
Mock__Factory__L1CrossDomainMessenger = await smock.mock(
'L1CrossDomainMessenger'
)
Mock__L1CrossDomainMessenger =
await Mock__Factory__L1CrossDomainMessenger.deploy()
})
it('should return the xDomainMsgSender address', async () => {
await Mock__L1CrossDomainMessenger.setVariable(
'xDomainMsgSender',
'0x0000000000000000000000000000000000000000'
)
expect(
await Mock__L1CrossDomainMessenger.xDomainMessageSender()
).to.equal('0x0000000000000000000000000000000000000000')
})
})
const generateMockRelayMessageProof = async (
target: string,
sender: string,
......
......@@ -88,6 +88,17 @@ describe('L1StandardBridge', () => {
})
})
describe('receive', () => {
it('should send an amount of ETH to the callers balance on L2', async () => {
await expect(
alice.sendTransaction({
to: L1StandardBridge.address,
data: '0x',
})
).to.not.be.reverted
})
})
describe('ETH deposits', () => {
const depositAmount = 1_000
......@@ -564,4 +575,18 @@ describe('L1StandardBridge', () => {
)
})
})
describe('donateETH', () => {
it('it should just call the function', async () => {
await expect(L1StandardBridge.donateETH()).to.not.be.reverted
})
it('should send ETH to the contract account', async () => {
await expect(
L1StandardBridge.donateETH({
value: 100,
})
).to.not.be.reverted
})
})
})
......@@ -218,6 +218,18 @@ describe('CanonicalTransactionChain', () => {
).to.be.revertedWith('Insufficient gas for L2 rate limiting burn.')
})
it('should burn L1 gas when L2 gas limit is high', async () => {
const _enqueueL2GasPrepaid =
await CanonicalTransactionChain.enqueueL2GasPrepaid()
const data = '0x' + '12'.repeat(1234)
// Create a tx with high L2 gas limit
const l2GasLimit = 4 * _enqueueL2GasPrepaid
await expect(CanonicalTransactionChain.enqueue(target, l2GasLimit, data))
.to.not.be.reverted
})
describe('with valid input parameters', () => {
it('should emit a TransactionEnqueued event', async () => {
const timestamp = (await getEthTime(ethers.provider)) + 100
......
/* External Imports */
import { ethers } from 'hardhat'
import { Contract, Signer, ContractFactory } from 'ethers'
/* Internal Imports */
import { expect } from '../../../setup'
import { makeAddressManager, NON_NULL_BYTES32 } from '../../../helpers'
describe('ChainStorageContainer', () => {
let sequencer: Signer
let otherSigner: Signer
let signer: Signer
let signerAddress: string
let AddressManager: Contract
let Factory__ChainStorageContainer: ContractFactory
before(async () => {
;[sequencer, otherSigner, signer] = await ethers.getSigners()
signerAddress = await otherSigner.getAddress()
AddressManager = await makeAddressManager()
await AddressManager.setAddress(
'OVM_Sequencer',
await sequencer.getAddress()
)
Factory__ChainStorageContainer = await ethers.getContractFactory(
'ChainStorageContainer'
)
})
let ChainStorageContainer: Contract
beforeEach(async () => {
ChainStorageContainer = await Factory__ChainStorageContainer.connect(
otherSigner
).deploy(AddressManager.address, signerAddress)
await AddressManager.setAddress(
'ChainStorageContainer',
ChainStorageContainer.address
)
await AddressManager.setAddress(signerAddress, signerAddress)
})
describe('push', () => {
for (const len of [1, 2, 4, 8, 32]) {
it(`it should be able to add ${len} element(s) to the array`, async () => {
for (let i = 0; i < len; i++) {
await expect(
ChainStorageContainer.connect(otherSigner)['push(bytes32)'](
NON_NULL_BYTES32
)
).to.not.be.reverted
}
})
}
})
describe('setGlobalMetadata', () => {
it('should modify the extra data', async () => {
const globalMetaData = `0x${'11'.repeat(27)}`
await ChainStorageContainer.connect(otherSigner).setGlobalMetadata(
globalMetaData
)
expect(await ChainStorageContainer.getGlobalMetadata()).to.equal(
globalMetaData
)
})
})
describe('deleteElementsAfterInclusive', () => {
it('should revert when the array is empty', async () => {
await expect(
ChainStorageContainer.connect(otherSigner)[
'deleteElementsAfterInclusive(uint256)'
](0)
).to.be.reverted
})
it('should revert when called by non-owner', async () => {
await expect(
ChainStorageContainer.connect(signer)[
'deleteElementsAfterInclusive(uint256)'
](0)
).to.be.revertedWith(
'ChainStorageContainer: Function can only be called by the owner.'
)
})
for (const len of [1, 2, 4, 8, 32]) {
describe(`when the array has ${len} element(s)`, () => {
const values = []
beforeEach(async () => {
for (let i = 0; i < len; i++) {
const value = NON_NULL_BYTES32
values.push(value)
await ChainStorageContainer.connect(otherSigner)['push(bytes32)'](
value
)
}
})
for (let i = len - 1; i > 0; i -= Math.max(1, len / 4)) {
it(`should be able to delete everything after and including the ${i}th/st/rd/whatever element`, async () => {
await expect(
ChainStorageContainer.connect(otherSigner)[
'deleteElementsAfterInclusive(uint256)'
](i)
).to.not.be.reverted
expect(await ChainStorageContainer.length()).to.equal(i)
await expect(ChainStorageContainer.get(i)).to.be.reverted
})
}
})
}
})
})
......@@ -409,17 +409,97 @@ describe('StateCommitmentChain', () => {
})
})
describe('verifyElement()', () => {
describe('getLastSequencerTimestamp', () => {
describe('when no batches have been inserted', () => {
it('should return zero', async () => {
expect(await StateCommitmentChain.getLastSequencerTimestamp()).to.equal(
0
)
})
})
describe('when one batch element has been inserted', () => {
let timestamp
beforeEach(async () => {
const batch = [NON_NULL_BYTES32]
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
await StateCommitmentChain.appendStateBatch(batch, 0)
timestamp = await getEthTime(ethers.provider)
})
it('should return the number of inserted batch elements', async () => {
expect(await StateCommitmentChain.getLastSequencerTimestamp()).to.equal(
timestamp
)
})
})
})
describe('verifyStateCommitment()', () => {
const batch = [NON_NULL_BYTES32]
const batchHeader = {
batchIndex: 0,
batchRoot: NON_NULL_BYTES32,
batchSize: 1,
prevTotalElements: 0,
extraData: ethers.constants.HashZero,
}
const inclusionProof = {
index: 0,
siblings: [],
}
const element = NON_NULL_BYTES32
before(async () => {
Mock__BondManager.smocked.isCollateralized.will.return.with(true)
})
beforeEach(async () => {
Mock__CanonicalTransactionChain.smocked.getTotalElements.will.return.with(
batch.length
)
await StateCommitmentChain.appendStateBatch(batch, 0)
batchHeader.extraData = ethers.utils.defaultAbiCoder.encode(
['uint256', 'address'],
[await getEthTime(ethers.provider), await sequencer.getAddress()]
)
})
it('should revert when given an invalid batch header', async () => {
// TODO
await expect(
StateCommitmentChain.verifyStateCommitment(
element,
{
...batchHeader,
extraData: '0x' + '22'.repeat(32),
},
inclusionProof
)
).to.be.revertedWith('Invalid batch header.')
})
it('should revert when given an invalid inclusion proof', async () => {
// TODO
await expect(
StateCommitmentChain.verifyStateCommitment(
ethers.constants.HashZero,
batchHeader,
inclusionProof
)
).to.be.revertedWith('Invalid inclusion proof.')
})
it('should return true when given a valid proof', async () => {
// TODO
expect(
await StateCommitmentChain.verifyStateCommitment(
element,
batchHeader,
inclusionProof
)
).to.equal(true)
})
})
})
......@@ -3,6 +3,7 @@ import hre, { ethers } from 'hardhat'
import { Signer, ContractFactory, Contract } from 'ethers'
import { smockit, MockContract } from '@eth-optimism/smock'
import { applyL1ToL2Alias } from '@eth-optimism/core-utils'
import { smock, MockContractFactory } from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -67,6 +68,30 @@ describe('L2CrossDomainMessenger', () => {
)
})
describe('xDomainMessageSender', () => {
let Mock__Factory__L2CrossDomainMessenger: MockContractFactory<ContractFactory>
let Mock__L2CrossDomainMessenger
before(async () => {
Mock__Factory__L2CrossDomainMessenger = await smock.mock(
'L2CrossDomainMessenger'
)
Mock__L2CrossDomainMessenger =
await Mock__Factory__L2CrossDomainMessenger.deploy(
Mock__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
......
......@@ -7,6 +7,7 @@ import {
smoddit,
ModifiableContract,
} from '@eth-optimism/smock'
import { smock } from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -20,6 +21,7 @@ const DUMMY_L1BRIDGE_ADDRESS: string =
'0x1234123412341234123412341234123412341234'
const DUMMY_L1TOKEN_ADDRESS: string =
'0x2234223412342234223422342234223422342234'
const OVM_ETH_ADDRESS: string = '0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000'
describe('L2StandardBridge', () => {
let alice: Signer
......@@ -182,6 +184,15 @@ describe('L2StandardBridge', () => {
describe('withdrawals', () => {
const withdrawAmount = 1_000
let SmoddedL2Token: ModifiableContract
let Fake__OVM_ETH
before(async () => {
Fake__OVM_ETH = await smock.fake('OVM_ETH', {
address: OVM_ETH_ADDRESS,
})
})
beforeEach(async () => {
// Deploy a smodded gateway so we can give some balances to withdraw
SmoddedL2Token = await (
......@@ -203,6 +214,35 @@ describe('L2StandardBridge', () => {
})
})
it('withdraw() withdraws and sends the correct withdrawal message for OVM_ETH', async () => {
await L2StandardBridge.withdraw(
Fake__OVM_ETH.address,
0,
0,
NON_NULL_BYTES32
)
const withdrawalCallToMessenger =
Mock__L2CrossDomainMessenger.smocked.sendMessage.calls[0]
// Assert the correct cross-chain call was sent:
// Message should be sent to the L1L1StandardBridge on L1
expect(withdrawalCallToMessenger._target).to.equal(DUMMY_L1BRIDGE_ADDRESS)
// Message data should be a call telling the L1StandardBridge to finalize the withdrawal
expect(withdrawalCallToMessenger._message).to.equal(
Factory__L1StandardBridge.interface.encodeFunctionData(
'finalizeETHWithdrawal',
[
await alice.getAddress(),
await alice.getAddress(),
0,
NON_NULL_BYTES32,
]
)
)
})
it('withdraw() burns and sends the correct withdrawal message', async () => {
await L2StandardBridge.withdraw(
SmoddedL2Token.address,
......
/* External Imports */
import { ethers } from 'hardhat'
import { Contract, Signer, ContractFactory } from 'ethers'
import {
smock,
MockContractFactory,
MockContract,
} from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
describe('WETH9', () => {
let signer: Signer
let otherSigner: Signer
let signerAddress: string
let otherSignerAddress: string
let Mock__Factory_WETH9: MockContractFactory<ContractFactory>
let Mock__WETH9: MockContract<Contract>
before(async () => {
;[signer, otherSigner] = await ethers.getSigners()
signerAddress = await signer.getAddress()
otherSignerAddress = await otherSigner.getAddress()
})
beforeEach(async () => {
Mock__Factory_WETH9 = await smock.mock('WETH9')
Mock__WETH9 = await Mock__Factory_WETH9.deploy()
})
describe('deposit', () => {
it('should create WETH with fallback function', async () => {
await expect(
signer.sendTransaction({
to: Mock__WETH9.address,
value: 200,
})
).to.not.be.reverted
expect(await Mock__WETH9.balanceOf(signerAddress)).to.be.equal(200)
})
it('should create WETH with deposit function', async () => {
await expect(Mock__WETH9.connect(signer).deposit({ value: 100 })).to.not
.be.reverted
expect(await Mock__WETH9.balanceOf(signerAddress)).to.be.equal(100)
})
})
describe('withdraw', () => {
it('should revert when withdraw amount is bigger than balance', async () => {
await expect(Mock__WETH9.connect(signer).withdraw(10000)).to.be.reverted
})
it('should withdraw to eth', async () => {
await Mock__WETH9.connect(signer).deposit({ value: 100 })
await expect(Mock__WETH9.connect(signer).withdraw(50)).to.not.be.reverted
expect(await Mock__WETH9.balanceOf(signerAddress)).to.be.equal(50)
})
})
describe('totalSupply', () => {
it('should return the totalSupply', async () => {
await expect(Mock__WETH9.totalSupply()).to.not.be.reverted
})
})
describe('transfer', () => {
it('should revert when sending more than deposited', async () => {
await Mock__WETH9.connect(signer).deposit({ value: 100 })
await expect(
Mock__WETH9.connect(signer).transfer(otherSignerAddress, 500)
).to.be.reverted
})
it('should transfer WETH to an other address', async () => {
await Mock__WETH9.connect(signer).deposit({ value: 100 })
await expect(Mock__WETH9.connect(signer).transfer(otherSignerAddress, 50))
.to.not.be.reverted
expect(await Mock__WETH9.balanceOf(signerAddress)).to.be.equal(50)
expect(await Mock__WETH9.balanceOf(otherSignerAddress)).to.be.equal(50)
})
})
describe('transferFrom', () => {
it('should revert when there is no allowance', async () => {
await Mock__WETH9.connect(signer).deposit({ value: 100 })
await expect(
Mock__WETH9.connect(otherSigner).transferFrom(
signerAddress,
otherSignerAddress,
50
)
).to.be.reverted
})
it('should transfer WETH to an other address when there is approvement', async () => {
await Mock__WETH9.connect(signer).deposit({ value: 100 })
await Mock__WETH9.connect(signer).approve(otherSignerAddress, 50)
await expect(
Mock__WETH9.connect(otherSigner).transferFrom(
signerAddress,
otherSignerAddress,
50
)
).to.not.be.reverted
})
})
})
/* External Imports */
import { ethers } from 'hardhat'
import { Contract } from 'ethers'
/* Internal Imports */
import '../../../setup'
import { Lib_OVMCodec_TEST_JSON } from '../../../data'
import { runJsonTest } from '../../../helpers'
import { expect } from '../../../setup'
import { NON_ZERO_ADDRESS } from '../../../helpers'
describe('Lib_OVMCodec', () => {
let Lib_OVMCodec: Contract
before(async () => {
Lib_OVMCodec = await (
await ethers.getContractFactory('TestLib_OVMCodec')
).deploy()
})
describe('hashTransaction', () => {
enum QueueOrigin {
SEQUENCER_QUEUE,
L1TOL2_QUEUE,
}
it('should return the hash of a transaction', async () => {
const tx = {
timestamp: 121212,
blockNumber: 10,
l1QueueOrigin: QueueOrigin.SEQUENCER_QUEUE,
l1TxOrigin: NON_ZERO_ADDRESS,
entrypoint: NON_ZERO_ADDRESS,
gasLimit: 100,
data: '0x1234',
}
describe.skip('Lib_OVMCodec', () => {
describe('JSON tests', () => {
runJsonTest('TestLib_OVMCodec', Lib_OVMCodec_TEST_JSON)
expect(await Lib_OVMCodec.hashTransaction(tx)).to.be.equal(
'0xf07818e2db63d0140e55c9e68cfaa030f9a2d0962f671d6b339edb2207633ebd'
)
})
})
})
......@@ -38,6 +38,16 @@ describe('Lib_RLPWriter', () => {
}
})
describe('writeBool', () => {
it(`should encode bool: true`, async () => {
expect(await Lib_RLPWriter.writeBool(true)).to.equal('0x01')
})
it(`should encode bool: false`, async () => {
expect(await Lib_RLPWriter.writeBool(false)).to.equal('0x80')
})
})
describe('Use of library with other memory-modifying operations', () => {
it('should allow creation of a contract beforehand and still work', async () => {
const randomAddress = '0x1234123412341234123412341234123412341234'
......
......@@ -115,4 +115,22 @@ describe('Lib_SecureMerkleTrie', () => {
})
}
})
describe('getSingleNodeRootHash', () => {
let generator: TrieTestGenerator
before(async () => {
generator = await TrieTestGenerator.fromRandom({
seed: `seed.get.${1}`,
nodeCount: 1,
secure: true,
})
})
it(`should get the root hash of a trie with a single node`, async () => {
const test = await generator.makeInclusionProofTest(0)
expect(
await Lib_SecureMerkleTrie.getSingleNodeRootHash(test.key, test.val)
).to.equal(test.root)
})
})
})
......@@ -12,12 +12,12 @@ describe('Lib_Buffer', () => {
Lib_Buffer = await Factory__Lib_Buffer.deploy()
})
describe('push', () => {
describe('push(bytes32,bytes27)', () => {
for (const len of [1, 2, 4, 8, 32]) {
it(`it should be able to add ${len} element(s) to the array`, async () => {
for (let i = 0; i < len; i++) {
await expect(
Lib_Buffer.push(
Lib_Buffer['push(bytes32,bytes27)'](
ethers.utils.keccak256(`0x${i.toString(16).padStart(16, '0')}`),
`0x${'00'.repeat(27)}`
)
......@@ -27,6 +27,20 @@ describe('Lib_Buffer', () => {
}
})
describe('push(bytes32)', () => {
for (const len of [1, 2, 4, 8, 32]) {
it(`it should be able to add ${len} element(s) to the array`, async () => {
for (let i = 0; i < len; i++) {
await expect(
Lib_Buffer['push(bytes32)'](
ethers.utils.keccak256(`0x${i.toString(16).padStart(16, '0')}`)
)
).to.not.be.reverted
}
})
}
})
describe('get', () => {
for (const len of [1, 2, 4, 8, 32]) {
describe(`when the array has ${len} element(s)`, () => {
......@@ -37,7 +51,10 @@ describe('Lib_Buffer', () => {
`0x${i.toString(16).padStart(16, '0')}`
)
values.push(value)
await Lib_Buffer.push(value, `0x${'00'.repeat(27)}`)
await Lib_Buffer['push(bytes32,bytes27)'](
value,
`0x${'00'.repeat(27)}`
)
}
})
......@@ -68,7 +85,10 @@ describe('Lib_Buffer', () => {
`0x${i.toString(16).padStart(16, '0')}`
)
values.push(value)
await Lib_Buffer.push(value, `0x${'00'.repeat(27)}`)
await Lib_Buffer['push(bytes32,bytes27)'](
value,
`0x${'00'.repeat(27)}`
)
}
})
......@@ -86,20 +106,26 @@ describe('Lib_Buffer', () => {
it('should change if set by a call to push()', async () => {
const extraData = `0x${'11'.repeat(27)}`
await Lib_Buffer.push(ethers.utils.keccak256('0x00'), extraData)
await Lib_Buffer['push(bytes32,bytes27)'](
ethers.utils.keccak256('0x00'),
extraData
)
expect(await Lib_Buffer.getExtraData()).to.equal(extraData)
})
it('should change if set multiple times', async () => {
await Lib_Buffer.push(
await Lib_Buffer['push(bytes32,bytes27)'](
ethers.utils.keccak256('0x00'),
`0x${'11'.repeat(27)}`
)
const extraData = `0x${'22'.repeat(27)}`
await Lib_Buffer.push(ethers.utils.keccak256('0x00'), extraData)
await Lib_Buffer['push(bytes32,bytes27)'](
ethers.utils.keccak256('0x00'),
extraData
)
expect(await Lib_Buffer.getExtraData()).to.equal(extraData)
})
......@@ -140,7 +166,10 @@ describe('Lib_Buffer', () => {
`0x${i.toString(16).padStart(16, '0')}`
)
values.push(value)
await Lib_Buffer.push(value, `0x${'00'.repeat(27)}`)
await Lib_Buffer['push(bytes32,bytes27)'](
value,
`0x${'00'.repeat(27)}`
)
}
})
......@@ -172,4 +201,26 @@ describe('Lib_Buffer', () => {
})
}
})
describe('setContext', () => {
it('should modify the context', async () => {
const length = 20
const extraData = `0x${'11'.repeat(27)}`
const cntx = [length, extraData]
await Lib_Buffer.setContext(length, extraData)
expect(await Lib_Buffer.getContext()).to.eql(cntx)
})
it('should not modify the context', async () => {
const length = 0
const extraData = `0x${'00'.repeat(27)}`
const prevContext = await Lib_Buffer.getContext()
await Lib_Buffer.setContext(length, extraData)
expect(await Lib_Buffer.getContext()).to.eql(prevContext)
})
})
})
......@@ -3,6 +3,7 @@ import { ethers } from 'hardhat'
import { Contract, BigNumber } from 'ethers'
import { MerkleTree } from 'merkletreejs'
import { fromHexString, toHexString } from '@eth-optimism/core-utils'
import { smock, FakeContract } from '@defi-wonderland/smock'
/* Internal Imports */
import { expect } from '../../../setup'
......@@ -32,10 +33,15 @@ const fillDefaultHashes = (elements: string[]): string[] => {
describe('Lib_MerkleTree', () => {
let Lib_MerkleTree: Contract
let Fake__LibMerkleTree: FakeContract<Contract>
before(async () => {
Lib_MerkleTree = await (
await ethers.getContractFactory('TestLib_MerkleTree')
).deploy()
Fake__LibMerkleTree = await smock.fake(
await ethers.getContractFactory('TestLib_MerkleTree')
)
})
describe('getMerkleRoot', () => {
......@@ -78,6 +84,19 @@ describe('Lib_MerkleTree', () => {
})
}
})
describe('when odd number of elements is provided', () => {
it(`should generate the correct root when odd number of elements are provided`, async () => {
const elements = ['0x12', '0x34', '0x56'].map((value) =>
ethers.utils.keccak256(value)
)
Fake__LibMerkleTree.getMerkleRoot.returns()
// expect(await Fake__LibMerkleTree.getMerkleRoot(elements)).to.not.be.reverted
await expect(Lib_MerkleTree.getMerkleRoot(elements)).to.not.be.reverted
})
})
})
describe('verify', () => {
......@@ -99,6 +118,24 @@ describe('Lib_MerkleTree', () => {
})
})
describe('when total elements is zero', () => {
const totalLeaves = 0
it('should revert', async () => {
await expect(
Lib_MerkleTree.verify(
ethers.constants.HashZero,
ethers.constants.HashZero,
0,
[],
totalLeaves
)
).to.be.revertedWith(
'Lib_MerkleTree: Total leaves must be greater than zero.'
)
})
})
describe('when an index is out of bounds', () => {
const totalLeaves = 1
const index = 2
......
......@@ -3,4 +3,3 @@ export { tests as Lib_RLPReader_TEST_JSON } from './json/libraries/rlp/Lib_RLPRe
export { tests as Lib_Bytes32Utils_TEST_JSON } from './json/libraries/utils/Lib_Bytes32Utils.test.json'
export { tests as Lib_BytesUtils_TEST_JSON } from './json/libraries/utils/Lib_BytesUtils.test.json'
export { tests as Lib_MerkleTrie_TEST_JSON } from './json/libraries/trie/Lib_MerkleTrie.test.json'
export { tests as Lib_OVMCodec_TEST_JSON } from './json/libraries/codec/Lib_OVMCodec.test.json'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment