Skip to content

Commit

Permalink
integration-tests: fee tests
Browse files Browse the repository at this point in the history
Add test coverage for new fee scheme
and refactor old tests to work with new scheme
  • Loading branch information
tynes authored and smartcontracts committed Oct 1, 2021
1 parent 190b9e6 commit fa55de6
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/mighty-jars-rest.md
@@ -0,0 +1,5 @@
---
'@eth-optimism/integration-tests': patch
---

Add updated fee scheme integration tests
8 changes: 4 additions & 4 deletions integration-tests/package.json
Expand Up @@ -9,8 +9,7 @@
"lint": "yarn lint:fix && yarn lint:check",
"lint:fix": "yarn lint:check --fix",
"lint:check": "eslint .",
"build:integration": "yarn build:contracts",
"build:contracts": "hardhat compile",
"build": "hardhat compile",
"test:integration": "hardhat --network optimism test",
"test:integration:live": "IS_LIVE_NETWORK=true hardhat --network optimism test",
"test:sync": "hardhat --network optimism test sync-tests/*.spec.ts --no-compile",
Expand All @@ -21,6 +20,7 @@
"@eth-optimism/core-utils": "^0.6.0",
"@eth-optimism/message-relayer": "^0.1.13",
"@ethersproject/providers": "^5.4.4",
"@ethersproject/transactions": "^5.4.0",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-waffle": "^2.0.1",
"@types/chai": "^4.2.17",
Expand All @@ -30,19 +30,19 @@
"@types/shelljs": "^0.8.8",
"@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0",
"babel-eslint": "^10.1.0",
"chai": "^4.3.3",
"chai-as-promised": "^7.1.1",
"docker-compose": "^0.23.8",
"dotenv": "^10.0.0",
"envalid": "^7.1.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.27.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.1.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-unicorn": "^32.0.1",
"ethereum-waffle": "^3.3.0",
Expand Down
148 changes: 134 additions & 14 deletions integration-tests/test/fee-payment.spec.ts
Expand Up @@ -4,37 +4,157 @@ chai.use(chaiAsPromised)

/* Imports: External */
import { ethers, BigNumber, Contract, utils } from 'ethers'
import { TxGasLimit, TxGasPrice } from '@eth-optimism/core-utils'
import { predeploys, getContractInterface } from '@eth-optimism/contracts'
import { sleep } from '@eth-optimism/core-utils'
import { serialize } from '@ethersproject/transactions'
import {
predeploys,
getContractInterface,
getContractFactory,
} from '@eth-optimism/contracts'

/* Imports: Internal */
import { IS_LIVE_NETWORK } from './shared/utils'
import { OptimismEnv } from './shared/env'
import { Direction } from './shared/watcher-utils'

const setPrices = async (env: OptimismEnv, value: number | BigNumber) => {
const gasPrice = await env.gasPriceOracle.setGasPrice(value)
await gasPrice.wait()
const baseFee = await env.gasPriceOracle.setL1BaseFee(value)
await baseFee.wait()
}

