EIP-1559 Fee Market (base fee = AIMD) TODO
Concept
EIP-1559 splits the block fee into a base fee set by the protocol and a priority fee added by the user; the base fee is burned, while only the priority fee goes to the block proposer. The base fee is adjusted by comparing the previous block's gas usage to a target (half of the block gas limit): it rises when usage exceeds the target and falls when usage is below it, with the change per block capped at 1/8, i.e., 12.5%. This feedback loop functions like an AIMD-style congestion controller, designed to converge around the target utilization. From the user's side, the actual amount paid is base fee + priority fee, capped at the max fee, with any excess refunded — this reduces the overbidding incentive that first-price auctions used to create. However, because the adjustment speed is capped, when demand shifts sharply the base fee can only catch up over several blocks, so during short spikes priority-fee competition still drives the price.
If you don't know the base fee's maximum rate of change when writing gas-estimation logic or transaction resubmission policy, you'll either set the max fee too low and get stuck pending, or set it needlessly high.
Code & Formula
# EIP-1559 수수료시장(base fee = AIMD) — 목표 가스 사용량 대비 초과/부족에 따라
# base fee 를 최대 ±12.5%/블록으로 조정하는 AIMD 컨트롤러를 재현한다.
GAS_LIMIT = 30_000_000
TARGET = GAS_LIMIT // 2 # 목표 사용량 = 가스 한도의 절반
MAX_CHANGE_DENOM = 8 # 블록당 최대 변화폭 = 1/8 (12.5%)
def next_base_fee(base_fee: float, gas_used: int) -> float:
if gas_used == TARGET:
return base_fee
delta = base_fee * abs(gas_used - TARGET) // TARGET // MAX_CHANGE_DENOM
delta = max(delta, 1) # 스펙상 최소 1 wei는 움직인다
if gas_used > TARGET:
return base_fee + delta # 혼잡 → 인상
return max(base_fee - delta, 0) # 여유 → 인하 (0 미만 방지)
# 블록별 실제 가스 사용량 시나리오: 혼잡 → 완화 → 정확히 목표
gas_used_per_block = [30_000_000, 30_000_000, 20_000_000, 10_000_000, 15_000_000, TARGET]
base_fee = 10 ** 9 # 1 gwei
print(f"target gas = {TARGET:,}, initial base fee = {base_fee:,} wei")
for i, used in enumerate(gas_used_per_block, start=1):
new_fee = next_base_fee(base_fee, used)
change_pct = (new_fee - base_fee) / base_fee * 100
print(f"block {i}: gasUsed={used:>10,} base_fee {base_fee:>12,} -> {new_fee:>12,} wei ({change_pct:+.2f}%)")
base_fee = new_fee
print(f"\n최종 base fee: {base_fee:,} wei — 목표 사용량에서는 그대로 유지됨을 확인")
Exercise
Take the base fee and gasUsed from the last few hundred blocks, reproduce the adjustment formula yourself to predict the next block's base fee, and compare it against the actual value.
Practical Connection
In a system like Verex where settlement or oracle resolution clusters around specific moments, you need to budget a max-fee buffer (e.g., the equivalent of several blocks' worth of increases) that accounts for the base fee's cap on its rate of increase, so settlement transactions don't stall.
Where it lands in Jayverse
- Wallet: implement transaction resubmission using the 12.5%-per-block cap explicitly — bump max fee by compounding 12.5% over N blocks in the simulate-before-sign flow, rather than an arbitrary multiplier.
- Verex: for settlement or oracle-resolution transactions clustered at known times, size the max-fee buffer directly from the AIMD cap — predict the worst case of several consecutive 12.5% increases instead of a flat safety margin.
- Devnet: add a config/test mode that replays base-fee changes with the real EIP-1559 formula, since a plain Anvil fork doesn't reproduce real base-fee volatility, so gas-estimation logic can be tested against worst-case sequences.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| capped at | ~로 상한이 걸리다 · 변화폭이나 값이 특정 한도를 못 넘게 제한될 때. "the change per block capped at 1/8" |
| converge around | ~주변으로 수렴하다 · 값이 시간이 지나며 목표치 근처로 모여들 때. "designed to converge around the target utilization" |
| overbidding incentive | 과도하게 입찰하려는 유인 · 경매에서 실제보다 높게 부르게 만드는 동기. "reduces the overbidding incentive" |
| catch up | (뒤처진 것을) 따라잡다 · 값이 실제 상황을 몇 단계 뒤늦게 뒤쫓아갈 때. "the base fee can only catch up over several blocks" |
| stuck pending | (트랜잭션이) 대기 상태로 멈춰 있다 · 처리되지 못하고 계속 걸려 있을 때. "get stuck pending" |
| needlessly high | 불필요하게 높은 · 과하게 여유를 둬서 낭비가 될 때. "set it needlessly high" |
| budget a buffer | 여유분을 미리 확보해두다 · 예상치 못한 변동에 대비해 여지를 남겨둘 때. "budget a max-fee buffer" |
| EIP-1559 | 이더리움 개선안 1559(Ethereum Improvement Proposal 1559) · 베이스피 소각과 우선순위 수수료를 분리한 수수료 시장 표준. "EIP-1559 splits the block fee into a base fee" |
| AIMD | 가산증가 승산감소(Additive Increase Multiplicative Decrease) · TCP 혼잡제어에서 쓰이는 피드백 방식, 베이스피 조정 로직이 이 형태를 따름. "functions like an AIMD-style congestion controller" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/math-50-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.