Skip to content

wip for a possible fix where celo receives undervalued gas estimates#522

Open
L03TJ3 wants to merge 1 commit into
masterfrom
fee-estimates-celo-are-undervalueing-txs
Open

wip for a possible fix where celo receives undervalued gas estimates#522
L03TJ3 wants to merge 1 commit into
masterfrom
fee-estimates-celo-are-undervalueing-txs

Conversation

@L03TJ3
Copy link
Copy Markdown
Contributor

@L03TJ3 L03TJ3 commented Apr 20, 2026

Description

For some reason forno.celo returns undervalued fee-estimates on the server. this behavior is not able to replicated from my local environment. but the log from the server shows these values being used:

"message": "sending tx from:",
"context": [
{
....
"balance": null,
"gas": 268106,
"maxFeePerGas": "30000000000",
"maxPriorityFeePerGas": "200000000",
....
}
]
},

The proposed fix follows changes applied in: https://github.com/GoodDollar/GoodWalletV2/pull/2155
but as far as I can tell if the server caches older fee-estimates anywhere this fix on its own will not change or fix anything.

What has been set as 'floor' hardcoded is at the moment 50 gwei since that is pretty consistently been the base floor since last wendesday.
It would in the short time likely make more transactions succeed but would fail anytime maxFeePerGas is HIGHER then 50 gwei (and this happens on/off throughout the day)

Summary by Sourcery

Adjust gas pricing normalization to treat configured EIP-1559 fee values as floors and prefer higher provider estimates, with Celo-specific fee floors to avoid underpriced transactions.

Bug Fixes:

  • Prevent underpriced Celo EIP-1559 transactions by enforcing minimum maxFeePerGas and maxPriorityFeePerGas floors against provider fee estimates.

Enhancements:

  • Introduce a helper to select gas fees using a configurable floor and update EIP-1559 fee normalization to fall back to floors when estimation fails.
  • Configure Celo admin wallet with explicit EIP-1559 fee floors tuned to typical base fee and tip levels.

Tests:

  • Add unit tests covering gas pricing behavior when provider fees exceed floors, underbid floors, or when fee estimation fails.

@L03TJ3 L03TJ3 requested a review from sirpy April 20, 2026 07:48
@L03TJ3
Copy link
Copy Markdown
Contributor Author

L03TJ3 commented Apr 20, 2026

@copilot can you review the proposed fix and perhaps conclude why or how we could end up with different estimated gas values then when testing locally (looking at our use of getFeeEstimates in Web3Wallet.js)

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 4 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/server/blockchain/Web3Wallet.js" line_range="1253" />
<code_context>
+      const maxFeeFloor = maxFeePerGas !== undefined ? maxFeePerGas : this.maxFeePerGas
+      const maxPriorityFloor = maxPriorityFeePerGas !== undefined ? maxPriorityFeePerGas : this.maxPriorityFeePerGas
+
+      const needsEstimation = !maxFeePerGas || !maxPriorityFeePerGas
+
+      if (needsEstimation) {
</code_context>
<issue_to_address>
**issue (bug_risk):** The `needsEstimation` check now treats `'0'`/`0` differently than before and may skip estimation when values are numerically zero.

Previously, `toNumber` ensured that `0` and invalid values were treated as needing estimation via `if (!maxFeeNum || !maxPriorityNum)`. The new check `!maxFeePerGas || !maxPriorityFeePerGas` works on the raw inputs, so a string like `'0'` is truthy and will no longer trigger estimation. This changes behavior for callers passing zero-like values and may result in using a zero max fee/tip instead of estimating. If you want to preserve the old behavior (zero → re-estimate), `needsEstimation` should be based on numeric-converted values or an explicit zero check rather than the raw inputs.
</issue_to_address>

### Comment 2
<location path="src/server/blockchain/Web3Wallet.js" line_range="1275-1276" />
<code_context>
+      }

       // Convert to numbers for comparison
       let maxFeeNum = toNumber(maxFeePerGas)
       let maxPriorityNum = toNumber(maxPriorityFeePerGas)

-      // Fetch fee estimates if EIP-1559 fees are not provided or invalid
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Loss of the previous `!maxFeeNum || !maxPriorityNum` validation means NaN values are no longer corrected via estimation.

