One Shot: Reloaded

First Flight #47
Beginner FriendlyNFT
100 EXP
Submission Details
Impact: high
Likelihood: high

Stake reward calculation is broken

Author Revealed upon completion

Stake reward calculation is broken

Description

Staking rewards should mint whole CRED token per day and deposit them to the recipient's CoinStore.
However, the current implementation does not take into account the decimals of the token and mints 1 subunit of CRED per day.

Risk

Likelihood: High

This issue affects any user who unstakes.

Impact: High

Stakers receive an unexpected reward breaking incentives and economics.

Proof of Concept

#[test]
public fun test_staking_rewards_calculation () {
let module_owner = account::create_account_for_test(@battle_addr);
let framework = account::create_account_for_test(@0x1);
let recipient = account::create_account_for_test(@0xA);
timestamp::set_time_has_started_for_testing(&framework);
cred_token::initialize_for_test(&module_owner, &framework);
cred_token::register(&recipient);
one_shot::mint_rapper(&module_owner, signer::address_of(&recipient));
let tokens = one_shot::get_tokens();
assert!(vector::length(&tokens) == 1);
let token_address = vector::borrow(&tokens, 0);
let token = object::address_to_object<token::Token>(*token_address);
streets::stake(&recipient, token);
timestamp::fast_forward_seconds(4 * 24 * 60 * 60);
streets::unstake(&recipient, &module_owner, token);
assert!(cred_token::balance_of(signer::address_of(&recipient)) == 4);
}

The test asserts that the current reward calculation distributes 4 CRED subunits for 4 days of staking. Instead, 4 * 10^8 CRED should be minted.

Recommended Mitigation

Convert the amount to main unit by multiplying by 10^8 before calling cred_token::mint.

- if (days_staked >= 1) { cred_token::mint(module_owner, staker_addr, 1); };
- if (days_staked >= 2) { cred_token::mint(module_owner, staker_addr, 1); };
- if (days_staked >= 3) { cred_token::mint(module_owner, staker_addr, 1); };
- if (days_staked >= 4) { cred_token::mint(module_owner, staker_addr, 1); };
+ if (days_staked >= 1) { cred_token::mint(module_owner, staker_addr, 1 * 10 ** 8); };
+ if (days_staked >= 2) { cred_token::mint(module_owner, staker_addr, 1 * 10 ** 8); };
+ if (days_staked >= 3) { cred_token::mint(module_owner, staker_addr, 1 * 10 ** 8); };
+ if (days_staked >= 4) { cred_token::mint(module_owner, staker_addr, 1 * 10 ** 8); };

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.