describe('Fee Payment Integration Tests', async () => {
let env: OptimismEnv
const other = '0x1234123412341234123412341234123412341234'

before(async () => {
env = await OptimismEnv.new()
})

let ovmSequencerFeeVault: Contract
before(async () => {
ovmSequencerFeeVault = new Contract(
predeploys.OVM_SequencerFeeVault,
getContractInterface('OVM_SequencerFeeVault'),
env.l2Wallet
it(`should return eth_gasPrice equal to OVM_GasPriceOracle.gasPrice`, async () => {
const assertGasPrice = async () => {
const gasPrice = await env.l2Wallet.getGasPrice()
const oracleGasPrice = await env.gasPriceOracle.gasPrice()
expect(gasPrice).to.deep.equal(oracleGasPrice)
}

assertGasPrice()
// update the gas price
const tx = await env.gasPriceOracle.setGasPrice(1000)
await tx.wait()

assertGasPrice()
})

it('Paying a nonzero but acceptable gasPrice fee', async () => {
await setPrices(env, 1000)

const amount = utils.parseEther('0.0000001')
const balanceBefore = await env.l2Wallet.getBalance()
const feeVaultBalanceBefore = await env.l2Wallet.provider.getBalance(
env.sequencerFeeVault.address
)
expect(balanceBefore.gt(amount))

const unsigned = await env.l2Wallet.populateTransaction({
to: other,
value: amount,
gasLimit: 500000,
})

const raw = serialize({
nonce: parseInt(unsigned.nonce.toString(10), 10),
value: unsigned.value,
gasPrice: unsigned.gasPrice,
gasLimit: unsigned.gasLimit,
to: unsigned.to,
data: unsigned.data,
})

const l1Fee = await env.gasPriceOracle.getL1Fee(raw)

const tx = await env.l2Wallet.sendTransaction(unsigned)
const receipt = await tx.wait()
expect(receipt.status).to.eq(1)

const balanceAfter = await env.l2Wallet.getBalance()
const feeVaultBalanceAfter = await env.l2Wallet.provider.getBalance(
env.sequencerFeeVault.address
)

const l2Fee = receipt.gasUsed.mul(tx.gasPrice)

const expectedFeePaid = l1Fee.add(l2Fee)

expect(balanceBefore.sub(balanceAfter)).to.deep.equal(
expectedFeePaid.add(amount)
)

// Make sure the fee was transferred to the vault.
expect(feeVaultBalanceAfter.sub(feeVaultBalanceBefore)).to.deep.equal(
expectedFeePaid
)

await setPrices(env, 1)
})

it('should compute correct fee', async () => {
await setPrices(env, 1000)

const preBalance = await env.l2Wallet.getBalance()

const OVM_GasPriceOracle = getContractFactory('OVM_GasPriceOracle')
.attach(predeploys.OVM_GasPriceOracle)
.connect(env.l2Wallet)

const WETH = getContractFactory('OVM_ETH')
.attach(predeploys.OVM_ETH)
.connect(env.l2Wallet)

const feeVaultBefore = await WETH.balanceOf(
predeploys.OVM_SequencerFeeVault
)

const unsigned = await env.l2Wallet.populateTransaction({
to: env.l2Wallet.address,
value: 0,
})

const raw = serialize({
nonce: parseInt(unsigned.nonce.toString(10), 10),
value: unsigned.value,
gasPrice: unsigned.gasPrice,
gasLimit: unsigned.gasLimit,
to: unsigned.to,
data: unsigned.data,
})

const l1Fee = await OVM_GasPriceOracle.getL1Fee(raw)

const tx = await env.l2Wallet.sendTransaction(unsigned)
const receipt = await tx.wait()
const l2Fee = receipt.gasUsed.mul(tx.gasPrice)
const postBalance = await env.l2Wallet.getBalance()
const feeVaultAfter = await WETH.balanceOf(predeploys.OVM_SequencerFeeVault)
const fee = l1Fee.add(l2Fee)
const balanceDiff = preBalance.sub(postBalance)
const feeReceived = feeVaultAfter.sub(feeVaultBefore)
expect(balanceDiff).to.deep.equal(fee)
// There is no inflation
expect(feeReceived).to.deep.equal(balanceDiff)

await setPrices(env, 1)
})

it('should not be able to withdraw fees before the minimum is met', async () => {
await expect(ovmSequencerFeeVault.withdraw()).to.be.rejected
await expect(env.sequencerFeeVault.withdraw()).to.be.rejected
})

it('should be able to withdraw fees back to L1 once the minimum is met', async function () {
const l1FeeWallet = await ovmSequencerFeeVault.l1FeeWallet()
const l1FeeWallet = await env.sequencerFeeVault.l1FeeWallet()
const balanceBefore = await env.l1Wallet.provider.getBalance(l1FeeWallet)
const withdrawalAmount = await ovmSequencerFeeVault.MIN_WITHDRAWAL_AMOUNT()
const withdrawalAmount = await env.sequencerFeeVault.MIN_WITHDRAWAL_AMOUNT()

const l2WalletBalance = await env.l2Wallet.getBalance()
if (IS_LIVE_NETWORK && l2WalletBalance.lt(withdrawalAmount)) {
Expand All @@ -48,18 +168,18 @@ describe('Fee Payment Integration Tests', async () => {

// Transfer the minimum required to withdraw.
const tx = await env.l2Wallet.sendTransaction({
to: ovmSequencerFeeVault.address,
to: env.sequencerFeeVault.address,
value: withdrawalAmount,
gasLimit: 500000,
})
await tx.wait()

const vaultBalance = await env.ovmEth.balanceOf(
ovmSequencerFeeVault.address
env.sequencerFeeVault.address
)

// Submit the withdrawal.
const withdrawTx = await ovmSequencerFeeVault.withdraw({
const withdrawTx = await env.sequencerFeeVault.withdraw({
gasPrice: 0, // Need a gasprice of 0 or the balances will include the fee paid during this tx.
})

Expand Down
47 changes: 41 additions & 6 deletions integration-tests/test/native-eth.spec.ts
Expand Up @@ -2,6 +2,7 @@ import { expect } from 'chai'

/* Imports: External */
import { Wallet, utils, BigNumber } from 'ethers'
import { serialize } from '@ethersproject/transactions'
import { predeploys } from '@eth-optimism/contracts'

/* Imports: Internal */
Expand Down Expand Up @@ -248,24 +249,44 @@ describe('Native ETH Integration Tests', async () => {
DEFAULT_TEST_GAS_L2,
'0xFFFF'
)

await transaction.wait()
await env.relayXDomainMessages(transaction)
const receipts = await env.waitForXDomainTransaction(
transaction,
Direction.L2ToL1
)
const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice)

const l2Fee = receipts.tx.gasPrice.mul(receipts.receipt.gasUsed)

// Calculate the L1 portion of the fee
const raw = serialize({
nonce: transaction.nonce,
value: transaction.value,
gasPrice: transaction.gasPrice,
gasLimit: transaction.gasLimit,
to: transaction.to,
data: transaction.data,
})

const l1Fee = await env.gasPriceOracle.getL1Fee(raw)
const fee = l2Fee.add(l1Fee)

const postBalances = await getBalances(env)

expect(postBalances.l1BridgeBalance).to.deep.eq(
preBalances.l1BridgeBalance.sub(withdrawAmount)
preBalances.l1BridgeBalance.sub(withdrawAmount),
'L1 Bridge Balance Mismatch'
)

expect(postBalances.l2UserBalance).to.deep.eq(
preBalances.l2UserBalance.sub(withdrawAmount.add(fee))
preBalances.l2UserBalance.sub(withdrawAmount.add(fee)),
'L2 User Balance Mismatch'
)

expect(postBalances.l1BobBalance).to.deep.eq(
preBalances.l1BobBalance.add(withdrawAmount)
preBalances.l1BobBalance.add(withdrawAmount),
'L1 User Balance Mismatch'
)
})

Expand All @@ -282,7 +303,7 @@ describe('Native ETH Integration Tests', async () => {
Direction.L1ToL2
)

// 2. trnsfer to another address
// 2. transfer to another address
const other = Wallet.createRandom().connect(env.l2Wallet.provider)
const tx = await env.l2Wallet.sendTransaction({
to: other.address,
Expand Down Expand Up @@ -311,8 +332,22 @@ describe('Native ETH Integration Tests', async () => {
Direction.L2ToL1
)

// Compute the L1 portion of the fee
const l1Fee = await env.gasPriceOracle.getL1Fee(
serialize({
nonce: transaction.nonce,
value: transaction.value,
gasPrice: transaction.gasPrice,
gasLimit: transaction.gasLimit,
to: transaction.to,
data: transaction.data,
})
)

// check that correct amount was withdrawn and that fee was charged
const fee = receipts.tx.gasLimit.mul(receipts.tx.gasPrice)
const l2Fee = receipts.tx.gasPrice.mul(receipts.receipt.gasUsed)

const fee = l1Fee.add(l2Fee)
const l1BalanceAfter = await other
.connect(env.l1Wallet.provider)
.getBalance()
Expand Down
6 changes: 1 addition & 5 deletions integration-tests/test/rpc.spec.ts
@@ -1,8 +1,4 @@
import {
injectL2Context,
TxGasLimit,
TxGasPrice,
} from '@eth-optimism/core-utils'
import { injectL2Context } from '@eth-optimism/core-utils'
import { Wallet, BigNumber, Contract, ContractFactory } from 'ethers'
import { ethers } from 'hardhat'
import chai, { expect } from 'chai'
Expand Down

0 comments on commit fa55de6

Please sign in to comment.