In ArcToken::distributeYield, the yield distribution mechanism has a logical flaw which causes dust accumulation of yieldTokens in the contract. There is no function to withdraw these dust yield tokens.
Vulnerability Details
distributeYield() uses a "last holder gets remainder" approach to handle rounding errors, but fails to account for cases where the last holder is yield-restricted (e.g., blacklisted from receiving yields).
The last holder is intended to receive lastShare = amount - distributedSum to ensure complete distribution without dust.
If the last holder is not allowed to receive yield, this lastShare remains in the contract.
There is no function to withdraw accumulated yieldTokens from the contract.
Distribution cycles use only the input amount parameter and never the contract's existing balance of yieldTokens, so each cycle compounds the problem and increases dust.
Impact Details
Not all yield is distributed to holders; some yield becomes stuck in the contract.
Over time, the dust amount increases with each distribution cycle.
Without a recovery mechanism, these funds remain stuck.
High-severity: Funds (yieldTokens) become permanently stuck in the contract if recipients are skipped (e.g., yield-restricted). This leads to progressively increasing undistributed yield.
Proof of Concept
Test reproducing dust accumulation (expand to view)
Notes / Remediation Ideas
Ensure the "remainder to last holder" logic only applies to eligible yield recipients; if the intended last recipient is ineligible, select the last eligible recipient or redistribute the remainder.
Alternatively, change distribution logic to consider the contract's existing yieldToken balance (aggregate available yield) and handle rounding such that no tokens are left undistributable.
Provide an admin recovery function to withdraw or redistribute dust balances (with appropriate access controls and auditing).