Skip to content

fix: beneficiary reward share snapshot#210

Open
dongcool wants to merge 2 commits into
mainfrom
fix/beneficiary-reward-share-price
Open

fix: beneficiary reward share snapshot#210
dongcool wants to merge 2 commits into
mainfrom
fix/beneficiary-reward-share-price

Conversation

@dongcool
Copy link
Copy Markdown
Collaborator

@dongcool dongcool commented May 7, 2026

Summary

This PR fixes beneficiary reward distribution to use a stable share-price snapshot during each reward distribution round.

Problem

When staking rewards are distributed to multiple beneficiaries, the previous logic calculated and minted shares one beneficiary at a time using the live total share
supply. Each mint increases total shares and changes the share price used by the next beneficiary, making the result depend on iteration order.

The current single-beneficiary behavior is already live in production and must remain fully compatible.

Fix

Snapshot total_share_amount and total_staked_near_amount before iterating beneficiaries, then use that same snapshot to calculate every beneficiary mint in the
round.

This keeps the existing single-beneficiary formula unchanged while preventing future multi-beneficiary order-dependent distribution.

Testing

CI runs the full test suite.

Summary by CodeRabbit

  • Bug Fixes

    • Improved staking rewards distribution to calculate all beneficiary rewards using a single contract state snapshot, ensuring fair and consistent reward allocation.
  • Tests

    • Added verification tests for reward share calculations across single and multiple beneficiary scenarios.

Review Change Stack

@linguists linguists changed the title fix beneficiary reward share snapshot fix: beneficiary reward share snapshot May 11, 2026
@linguists
Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 82285824-07d9-492e-b08e-48a8b1ef1b2c

📥 Commits

Reviewing files that changed from the base of the PR and between 7620e4e and 6f400b8.

📒 Files selected for processing (1)
  • contracts/linear/src/internal.rs

📝 Walkthrough

Walkthrough

This PR refactors staking rewards distribution to ensure deterministic pricing. The distribution function now snapshots total share and stake amounts once before distributing to beneficiaries, computes reward shares from that snapshot for each beneficiary, and mints via a shares-based helper instead of recalculating prices per iteration.

Changes

Deterministic Price Snapshot for Rewards

Layer / File(s) Summary
Share Quote Refactoring with Explicit Totals
contracts/linear/src/internal.rs
num_shares_from_staked_amount_rounded_down delegates to a new internal "with totals" variant that accepts explicit total_share_amount and total_staked_near_amount, centralizing require-checks and arithmetic.
Shares-Based Reward Minting Helper
contracts/linear/src/internal.rs
New internal_mint_beneficiary_reward_shares(account_id, shares) helper mints LiNEAR tokens from precomputed share amounts, replacing the prior NEAR-based helper that recalculated shares internally.
Rewards Distribution with Single Snapshot
contracts/linear/src/internal.rs
internal_distribute_staking_rewards snapshots total stake and share amounts once before the loop, computes each beneficiary's reward shares from that snapshot, and mints via the shares-based helper.
Unit Tests for Snapshot Behavior
contracts/linear/src/internal.rs
Two unit tests verify that single-beneficiary reward shares match the existing formula and that multiple beneficiaries receive shares computed from the same price snapshot per distribution call.

🎯 2 (Simple) | ⏱️ ~12 minutes

A snapshot frozen in time,
no prices dance between the tasks—
each share-mint aligned. 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: beneficiary reward share snapshot' directly and clearly summarizes the main change: introducing a snapshot-based approach to compute beneficiary reward shares, fixing order-dependent behavior.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/beneficiary-reward-share-price

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

let total_staked_near_amount = self.total_staked_near_amount;
for (account_id, bps) in hashmap.iter() {
let reward_near_amount: Balance = bps_mul(rewards, *bps);
let shares = Self::num_shares_from_staked_amount_rounded_down_with_totals(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We'd better add comments about why the change is needed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

@linear-protocol linear-protocol deleted a comment from danielwpz May 11, 2026
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.

2 participants