Commit c2b6e14b authored by Mark Tyneway's avatar Mark Tyneway Committed by GitHub

feat: fees v3 (#999)

* core-utils: fee impl v3

* l2geth: fees v3 impl

* integration-tests: update for fees v3

* chore: add changeset

* fix: typo

* integration-tests: fix and generalize

* fees: update fee scalar

* l2geth: check gas in the mempool behind usingovm

* tests: fix up

* l2geth: remove dead var

* truffle: fix config
parent 8082d16c
---
'@eth-optimism/integration-tests': patch
'@eth-optimism/l2geth': patch
'@eth-optimism/core-utils': patch
---
Implement the latest fee spec such that the L2 gas limit is scaled and the tx.gasPrice/tx.gasLimit show correctly in metamask
...@@ -17,6 +17,7 @@ module.exports = { ...@@ -17,6 +17,7 @@ module.exports = {
host: '127.0.0.1', host: '127.0.0.1',
port: 8545, port: 8545,
gasPrice: 0, gasPrice: 0,
gas: 54180127,
} }
}, },
compilers: { compilers: {
...@@ -31,4 +32,4 @@ module.exports = { ...@@ -31,4 +32,4 @@ module.exports = {
} }
} }
} }
} }
\ No newline at end of file
...@@ -3,7 +3,7 @@ import chaiAsPromised from 'chai-as-promised' ...@@ -3,7 +3,7 @@ import chaiAsPromised from 'chai-as-promised'
chai.use(chaiAsPromised) chai.use(chaiAsPromised)
import { BigNumber, utils } from 'ethers' import { BigNumber, utils } from 'ethers'
import { OptimismEnv } from './shared/env' import { OptimismEnv } from './shared/env'
import { TxGasLimit } from '@eth-optimism/core-utils' import { TxGasLimit, TxGasPrice } from '@eth-optimism/core-utils'
describe('Fee Payment Integration Tests', async () => { describe('Fee Payment Integration Tests', async () => {
let env: OptimismEnv let env: OptimismEnv
...@@ -13,9 +13,9 @@ describe('Fee Payment Integration Tests', async () => { ...@@ -13,9 +13,9 @@ describe('Fee Payment Integration Tests', async () => {
env = await OptimismEnv.new() env = await OptimismEnv.new()
}) })
it('Should return a gasPrice of 1 wei', async () => { it(`Should return a gasPrice of ${TxGasPrice.toString()} wei`, async () => {
const gasPrice = await env.l2Wallet.getGasPrice() const gasPrice = await env.l2Wallet.getGasPrice()
expect(gasPrice.eq(1)) expect(gasPrice).to.deep.eq(TxGasPrice)
}) })
it('Should estimateGas with recoverable L2 gasLimit', async () => { it('Should estimateGas with recoverable L2 gasLimit', async () => {
...@@ -28,7 +28,7 @@ describe('Fee Payment Integration Tests', async () => { ...@@ -28,7 +28,7 @@ describe('Fee Payment Integration Tests', async () => {
utils.parseEther('0.5') utils.parseEther('0.5')
) )
const executionGas = await (env.ovmEth const executionGas = await (env.ovmEth
.provider as any).send('eth_estimateExecutionGas', [tx]) .provider as any).send('eth_estimateExecutionGas', [tx, true])
const decoded = TxGasLimit.decode(gas) const decoded = TxGasLimit.decode(gas)
expect(BigNumber.from(executionGas)).deep.eq(decoded) expect(BigNumber.from(executionGas)).deep.eq(decoded)
}) })
......
...@@ -45,13 +45,13 @@ describe('Native ETH Integration Tests', async () => { ...@@ -45,13 +45,13 @@ describe('Native ETH Integration Tests', async () => {
const amount = utils.parseEther('0.5') const amount = utils.parseEther('0.5')
const addr = '0x' + '1234'.repeat(10) const addr = '0x' + '1234'.repeat(10)
const gas = await env.ovmEth.estimateGas.transfer(addr, amount) const gas = await env.ovmEth.estimateGas.transfer(addr, amount)
expect(gas).to.be.deep.eq(BigNumber.from(0x0ef897216d)) expect(gas).to.be.deep.eq(BigNumber.from(6430020))
}) })
it('Should estimate gas for ETH withdraw', async () => { it('Should estimate gas for ETH withdraw', async () => {
const amount = utils.parseEther('0.5') const amount = utils.parseEther('0.5')
const gas = await env.ovmEth.estimateGas.withdraw(amount) const gas = await env.ovmEth.estimateGas.withdraw(amount)
expect(gas).to.be.deep.eq(BigNumber.from(61400489396)) expect(gas).to.be.deep.eq(BigNumber.from(6140049))
}) })
}) })
......
...@@ -134,7 +134,7 @@ describe('Basic RPC tests', () => { ...@@ -134,7 +134,7 @@ describe('Basic RPC tests', () => {
gasPrice: TxGasPrice, gasPrice: TxGasPrice,
} }
const fee = tx.gasPrice.mul(tx.gasLimit) const fee = tx.gasPrice.mul(tx.gasLimit)
const gasLimit = 59300000001 const gasLimit = 5920001
await expect(env.l2Wallet.sendTransaction(tx)).to.be.rejectedWith( await expect(env.l2Wallet.sendTransaction(tx)).to.be.rejectedWith(
`fee too low: ${fee}, use at least tx.gasLimit = ${gasLimit} and tx.gasPrice = ${TxGasPrice.toString()}` `fee too low: ${fee}, use at least tx.gasLimit = ${gasLimit} and tx.gasPrice = ${TxGasPrice.toString()}`
...@@ -213,7 +213,7 @@ describe('Basic RPC tests', () => { ...@@ -213,7 +213,7 @@ describe('Basic RPC tests', () => {
it('correctly exposes revert data for contract calls', async () => { it('correctly exposes revert data for contract calls', async () => {
const req: TransactionRequest = { const req: TransactionRequest = {
...revertingTx, ...revertingTx,
gasLimit: 59808999999, // override gas estimation gasLimit: 5980899, // override gas estimation
} }
const tx = await wallet.sendTransaction(req) const tx = await wallet.sendTransaction(req)
...@@ -236,7 +236,7 @@ describe('Basic RPC tests', () => { ...@@ -236,7 +236,7 @@ describe('Basic RPC tests', () => {
it('correctly exposes revert data for contract creations', async () => { it('correctly exposes revert data for contract creations', async () => {
const req: TransactionRequest = { const req: TransactionRequest = {
...revertingDeployTx, ...revertingDeployTx,
gasLimit: 177008999999, // override gas estimation gasLimit: 17700899, // override gas estimation
} }
const tx = await wallet.sendTransaction(req) const tx = await wallet.sendTransaction(req)
...@@ -355,7 +355,7 @@ describe('Basic RPC tests', () => { ...@@ -355,7 +355,7 @@ describe('Basic RPC tests', () => {
to: DEFAULT_TRANSACTION.to, to: DEFAULT_TRANSACTION.to,
value: 0, value: 0,
}) })
expect(estimate).to.be.eq(0x0dce9004c7) expect(estimate).to.be.eq(5920012)
}) })
it('should return a gas estimate that grows with the size of data', async () => { it('should return a gas estimate that grows with the size of data', async () => {
...@@ -373,6 +373,7 @@ describe('Basic RPC tests', () => { ...@@ -373,6 +373,7 @@ describe('Basic RPC tests', () => {
const estimate = await l2Provider.estimateGas(tx) const estimate = await l2Provider.estimateGas(tx)
const l2Gaslimit = await l2Provider.send('eth_estimateExecutionGas', [ const l2Gaslimit = await l2Provider.send('eth_estimateExecutionGas', [
tx, tx,
true,
]) ])
const decoded = TxGasLimit.decode(estimate) const decoded = TxGasLimit.decode(estimate)
......
...@@ -92,9 +92,8 @@ var ( ...@@ -92,9 +92,8 @@ var (
) )
var ( var (
evictionInterval = time.Minute // Time interval to check for evictable transactions evictionInterval = time.Minute // Time interval to check for evictable transactions
statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats statsReportInterval = 8 * time.Second // Time interval to report transaction pool stats
gwei = big.NewInt(params.GWei) // 1 gwei, used as a flag for "rollup" transactions
) )
var ( var (
...@@ -540,10 +539,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { ...@@ -540,10 +539,14 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
} }
// Ensure the transaction doesn't exceed the current block limit gas. // Ensure the transaction doesn't exceed the current block limit gas.
// We skip this condition check if the transaction's gasPrice is set to 1gwei, if vm.UsingOVM {
// which indicates a "rollup" transaction that's paying for its data. if pool.currentMaxGas < tx.L2Gas() {
if pool.currentMaxGas < tx.L2Gas() && tx.GasPrice().Cmp(gwei) != 0 { return ErrGasLimit
return ErrGasLimit }
} else {
if pool.currentMaxGas < tx.Gas() {
return ErrGasLimit
}
} }
// Make sure the transaction is signed properly // Make sure the transaction is signed properly
......
...@@ -27,6 +27,7 @@ import ( ...@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rollup/fees"
) )
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go //go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
...@@ -225,7 +226,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { ...@@ -225,7 +226,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
func (tx *Transaction) L2Gas() uint64 { return tx.data.GasLimit % 100_000_000 } func (tx *Transaction) L2Gas() uint64 { return fees.DecodeL2GasLimitU64(tx.data.GasLimit) }
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
......
...@@ -1148,9 +1148,17 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h ...@@ -1148,9 +1148,17 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
// EstimateExecutionGas returns an estimate of the amount of gas needed to execute the // EstimateExecutionGas returns an estimate of the amount of gas needed to execute the
// given transaction against the current pending block. // given transaction against the current pending block.
func (s *PublicBlockChainAPI) EstimateExecutionGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) { func (s *PublicBlockChainAPI) EstimateExecutionGas(ctx context.Context, args CallArgs, round *bool) (hexutil.Uint64, error) {
blockNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) blockNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
return legacyDoEstimateGas(ctx, s.b, args, blockNrOrHash, s.b.RPCGasCap()) estimate, err := legacyDoEstimateGas(ctx, s.b, args, blockNrOrHash, s.b.RPCGasCap())
if err != nil {
return estimate, err
}
if round != nil && *round {
rounded := fees.Ceilmod(new(big.Int).SetUint64(uint64(estimate)), fees.BigTenThousand)
estimate = (hexutil.Uint64)(rounded.Uint64())
}
return estimate, nil
} }
// ExecutionResult groups all structured logs emitted by the EVM // ExecutionResult groups all structured logs emitted by the EVM
......
...@@ -3,6 +3,7 @@ package fees ...@@ -3,6 +3,7 @@ package fees
import ( import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
...@@ -10,12 +11,9 @@ import ( ...@@ -10,12 +11,9 @@ import (
// transaction in gas. // transaction in gas.
const overhead uint64 = 4200 + 200*params.TxDataNonZeroGasEIP2028 const overhead uint64 = 4200 + 200*params.TxDataNonZeroGasEIP2028
// hundredMillion is a constant used in the gas encoding formula
const hundredMillion uint64 = 100_000_000
// feeScalar is used to scale the calculations in EncodeL2GasLimit // feeScalar is used to scale the calculations in EncodeL2GasLimit
// to prevent them from being too large // to prevent them from being too large
const feeScalar uint64 = 1000 const feeScalar uint64 = 10_000_000
// TxGasPrice is a constant that determines the result of `eth_gasPrice` // TxGasPrice is a constant that determines the result of `eth_gasPrice`
// It is scaled upwards by 50% // It is scaled upwards by 50%
...@@ -26,7 +24,10 @@ const TxGasPrice uint64 = feeScalar + (feeScalar / 2) ...@@ -26,7 +24,10 @@ const TxGasPrice uint64 = feeScalar + (feeScalar / 2)
// BigTxGasPrice is the L2GasPrice as type big.Int // BigTxGasPrice is the L2GasPrice as type big.Int
var BigTxGasPrice = new(big.Int).SetUint64(TxGasPrice) var BigTxGasPrice = new(big.Int).SetUint64(TxGasPrice)
var bigFeeScalar = new(big.Int).SetUint64(feeScalar) var bigFeeScalar = new(big.Int).SetUint64(feeScalar)
var bigHundredMillion = new(big.Int).SetUint64(hundredMillion)
const tenThousand = 10000
var BigTenThousand = new(big.Int).SetUint64(tenThousand)
// EncodeTxGasLimit computes the `tx.gasLimit` based on the L1/L2 gas prices and // EncodeTxGasLimit computes the `tx.gasLimit` based on the L1/L2 gas prices and
// the L2 gas limit. The L2 gas limit is encoded inside of the lower order bits // the L2 gas limit. The L2 gas limit is encoded inside of the lower order bits
...@@ -40,32 +41,50 @@ var bigHundredMillion = new(big.Int).SetUint64(hundredMillion) ...@@ -40,32 +41,50 @@ var bigHundredMillion = new(big.Int).SetUint64(hundredMillion)
// the fee, so increasing the L2 Gas limit will increase the fee paid. // the fee, so increasing the L2 Gas limit will increase the fee paid.
// The calculation is: // The calculation is:
// l1GasLimit = zero_count(data) * 4 + non_zero_count(data) * 16 + overhead // l1GasLimit = zero_count(data) * 4 + non_zero_count(data) * 16 + overhead
// roundedL2GasLimit = ceilmod(l2GasLimit, 10_000)
// l1Fee = l1GasPrice * l1GasLimit // l1Fee = l1GasPrice * l1GasLimit
// l2Fee = l2GasPrice * l2GasLimit // l2Fee = l2GasPrice * roundedL2GasLimit
// sum = l1Fee + l2Fee // sum = l1Fee + l2Fee
// scaled = sum / scalar // scaled = sum / scalar
// rounded = ceilmod(scaled, hundredMillion) // rounded = ceilmod(scaled, tenThousand)
// result = rounded + l2GasLimit // roundedScaledL2GasLimit = roundedL2GasLimit / tenThousand
// result = rounded + roundedScaledL2GasLimit
// Note that for simplicity purposes, only the calldata is passed into this // Note that for simplicity purposes, only the calldata is passed into this
// function when in reality the RLP encoded transaction should be. The // function when in reality the RLP encoded transaction should be. The
// additional cost is added to the overhead constant to prevent the need to RLP // additional cost is added to the overhead constant to prevent the need to RLP
// encode transactions during calls to `eth_estimateGas` // encode transactions during calls to `eth_estimateGas`
func EncodeTxGasLimit(data []byte, l1GasPrice, l2GasLimit, l2GasPrice *big.Int) *big.Int { func EncodeTxGasLimit(data []byte, l1GasPrice, l2GasLimit, l2GasPrice *big.Int) *big.Int {
l1GasLimit := calculateL1GasLimit(data, overhead) l1GasLimit := calculateL1GasLimit(data, overhead)
roundedL2GasLimit := Ceilmod(l2GasLimit, BigTenThousand)
l1Fee := new(big.Int).Mul(l1GasPrice, l1GasLimit) l1Fee := new(big.Int).Mul(l1GasPrice, l1GasLimit)
l2Fee := new(big.Int).Mul(l2GasPrice, l2GasLimit) l2Fee := new(big.Int).Mul(l2GasPrice, roundedL2GasLimit)
sum := new(big.Int).Add(l1Fee, l2Fee) sum := new(big.Int).Add(l1Fee, l2Fee)
scaled := new(big.Int).Div(sum, bigFeeScalar) scaled := new(big.Int).Div(sum, bigFeeScalar)
remainder := new(big.Int).Mod(scaled, bigHundredMillion) rounded := Ceilmod(scaled, BigTenThousand)
scaledSum := new(big.Int).Add(scaled, bigHundredMillion) roundedScaledL2GasLimit := new(big.Int).Div(roundedL2GasLimit, BigTenThousand)
rounded := new(big.Int).Sub(scaledSum, remainder) result := new(big.Int).Add(rounded, roundedScaledL2GasLimit)
result := new(big.Int).Add(rounded, l2GasLimit)
return result return result
} }
func Ceilmod(a, b *big.Int) *big.Int {
remainder := new(big.Int).Mod(a, b)
if remainder.Cmp(common.Big0) == 0 {
return a
}
sum := new(big.Int).Add(a, b)
rounded := new(big.Int).Sub(sum, remainder)
return rounded
}
// DecodeL2GasLimit decodes the L2 gas limit from an encoded L2 gas limit // DecodeL2GasLimit decodes the L2 gas limit from an encoded L2 gas limit
func DecodeL2GasLimit(gasLimit *big.Int) *big.Int { func DecodeL2GasLimit(gasLimit *big.Int) *big.Int {
return new(big.Int).Mod(gasLimit, bigHundredMillion) scaled := new(big.Int).Mod(gasLimit, BigTenThousand)
return new(big.Int).Mul(scaled, BigTenThousand)
}
func DecodeL2GasLimitU64(gasLimit uint64) uint64 {
scaled := gasLimit % tenThousand
return scaled * tenThousand
} }
// calculateL1GasLimit computes the L1 gasLimit based on the calldata and // calculateL1GasLimit computes the L1 gasLimit based on the calldata and
......
...@@ -74,7 +74,7 @@ var feeTests = map[string]struct { ...@@ -74,7 +74,7 @@ var feeTests = map[string]struct {
"max-gaslimit": { "max-gaslimit": {
dataLen: 10, dataLen: 10,
l1GasPrice: params.GWei, l1GasPrice: params.GWei,
l2GasLimit: 99999999, l2GasLimit: 99_970_000,
l2GasPrice: params.GWei, l2GasPrice: params.GWei,
}, },
"larger-divisor": { "larger-divisor": {
...@@ -95,7 +95,8 @@ func TestCalculateRollupFee(t *testing.T) { ...@@ -95,7 +95,8 @@ func TestCalculateRollupFee(t *testing.T) {
fee := EncodeTxGasLimit(data, l1GasPrice, l2GasLimit, l2GasPrice) fee := EncodeTxGasLimit(data, l1GasPrice, l2GasLimit, l2GasPrice)
decodedGasLimit := DecodeL2GasLimit(fee) decodedGasLimit := DecodeL2GasLimit(fee)
if l2GasLimit.Cmp(decodedGasLimit) != 0 { roundedL2GasLimit := Ceilmod(l2GasLimit, BigTenThousand)
if roundedL2GasLimit.Cmp(decodedGasLimit) != 0 {
t.Errorf("rollup fee check failed: expected %d, got %d", l2GasLimit.Uint64(), decodedGasLimit) t.Errorf("rollup fee check failed: expected %d, got %d", l2GasLimit.Uint64(), decodedGasLimit)
} }
}) })
......
...@@ -6,11 +6,12 @@ import { BigNumber } from 'ethers' ...@@ -6,11 +6,12 @@ import { BigNumber } from 'ethers'
import { remove0x } from './common' import { remove0x } from './common'
const hundredMillion = BigNumber.from(100_000_000) const hundredMillion = BigNumber.from(100_000_000)
const feeScalar = 1000 const feeScalar = 10_000_000
export const TxGasPrice = BigNumber.from(feeScalar + feeScalar / 2) export const TxGasPrice = BigNumber.from(feeScalar + feeScalar / 2)
const txDataZeroGas = 4 const txDataZeroGas = 4
const txDataNonZeroGasEIP2028 = 16 const txDataNonZeroGasEIP2028 = 16
const overhead = 4200 + 200 * txDataNonZeroGasEIP2028 const overhead = 4200 + 200 * txDataNonZeroGasEIP2028
const tenThousand = BigNumber.from(10_000)
export interface EncodableL2GasLimit { export interface EncodableL2GasLimit {
data: Buffer | string data: Buffer | string
...@@ -32,21 +33,22 @@ function encode(input: EncodableL2GasLimit): BigNumber { ...@@ -32,21 +33,22 @@ function encode(input: EncodableL2GasLimit): BigNumber {
l2GasPrice = BigNumber.from(l2GasPrice) l2GasPrice = BigNumber.from(l2GasPrice)
} }
const l1GasLimit = calculateL1GasLimit(data) const l1GasLimit = calculateL1GasLimit(data)
const roundedL2GasLimit = ceilmod(l2GasLimit, tenThousand)
const l1Fee = l1GasLimit.mul(l1GasPrice) const l1Fee = l1GasLimit.mul(l1GasPrice)
const l2Fee = l2GasLimit.mul(l2GasPrice) const l2Fee = roundedL2GasLimit.mul(l2GasPrice)
const sum = l1Fee.add(l2Fee) const sum = l1Fee.add(l2Fee)
const scaled = sum.div(feeScalar) const scaled = sum.div(feeScalar)
const remainder = scaled.mod(hundredMillion) const rounded = ceilmod(scaled, tenThousand)
const scaledSum = scaled.add(hundredMillion) const roundedScaledL2GasLimit = roundedL2GasLimit.div(tenThousand)
const rounded = scaledSum.sub(remainder) return rounded.add(roundedScaledL2GasLimit)
return rounded.add(l2GasLimit)
} }
function decode(fee: BigNumber | number): BigNumber { function decode(fee: BigNumber | number): BigNumber {
if (typeof fee === 'number') { if (typeof fee === 'number') {
fee = BigNumber.from(fee) fee = BigNumber.from(fee)
} }
return fee.mod(hundredMillion) const scaled = fee.mod(tenThousand)
return scaled.mul(tenThousand)
} }
export const TxGasLimit = { export const TxGasLimit = {
...@@ -54,6 +56,22 @@ export const TxGasLimit = { ...@@ -54,6 +56,22 @@ export const TxGasLimit = {
decode, decode,
} }
export function ceilmod(a: BigNumber | number, b: BigNumber | number) {
if (typeof a === 'number') {
a = BigNumber.from(a)
}
if (typeof b === 'number') {
b = BigNumber.from(b)
}
const remainder = a.mod(b)
if (remainder.eq(0)) {
return a
}
const sum = a.add(b)
const rounded = sum.sub(remainder)
return rounded
}
export function calculateL1GasLimit(data: string | Buffer): BigNumber { export function calculateL1GasLimit(data: string | Buffer): BigNumber {
const [zeroes, ones] = zeroesAndOnes(data) const [zeroes, ones] = zeroesAndOnes(data)
const zeroesCost = zeroes * txDataZeroGas const zeroesCost = zeroes * txDataZeroGas
......
...@@ -56,7 +56,7 @@ describe('Fees', () => { ...@@ -56,7 +56,7 @@ describe('Fees', () => {
dataLen: 10, dataLen: 10,
l1GasPrice: utils.parseUnits('5', 'ether'), l1GasPrice: utils.parseUnits('5', 'ether'),
l2GasPrice: utils.parseUnits('5', 'ether'), l2GasPrice: utils.parseUnits('5', 'ether'),
l2GasLimit: 10 ** 8 - 1, l2GasLimit: 99_970_000,
}, },
{ {
name: 'zero-l2-gasprice', name: 'zero-l2-gasprice',
...@@ -113,7 +113,8 @@ describe('Fees', () => { ...@@ -113,7 +113,8 @@ describe('Fees', () => {
}) })
const decoded = fees.TxGasLimit.decode(got) const decoded = fees.TxGasLimit.decode(got)
expect(decoded).to.deep.eq(BigNumber.from(test.l2GasLimit)) const roundedL2GasLimit = fees.ceilmod(test.l2GasLimit, 10_000)
expect(decoded).to.deep.eq(roundedL2GasLimit)
}) })
} }
}) })
......
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