Contract fails to deliver promised returns, but doesn't lose value
Description
Description
Brief/Intro
When users mint XALGO, they can use "immediate_mint" or "delayed_mint" by sending ALGO to the consensus contract. Then the consensus will distribute the ALGO to all Proposers almost evenly.
The register_admin or proposer_admin can register the proposer to be offline by calling "register_offline" function.
The vulnerability
Vulnerability Details
When distributing the ALGO, the consensus contract does not check if the proposer is offline, but still distributes the ALGO evenly. So if in case, that the register_admin or proposer_admin register the proposer to be offline, then the proposer status is offline, then the proposer will not earn any reward. By still distributing the ALGO to offline proposers, this will cause losing of the reward, because the user's capital is not used for active proposers.
So if the offline period and number of offline proposers is high enough, then this will significantly impact users' interest.
Impacts
About the severity assessment
Bug Severity: Low
Impact category:
Contract fails to deliver promised returns, but doesn't lose value
Likelyhood: Very Likely
Recommendation: Implement the status tracking of proposer status and prioritize ALGO distribution for online proposers to maximize the reward earning.
Proof of Concept
Proof of concept
Steps to reproduce the bug:
Step 1: The register_admin or proposer_admin can register the proposer to be offline by calling "register_offline" function.
Step 2: User call "immediate_mint" to mint the XALGO. The ALGO received is distributed for offline proposers.
Test code:
I modify the test case "succeeds and splits between proposers" in algo-liquid-staking-contracts\test\xAlgoConsensusV2.test.ts and add the code to register_offline
immediate mint ✓ succeeds and splits between proposers (1320 ms)
Explanation:
The test code first register proposer_0 offline.
But when user call "immediate_mint" the contract still distributes the ALGO to node proposer_0.
Full log for reference:
npm run test > test_all_241216_1400.log(node:15045) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time(Use `node --trace-warnings ...` to show where the warning was created)PASS test/xAlgoConsensusV2.test.ts (84.908 s) Algo Consensus V2 creation ✓ succeeds in updating from x algo consensus v1 to x algo consensus v2 (9331 ms) initialise ✓ succeeds for admin (67 ms) ✓ fails when already setup (39 ms) Update admin ✓ fails for invalid admin type (37 ms) ✓ admins can update admins (250 ms) ✓ non-admin cannot update admins (236 ms) add proposer ✓ fails for non register admin (177 ms) ✓ fails if proposer is not rekeyed (1064 ms) ✓ fails when proposer has already been added (37 ms) ✓ succeeds for register admin for second proposer (283 ms) update max proposer ✓ fails for non-admin (41 ms) ✓ succeeds for admin (81 ms) update premium ✓ fails for non-admin (37 ms) ✓ fails when premium is greater than 1% (38 ms) ✓ succeeds for admin (77 ms) pause minting ✓ fails for non-admin (37 ms) ✓ fails for invalid minting type (34 ms) ✓ succeeds for admin (196 ms) set proposer admin ✓ succeeds for register admin (1112 ms) ✓ fails for pending proposer admin (38 ms) ✓ succeeds for proposer admin (175 ms) ✓ fails for non register or proposer admin (157 ms) ✓ fails when proposer does not exist (38 ms) register online ✓ fails for non proposer admin (213 ms) ✓ fails when you don't send algo (138 ms) ✓ fails when proposer does not exist (1124 ms) ✓ succeeds for proposer admin (73 ms) register offline ✓ fails for non register admin (76 ms) ✓ fails when proposer does not exist (47 ms) ✓ succeeds for register and proposer admin (104 ms) subscribe to xgov ✓ fails for non xgov admin (145 ms) ✓ fails when proposer does not exist (67 ms) ✓ fails when don't send xgov fee (289 ms) ✓ succeeds for xgov admin (84 ms) unsubscribe from xgov ✓ fails for non xgov admin (1120 ms) ✓ fails when proposer does not exist (37 ms) ✓ succeeds for xgov admin (40 ms) immediate mint ✓ fails when immediate mint is paused (161 ms) ✓ fails when you don't send algo (158 ms) ✓ fails when proposer max balance is exceeded (111 ms) ✓ fails when you receive less x algo than min received specified (111 ms) ✓ succeeds and allocates to lowest balance proposer (198 ms) ✓ succeeds and splits between proposers (1320 ms) delayed mint ✓ fails when delay mint is paused (147 ms) ✓ fails when you don't send algo (131 ms) ✓ fails when proposer max balance is exceeded (101 ms) ✓ fails when nonce is not 2 bytes (65 ms) ✓ succeeds (1182 ms) ✓ fails when box is already used (125 ms) claim delayed mint ✓ fails when nonce is not 2 bytes (41 ms) ✓ fails when box does not exist (67 ms) ✓ fails when 320 rounds hasn't passed (69 ms) ✓ succeeds (26546 ms) burn ✓ fails when you don't send x algo (110 ms) ✓ fails when you receive less algo than min received specified (108 ms) ✓ succeeds and allocates from highest balance proposer (186 ms) ✓ succeeds and splits between proposers (1295 ms) update fee ✓ fails for non-admin (38 ms) ✓ fails when fee is greater than 100% (38 ms) ✓ succeeds for admin (280 ms) claim fee ✓ succeeds (211 ms) update smart contract ✓ fails in smart contract update when nothing scheduled (1338 ms) ✓ succeeds in scheduling update (645 ms) ✓ succeeds in overriding and scheduling update (1620 ms) ✓ fails in scheduling update when not admin (634 ms) ✓ fails in smart contract update when not past scheduled timestamp (1496 ms) ✓ fails in smart contract update when not admin (617 ms) ✓ succeeds in smart contract update (1351 ms)Test Suites: 1 passed, 1 totalTests: 68 passed, 68 totalSnapshots: 0 totalTime: 85.494 sRan all test suites.