Skip to content

Commit

Permalink
fix arbitrum preVerificationGas calculation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mouseless-eth committed Sep 26, 2024
1 parent 8ad4618 commit 2cfd4b2
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 7 deletions.
76 changes: 75 additions & 1 deletion src/handlers/gasPriceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from "@alto/types"
import { maxBigInt, minBigInt, type Logger } from "@alto/utils"
import * as sentry from "@sentry/node"
import { parseGwei, type Chain, type PublicClient } from "viem"
import { parseGwei, type Chain, type PublicClient, maxUint128 } from "viem"
import {
celo,
celoAlfajores,
Expand Down Expand Up @@ -36,6 +36,77 @@ function getGasStationUrl(chainId: ChainId.Polygon | ChainId.Mumbai): string {
}
}

class ArbitrumManager {
private queueL1BaseFee: { timestamp: number; baseFee: bigint }[]
private queueL2BaseFee: { timestamp: number; baseFee: bigint }[]

private maxQueueSize
private queueValidity = 15_000

constructor(maxQueueSize: number) {
this.maxQueueSize = maxQueueSize
this.queueL1BaseFee = []
this.queueL2BaseFee = []
}

public saveL1BaseFee(baseFee: bigint) {
const queue = this.queueL1BaseFee
const last = queue.length > 0 ? queue[queue.length - 1] : null
const timestamp = Date.now()

if (!last || timestamp - last.timestamp >= this.queueValidity) {
if (queue.length >= this.maxQueueSize) {
queue.shift()
}
queue.push({ baseFee, timestamp })
} else if (baseFee < last.baseFee) {
last.baseFee = baseFee
last.timestamp = timestamp
}
}

public saveL2BaseFee(baseFee: bigint) {
const queue = this.queueL2BaseFee
const last = queue.length > 0 ? queue[queue.length - 1] : null
const timestamp = Date.now()

if (!last || timestamp - last.timestamp >= this.queueValidity) {
if (queue.length >= this.maxQueueSize) {
queue.shift()
}
queue.push({ baseFee, timestamp })
} else if (baseFee < last.baseFee) {
last.baseFee = baseFee
last.timestamp = timestamp
}
}

public async getMinL1BaseFee() {
const queue = this.queueL1BaseFee

if (queue.length === 0) {
return 1n
}
return queue.reduce(
(acc: bigint, cur) => minBigInt(cur.baseFee, acc),
queue[0].baseFee
)
}

public async getMaxL2BaseFee() {
const queue = this.queueL2BaseFee

if (queue.length === 0) {
return maxUint128
}

return queue.reduce(
(acc: bigint, cur) => maxBigInt(cur.baseFee, acc),
queue[0].baseFee
)
}
}

export class GasPriceManager {
private chain: Chain
private publicClient: PublicClient
Expand All @@ -53,6 +124,7 @@ export class GasPriceManager {
private gasBumpMultiplier: bigint
private gasPriceRefreshIntervalInSeconds: number
private chainType: ChainType
public arbitrumManager: ArbitrumManager

constructor(
chain: Chain,
Expand Down Expand Up @@ -83,6 +155,8 @@ export class GasPriceManager {
this.updateGasPrice()
}, this.gasPriceRefreshIntervalInSeconds * 1000)
}

this.arbitrumManager = new ArbitrumManager(this.maxQueueSize)
}

public init() {
Expand Down
25 changes: 19 additions & 6 deletions src/utils/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,9 +330,10 @@ export async function calcPreVerificationGas(
preVerificationGas = await calcArbitrumPreVerificationGas(
publicClient,
userOperation,
validate,
entryPoint,
preVerificationGas
preVerificationGas,
gasPriceManager,
validate
)
}

Expand Down Expand Up @@ -583,9 +584,10 @@ const getArbitrumL1FeeAbi = [
export async function calcArbitrumPreVerificationGas(
publicClient: PublicClient<Transport, Chain | undefined>,
op: UserOperation,
validate: boolean,
entryPoint: Address,
staticFee: bigint
staticFee: bigint,
gasPriceManager: GasPriceManager,
validate: boolean
) {
let selector: Hex
let paramData: Hex
Expand Down Expand Up @@ -651,10 +653,21 @@ export async function calcArbitrumPreVerificationGas(
serializedTx
])

let gasForL1 = result[0]
let [gasForL1, l2BaseFee, l1BaseFeeEstimate] = result

gasPriceManager.arbitrumManager.saveL1BaseFee(l1BaseFeeEstimate)
gasPriceManager.arbitrumManager.saveL2BaseFee(l2BaseFee)

if (validate) {
gasForL1 = (gasForL1 * 80n) / 100n
// gasEstimateL1Component source: https://github.com/OffchainLabs/nitro/blob/5cd7d6913eb6b4dedb08f6ea49d7f9802d2cc5b9/execution/nodeInterface/NodeInterface.go#L515-L551
const feesForL1 = (gasForL1 * l2BaseFee) / l1BaseFeeEstimate

const minL1BaseFeeEstimate =
await gasPriceManager.arbitrumManager.getMinL1BaseFee()
const maxBaseFee =
await gasPriceManager.arbitrumManager.getMaxL2BaseFee()

gasForL1 = (feesForL1 * minL1BaseFeeEstimate) / maxBaseFee
}

return staticFee + gasForL1
Expand Down

0 comments on commit 2cfd4b2

Please sign in to comment.