With the removal of this guard, non-numeric `maxFeePerGas` / `maxPriorityFeePerGas` can now become `NaN` via `toNumber` while `needsEstimation` is `false`, so they’ll flow into the comparison logic and downstream fee handling as `NaN`. To keep the prior safety behavior, add a post-conversion check (e.g. `!Number.isFinite(maxFeeNum)` or `maxFeeNum <= 0`, same for priority fee) and fall back to estimates or a safe default when the values are invalid.
</issue_to_address>

### Comment 3
<location path="src/server/blockchain/__tests__/web3wallet.gas.test.js" line_range="39-48" />
<code_context>
+  test('prefers provider EIP-1559 fees when they are above configured floors', async () => {
</code_context>
<issue_to_address>
**suggestion (testing):** Add tests for the branch where both EIP-1559 fees are fully provided and no estimation is performed.

The current tests only cover cases where `needsEstimation` is `true` (at least one of `maxFeePerGas` / `maxPriorityFeePerGas` is missing). Please add a test that passes both values in `txParams` so `needsEstimation` is `false`, and verify that:

- `getFeeEstimates` is not called
- The returned `maxFeePerGas` / `maxPriorityFeePerGas` match the provided values (used as floors) and still satisfy the EIP-1559 constraint after adjustment.

This will cover the non-estimation path when callers fully specify fees.

Suggested implementation:

```javascript
  beforeEach(() => {
    jest.clearAllMocks()
  })

  test('uses fully specified EIP-1559 fees without estimation', async () => {
    const wallet = createTestWallet({
      maxFeePerGas: '60000000000',
      maxPriorityFeePerGas: '3000000000'
    })

    wallet.supportsEIP1559 = jest.fn().mockResolvedValue(true)
    wallet.getFeeEstimates = jest.fn()

    const txParams = {
      maxFeePerGas: '60000000000',
      maxPriorityFeePerGas: '3000000000'
    }

    const result = await wallet.getGasPricing(txParams, logger)

    expect(wallet.getFeeEstimates).not.toHaveBeenCalled()
    expect(result.maxFeePerGas).toBe('60000000000')
    expect(result.maxPriorityFeePerGas).toBe('3000000000')
    expect(BigInt(result.maxFeePerGas)).toBeGreaterThanOrEqual(BigInt(result.maxPriorityFeePerGas))
  })

  test('prefers provider EIP-1559 fees when they are above configured floors', async () => {

```

- If the helper used in this file is not `wallet.getGasPricing(txParams, logger)` but some other function (e.g. a standalone `getGasPricing(wallet, txParams, logger)`), adjust the call accordingly while keeping the assertions identical.
- If `maxFeePerGas` / `maxPriorityFeePerGas` in the rest of the suite are `BigNumber`/`BN`/numeric types rather than strings, convert the literals and comparisons to match that convention, and adapt the EIP-1559 constraint assertion to use the same big-number utilities.
</issue_to_address>

### Comment 4
<location path="src/server/blockchain/Web3Wallet.js" line_range="1206" />
<code_context>
     }
   }

