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
-
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?
-
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?
-
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.
-
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.
Summary
8 V3 INVOKE transactions on mainnet charged 1,270–2,240 STRK in gas fees each, while the signed
resource_boundscap 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
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
A normal transfer TX in the same session (`0xd75f2a...`, block 7654775) had a fee of 0.028 STRK — consistent with resource bounds.
Questions
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?
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?
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.
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.