Skip to content

[Contract] Implement Staking Rewards Decay Rate Calculation with Epoch Snapshots (#637) - #742

Open
iexwr wants to merge 2 commits into
SoroLabs:mainfrom
iexwr:feature/issue-79-staking-decay
Open

[Contract] Implement Staking Rewards Decay Rate Calculation with Epoch Snapshots (#637)#742
iexwr wants to merge 2 commits into
SoroLabs:mainfrom
iexwr:feature/issue-79-staking-decay

Conversation

@iexwr

@iexwr iexwr commented Jul 29, 2026

Copy link
Copy Markdown

Closes #637

Summary

Replaces the previous continuous per-block decay model with an epoch snapshot system. The reward emission rate is constant within each epoch and decays by a configured percentage at epoch boundaries, providing predictable per-epoch rates and reducing computational overhead.

Changes

StakingConfig

  • Replaced decay_rate with epoch_decay_percent: Fixed (percentage reduction per epoch)
  • Added epoch_length: u32 (blocks per epoch)

New: EpochSnapshot storage

  • Each epoch stores its rate and start_block on-chain
  • Snapshots are created lazily on first access via ensure_epoch_snapshots
  • initialize creates epoch 0 snapshot at deployment

Reward calculation

  • calculate_multiplier iterates over epochs between t1 and t2
  • Within each epoch, rate is constant: rate = initial_rate * (1 - epoch_decay_percent)^epoch
  • Compounding uses exp(rate * blocks_in_epoch) per epoch
  • Eliminates large-exponent fixed_pow_int calls previously needed for continuous decay

Bug fixes

  • Fixed withdraw() not persisting total_staked update (pre-existing)
  • Added total_staked tracking to stake() (was missing, pre-existing)

Testing

cargo test --package soroban-staking-rewards

All 12 tests pass:

Test What it verifies
test_initialization Config stored with new fields
test_stake_and_yield_accumulation_no_decay Zero decay = constant rate across epochs
test_stake_and_yield_accumulation_with_decay Rewards within epoch 0
test_epoch_boundary_decay Rate drops at epoch boundary
test_epoch_snapshot_storage Snapshots stored correctly for epochs 0-2
test_compounding_interest Rewards compound on stake + accrued
test_zero_stake_security Zero stake stops compounding
test_multi_epoch_accumulation Rewards across 10 epochs
test_emergency_withdraw Principal recovery while paused
test_pause_safeguards_stake Stake blocked when paused
test_pause_safeguards_withdraw Withdraw blocked when paused
test_pause_safeguards_claim Claim blocked when paused

iexwr and others added 2 commits July 29, 2026 01:32
…ission rate (SoroLabs#637)

Replace continuous per-block decay with epoch-based decay using
on-chain snapshots.

Changes:
- StakingConfig: replace decay_rate with epoch_decay_percent + epoch_length
- New EpochSnapshot struct stored per epoch (rate, start_block)
- ensure_epoch_snapshots lazily creates snapshots up to current block
- calculate_multiplier uses epoch-based rate (constant within epoch)
- initialize creates epoch 0 snapshot at deployment
- Fixed pre-existing bug: total_staked not updated in withdraw()
- Fixed pre-existing bug: total_staked not tracked in stake()
- 12 tests: all passing, including epoch_boundary_decay,
  epoch_snapshot_storage, multi_epoch_accumulation
- Updated README with epoch snapshot documentation
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@iexwr Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@iexwr

iexwr commented Jul 30, 2026

Copy link
Copy Markdown
Author

@EDOHWARES Hello

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.

[Contract] Implement Staking Rewards Decay Rate Calculation with Epoch Snapshots

1 participant