+  pickFeeWithFloor(value: string | number | void, floor: string | number | void) {
+    if (value === null || value === undefined) {
+      return floor
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying the EIP-1559 fee handling by removing `pickFeeWithFloor` and doing all floor and estimate logic in a single numeric flow using `Math.max` and `toNumber`.

You can keep the “instance values as floors” behavior with a single, numeric flow and remove `pickFeeWithFloor`. That reduces branching and type juggling without changing semantics.

### 1. Drop `pickFeeWithFloor` and use numeric comparison

Instead of mixing `BigInt`, `toString`, and null-handling in a helper, normalize to numbers once and use `Math.max`:

```js
// remove this entirely
pickFeeWithFloor(value: string | number | void, floor: string | number | void) {
  if (value === null || value === undefined) {
    return floor
  }

  if (floor === null || floor === undefined) {
    return value
  }

  return BigInt(value.toString()) < BigInt(floor.toString()) ? floor : value
}
```

Inline floor application after estimates:

```js
// Instance values are treated as floors so live provider estimates can rise above them.
const maxFeeFloor = maxFeePerGas !== undefined ? maxFeePerGas : this.maxFeePerGas
const maxPriorityFloor = maxPriorityFeePerGas !== undefined ? maxPriorityFeePerGas : this.maxPriorityFeePerGas

const hasAnyFeeInput =
  maxFeePerGas != null ||
  maxPriorityFeePerGas != null

if (!hasAnyFeeInput) {
  try {
    const { baseFee, priorityFee } = await this.getFeeEstimates()

    const baseFeeNum = toNumber(baseFee)
    const priorityFeeNum = toNumber(priorityFee)
    const maxFeeFloorNum = toNumber(maxFeeFloor)
    const maxPriorityFloorNum = toNumber(maxPriorityFloor)

    // estimates can rise above floors
    const effectiveMaxFeeNum = Math.max(baseFeeNum, maxFeeFloorNum)
    const effectiveMaxPriorityNum = Math.max(priorityFeeNum, maxPriorityFloorNum)

    maxFeePerGas = effectiveMaxFeeNum.toString()
    maxPriorityFeePerGas = effectiveMaxPriorityNum.toString()
  } catch (error) {
    logger.warn('Failed to estimate EIP-1559 fees, falling back to configured values', {
      error: error.message,
      network: this.network,
      networkId: this.networkId,
    })
    maxFeePerGas = maxFeeFloor
    maxPriorityFeePerGas = maxPriorityFloor
  }
} else {
  maxFeePerGas = maxFeeFloor
  maxPriorityFeePerGas = maxPriorityFloor
}
```

### 2. Keep normalization and validation in one place

Now the rest of the logic stays as-is and operates in one numeric domain:

```js
let maxFeeNum = toNumber(maxFeePerGas)
let maxPriorityNum = toNumber(maxPriorityFeePerGas)

if (maxPriorityNum > 0 && (maxFeeNum === 0 || maxFeeNum < maxPriorityNum)) {
  logger.warn('maxFeePerGas < maxPriorityFeePerGas or is 0, adjusting maxFeePerGas', {
    originalMaxFeePerGas: maxFeePerGas,
    maxPriorityFeePerGas: maxPriorityFeePerGas,
    adjustedMaxFeePerGas: maxPriorityFeePerGas,
  })
  maxFeePerGas = maxPriorityFeePerGas
}
```

This keeps the new behavior:

- Instance values are floors.
- Estimates can exceed floors.
- On estimation failure, you fall back to floors.

But it removes the extra helper, avoids BigInt juggling, and makes the flow linear: compute floors → optionally fetch estimates → apply floors vs estimates numerically → enforce EIP‑1559 constraint.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

const maxFeeFloor = maxFeePerGas !== undefined ? maxFeePerGas : this.maxFeePerGas
const maxPriorityFloor = maxPriorityFeePerGas !== undefined ? maxPriorityFeePerGas : this.maxPriorityFeePerGas

const needsEstimation = !maxFeePerGas || !maxPriorityFeePerGas
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The needsEstimation check now treats '0'/0 differently than before and may skip estimation when values are numerically zero.

Previously, toNumber ensured that 0 and invalid values were treated as needing estimation via if (!maxFeeNum || !maxPriorityNum). The new check !maxFeePerGas || !maxPriorityFeePerGas works on the raw inputs, so a string like '0' is truthy and will no longer trigger estimation. This changes behavior for callers passing zero-like values and may result in using a zero max fee/tip instead of estimating. If you want to preserve the old behavior (zero → re-estimate), needsEstimation should be based on numeric-converted values or an explicit zero check rather than the raw inputs.

Comment on lines 1275 to 1276
let maxFeeNum = toNumber(maxFeePerGas)
let maxPriorityNum = toNumber(maxPriorityFeePerGas)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Loss of the previous !maxFeeNum || !maxPriorityNum validation means NaN values are no longer corrected via estimation.

With the removal of this guard, non-numeric maxFeePerGas / maxPriorityFeePerGas can now become NaN via toNumber while needsEstimation is false, so they’ll flow into the comparison logic and downstream fee handling as NaN. To keep the prior safety behavior, add a post-conversion check (e.g. !Number.isFinite(maxFeeNum) or maxFeeNum <= 0, same for priority fee) and fall back to estimates or a safe default when the values are invalid.

Comment on lines +39 to +48
test('prefers provider EIP-1559 fees when they are above configured floors', async () => {
const wallet = createTestWallet({
maxFeePerGas: '40000000000',
maxPriorityFeePerGas: '1000000000'
})

wallet.supportsEIP1559 = jest.fn().mockResolvedValue(true)
wallet.getFeeEstimates = jest.fn().mockResolvedValue({
baseFee: 52000000000,
priorityFee: 2000000000
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Add tests for the branch where both EIP-1559 fees are fully provided and no estimation is performed.

The current tests only cover cases where needsEstimation is true (at least one of maxFeePerGas / maxPriorityFeePerGas is missing). Please add a test that passes both values in txParams so needsEstimation is false, and verify that:

  • getFeeEstimates is not called
  • The returned maxFeePerGas / maxPriorityFeePerGas match the provided values (used as floors) and still satisfy the EIP-1559 constraint after adjustment.

This will cover the non-estimation path when callers fully specify fees.

Suggested implementation:

  beforeEach(() => {
    jest.clearAllMocks()
  })

  test('uses fully specified EIP-1559 fees without estimation', async () => {
    const wallet = createTestWallet({
      maxFeePerGas: '60000000000',
      maxPriorityFeePerGas: '3000000000'
    })

    wallet.supportsEIP1559 = jest.fn().mockResolvedValue(true)
    wallet.getFeeEstimates = jest.fn()

    const txParams = {
      maxFeePerGas: '60000000000',
      maxPriorityFeePerGas: '3000000000'
    }

    const result = await wallet.getGasPricing(txParams, logger)

    expect(wallet.getFeeEstimates).not.toHaveBeenCalled()
    expect(result.maxFeePerGas).toBe('60000000000')
    expect(result.maxPriorityFeePerGas).toBe('3000000000')
    expect(BigInt(result.maxFeePerGas)).toBeGreaterThanOrEqual(BigInt(result.maxPriorityFeePerGas))
  })

  test('prefers provider EIP-1559 fees when they are above configured floors', async () => {
  • If the helper used in this file is not wallet.getGasPricing(txParams, logger) but some other function (e.g. a standalone getGasPricing(wallet, txParams, logger)), adjust the call accordingly while keeping the assertions identical.
  • If maxFeePerGas / maxPriorityFeePerGas in the rest of the suite are BigNumber/BN/numeric types rather than strings, convert the literals and comparisons to match that convention, and adapt the EIP-1559 constraint assertion to use the same big-number utilities.

}
}

pickFeeWithFloor(value: string | number | void, floor: string | number | void) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider simplifying the EIP-1559 fee handling by removing pickFeeWithFloor and doing all floor and estimate logic in a single numeric flow using Math.max and toNumber.

You can keep the “instance values as floors” behavior with a single, numeric flow and remove pickFeeWithFloor. That reduces branching and type juggling without changing semantics.

1. Drop pickFeeWithFloor and use numeric comparison

Instead of mixing BigInt, toString, and null-handling in a helper, normalize to numbers once and use Math.max:

// remove this entirely
pickFeeWithFloor(value: string | number | void, floor: string | number | void) {
  if (value === null || value === undefined) {
    return floor
  }

  if (floor === null || floor === undefined) {
    return value
  }

  return BigInt(value.toString()) < BigInt(floor.toString()) ? floor : value
}

Inline floor application after estimates:

// Instance values are treated as floors so live provider estimates can rise above them.
const maxFeeFloor = maxFeePerGas !== undefined ? maxFeePerGas : this.maxFeePerGas
const maxPriorityFloor = maxPriorityFeePerGas !== undefined ? maxPriorityFeePerGas : this.maxPriorityFeePerGas

const hasAnyFeeInput =
  maxFeePerGas != null ||
  maxPriorityFeePerGas != null

if (!hasAnyFeeInput) {
  try {
    const { baseFee, priorityFee } = await this.getFeeEstimates()

    const baseFeeNum = toNumber(baseFee)
    const priorityFeeNum = toNumber(priorityFee)
    const maxFeeFloorNum = toNumber(maxFeeFloor)
    const maxPriorityFloorNum = toNumber(maxPriorityFloor)

    // estimates can rise above floors
    const effectiveMaxFeeNum = Math.max(baseFeeNum, maxFeeFloorNum)
    const effectiveMaxPriorityNum = Math.max(priorityFeeNum, maxPriorityFloorNum)

    maxFeePerGas = effectiveMaxFeeNum.toString()
    maxPriorityFeePerGas = effectiveMaxPriorityNum.toString()
  } catch (error) {
    logger.warn('Failed to estimate EIP-1559 fees, falling back to configured values', {
      error: error.message,
      network: this.network,
      networkId: this.networkId,
    })
    maxFeePerGas = maxFeeFloor
    maxPriorityFeePerGas = maxPriorityFloor
  }
} else {
  maxFeePerGas = maxFeeFloor
  maxPriorityFeePerGas = maxPriorityFloor
}

2. Keep normalization and validation in one place

Now the rest of the logic stays as-is and operates in one numeric domain:

let maxFeeNum = toNumber(maxFeePerGas)
let maxPriorityNum = toNumber(maxPriorityFeePerGas)

if (maxPriorityNum > 0 && (maxFeeNum === 0 || maxFeeNum < maxPriorityNum)) {
  logger.warn('maxFeePerGas < maxPriorityFeePerGas or is 0, adjusting maxFeePerGas', {
    originalMaxFeePerGas: maxFeePerGas,
    maxPriorityFeePerGas: maxPriorityFeePerGas,
    adjustedMaxFeePerGas: maxPriorityFeePerGas,
  })
  maxFeePerGas = maxPriorityFeePerGas
}

This keeps the new behavior:

  • Instance values are floors.
  • Estimates can exceed floors.
  • On estimation failure, you fall back to floors.

But it removes the extra helper, avoids BigInt juggling, and makes the flow linear: compute floors → optionally fetch estimates → apply floors vs estimates numerically → enforce EIP‑1559 constraint.

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 20, 2026

@copilot can you review the proposed fix and perhaps conclude why or how we could end up with different estimated gas values then when testing locally (looking at our use of getFeeEstimates in Web3Wal...

Looking at getFeeEstimates in Web3Wallet.js, there are several reasons the server ends up with lower estimates than a local environment:


How getFeeEstimates works

const result = await this.web3.eth.getFeeHistory('0x5', 'latest', [10])
const baseFees  = result.baseFeePerGas.map(hex => parseInt(hex, 16))
const rewards   = result.reward.map(r => parseInt(r[0], 16)) // 10th percentile

const latestBaseFee  = baseFees[baseFees.length - 1]
const minPriorityFee = Math.min(...rewards)

return {
  baseFee:     Math.floor(latestBaseFee * 1.1),
  priorityFee: minPriorityFee
}

Why the server consistently gets undervalued results (and locally you don't)

  1. Forno caches eth_feeHistory responses. Forno is a shared public RPC, and it rate-limits/caches fee-history to protect itself. The server hammers forno with every transaction and will very frequently get a cached (stale) response reflecting blocks from several seconds or even a minute ago — when the base fee was lower. A local dev environment hits forno far less often and is more likely to receive a fresh response.

  2. The [10] percentile is already the floor of the fee distribution. The third argument to getFeeHistory requests the 10th-percentile priority-fee reward per block, meaning 90 % of transactions in those blocks actually paid more. This is deliberately conservative but unsuitable for a server that needs reliable inclusion.

  3. Math.min(...rewards) compounds the underestimation. Instead of taking an average or median of the 10th-percentile rewards across the 5 sampled blocks, the code takes the minimum. So the final priorityFee is min(p10_block_n-4, …, p10_block_n) — the absolute lowest tail of tip data. This is what produces values like 200000000 (0.2 gwei) even when the network typically demands ≥ 1 gwei.

  4. Only a 10 % buffer on baseFee instead of the EIP-1559-recommended 2×. The EIP-1559 spec recommends maxFeePerGas = 2 × baseFee + priorityFee so the transaction survives up to 12.5 % base-fee increases per block without being re-priced. Using baseFee × 1.1 means the tx is already priced too low if the base fee increases by more than one block's maximum increment (~12.5 %). Locally the timing between estimation and submission is tighter, so you see fewer failures; the server has more latency to forno.

  5. The original CeloAdminWallet set maxFeePerGas: undefined, which forced normalizeGasPricing to always fall through to whatever forno returned. The configured 0.2 gwei maxPriorityFeePerGas wasn't overridden because the || guard only triggers when the value is falsy — so the server was using forno's stale/low base fee with a hardcoded ultra-low tip, exactly matching what was logged.


What the fix does and what remains

The fix introduces a floor (50 gwei / 1 gwei) so that even when forno returns stale low data, the transaction is submitted at no less than those values and at the live estimate when forno returns higher values. This is the right direction.

The remaining limitation is that 50 gwei is a static floor — if the Celo base fee spikes above 50 gwei the fix has no effect other than preventing worse-than-floor outcomes. The real long-term improvement would be to fix the estimation itself:

  • Raise the percentile reward from [10] to something like [50] or [75].
  • Use mean or max of rewards instead of Math.min.
  • Apply the standard 2 × baseFee + priorityFee formula instead of × 1.1.

@L03TJ3
Copy link
Copy Markdown
Contributor Author

L03TJ3 commented Apr 20, 2026

@copilot locally when running getFeeHistory even within the same minute never produces or sees a maxFeePerGas lower then 50.
I am running the call roughly the same time that transactions are attempted on the server

what does it mean 'it caches' and how often is it being refreshed?

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 20, 2026

@copilot locally when running getFeeHistory even within the same minute never produces or sees a maxFeePerGas lower then 50.
I am running the call roughly the same time that transactions are attempted...

To be precise: there is no server-side cache of fee estimates in our code. Every call to normalizeGasPricing calls getFeeEstimates() fresh against forno.

By "Forno caches" I meant that Forno (as a hosted, load-balanced RPC cluster) may serve a slightly stale eth_feeHistory response from its own infrastructure cache — but this is a few-second delay at most and is not the root cause of the logged 30 gwei values.

The actual root cause was a || short-circuit bug in the old normalizeGasPricing code:

// Old CeloAdminWallet config:
maxFeePerGas: undefined,
maxPriorityFeePerGas: (2e8).toFixed(0)   // "200000000" — 0.2 gwei

// Old normalizeGasPricing:
maxFeePerGas     = maxFeePerGas     !== undefined ? maxFeePerGas     : this.maxFeePerGas
// → maxFeePerGas = undefined (class default was also undefined)
maxPriorityFeePerGas = maxPriorityFeePerGas !== undefined ? maxPriorityFeePerGas : this.maxPriorityFeePerGas
// → maxPriorityFeePerGas = "200000000" (0.2 gwei from config)

// Then:
if (!maxFeeNum || !maxPriorityNum) {           // maxFeeNum=0 → enters block
    maxFeePerGas     = maxFeeNum     || baseFee     // 0 → uses forno's baseFee ✓
    maxPriorityFeePerGas = maxPriorityNum || priorityFee  // 200000000 is truthy → NEVER updated ✗
}

So the priority fee was always the hardcoded 0.2 gwei, and the base fee was whatever forno returned at that moment. The 30 gwei base fee in the logs was genuine — Celo's base fee does dip to that range during low-activity periods. Because you test locally during higher-activity windows and run single transactions rather than the server's continuous throughput, you've simply not hit those low-base-fee windows.

The fix in this PR closes both issues: the priority fee is now updated from forno (with a floor), and the base fee can no longer be lower than the configured floor.

const minPriorityFee = Math.min(...rewards)

return {
baseFee: Math.floor(latestBaseFee * 1.1), // in wei
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. acording to the AI review this is the main problem, and I agree. so this multiplier should increase.
  2. we need to verify the topAdmins is enough
  3. we need to also look at the faucet, are we giving enough? should we change the contract to look at the block gas price? (we do it in the base faucet we have for superfluid campaign)
  4. the floor for celo shouldn't be that high 30 gwei should be fine (ie 5 above the minimum of 25)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants