Skip to content

V3 actual_fee exceeds resource_bounds by 3644x — 15,518 STRK lost #1597

@ttendoscopie-creator

Description

@ttendoscopie-creator

Summary

8 V3 INVOKE transactions on mainnet charged 1,270–2,240 STRK in gas fees each, while the signed resource_bounds cap the maximum fee at ~0.506 STRK. This represents a 3,644x violation of the resource bounds ceiling. Total loss: ~15,518 STRK.

According to Starknet fee docs, the ZK proof enforces that the sequencer cannot charge more than max_amount × max_price_per_unit. This enforcement appears to have failed.

Environment

  • starknet.js: 8.9.2
  • Network: Starknet Mainnet, version 0.14.1
  • Block range: 7654710 — 7654901
  • Date: 2026-03-12
  • Account: Braavos `0x07dfa610d64cff230d00e1c64dc648465bfcf4c74b4c5e0541613af0873869f5`
  • @avnu/avnu-sdk: 4.0.1

How execute() was called

```typescript
const feeEstimate = await account.estimateInvokeFee(swapCalls);
// ... fee validation ...
const result = await account.execute(swapCalls, { tip });
// ↑ No resourceBounds passed — starknet.js auto-estimates internally
```

Key issue: `resourceBounds` was NOT passed to `execute()`, so starknet.js re-estimated internally. The question is: did the internal re-estimation produce much higher bounds than the 0.506 STRK shown by `getTransactionByHash`?

Reproduction TX

TX hash: `0x3b8da656f920607a8b529f204e15037c877c74c727defc93890fdab292695bc`

Signed resource bounds (from `starknet_getTransactionByHash`)

```
l2_gas: max_amount=0xdffea8 (14,679,720) max_price=0x8085c3900 (34.5 gwei) → max 0.506 STRK
l1_data_gas: max_amount=0x4b0 (1,200) max_price=0x5079c49f0 → max 0.000026 STRK
l1_gas: max_amount=0x0
tip: 0xb5e620f48000 = 0.0002 STRK

TOTAL MAX POSSIBLE FEE: 0.506676 STRK
```

Actual fee (from `starknet_getTransactionReceipt`)

```
actual_fee: 0x640f31aa1835efe060 = 1,845.769251 STRK (unit: FRI)
Ratio: 3,644x the resource bounds
```

Execution resources consumed

```
l2_gas: 9,227,785 units
l1_data_gas: 800 units
Expected fee at block gas prices: 0.212 STRK
```

On-chain balance verification

```
Block 7654709 (before): 10,233.995 STRK
Block 7654710 (after): 8,378.226 STRK
Change: -1,855.769 STRK (= 10 STRK swap + 1,845.77 fee)
```

The last Transfer event in the receipt confirms 1,845.77 STRK sent from account to sequencer address `0x1176a1bd84...`.

All affected transactions

# TX Hash Block Fee (STRK) Bounds Max Ratio
1 `0x3b8da6...` 7654710 1,845.77 0.506 3,644x
2 `0x20db3c...` 7654718 1,893.77 ~0.5 ~3,738x
3 `0x32d6f7...` 7654725 1,893.77 ~0.5 ~3,738x
4 `0x5bfcc4...` 7654802 1,893.77 ~0.5 ~3,738x
5 `0x16693a...` 7654811 2,240.04 ~0.5 ~4,420x
6 `0x1368a2...` 7654885 2,240.04 ~0.5 ~4,420x
7 `0x564530...` 7654893 2,240.04 ~0.5 ~4,420x
8 `0x3b6b33...` 7654901 1,270.61 ~0.5 ~2,508x
Total 15,517.81

A normal transfer TX in the same session (`0xd75f2a...`, block 7654775) had a fee of 0.028 STRK — consistent with resource bounds.

Questions

  1. Are the `resource_bounds` returned by `starknet_getTransactionByHash` guaranteed to match the values actually signed? Or could starknet.js be encoding them differently than the RPC reports? I see there was a prior fix "utilize provided resourceBounds value" (commit 65bea53) — could a similar issue affect auto-estimated bounds in v8.9.2?

  2. When `execute()` is called without `resourceBounds`, how are the internal bounds computed? Is it possible the auto-estimation produces bounds much larger than what `getTransactionByHash` returns?

  3. Does the 50% `feeMarginPercentage` overhead apply to the auto-estimated bounds? Even with 2.25x overhead, 0.506 STRK × 2.25 = 1.14 STRK — still far from 1,845 STRK.

  4. Could this be a Starknet sequencer issue rather than a starknet.js issue? Should this be reported to starkware-libs/sequencer instead?

Workaround applied

Passing the `resourceBounds` from `estimateInvokeFee()` explicitly to `execute()`:

```typescript
const feeEstimate = await account.estimateInvokeFee(swapCalls);
const result = await account.execute(swapCalls, {
tip,
...(feeEstimate.resourceBounds ? { resourceBounds: feeEstimate.resourceBounds } : {}),
});
```

This prevents the double-estimation and ensures the bounds validated by the gas check are the same ones used in the transaction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Context: coupledinteract with some parts of the codebaseDifficulty: intermediatemobilise some notions about the field, but can be learned while doingType: featureNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions