Beginner FriendlyGameFi
100 EXP
View results
Submission Details
Severity: high
Valid

Mismatch Between Documentation and Implementation Causes Users to Receive 0.000001–0.000005 APT Instead of 100–500 APT

Root + Impact

Description

  • The contract pizza_drop::airdrop is designed to randomly assign each registered pizza lover between 100–500 APT as per the project documentation and inline comments.

  • However, in the implementation of get_random_slice, the code calculates the reward without converting to Octas (the base unit of Aptos, where 1 APT = 10^8 Octas).

  • This means that instead of receiving 100–500 APT, users actually only receive 100–500 Octas (≈ 0.000001–0.000005 APT).

#[randomness]
entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
let time = timestamp::now_microseconds();
let random_val = time % 401;
let random_amount = 100 + random_val; // 100-500 APT (in Octas: 10^8 smallest unit)
table::add(&mut state.users_claimed_amount, user_addr, random_amount);
}

Risk

Likelihood:

  • Certain (the bug is present in all executions of get_random_slice).

Impact:

  • Severe underpayment: Users expect 100–500 APT but receive only micro-APT fractions.

  • Loss of trust: Creates a material discrepancy between the system’s advertised functionality and its actual behavior.

  • Financial Loss: If undetected, users may claim negligible amounts, leaving the majority of the funded APT unclaimed as there is no function to withdraw the unclaimed rewards to contract owner.

Proof of Concept

Assume timestamp::now_microseconds() returns 123456789, so random_val = 123456789 % 401 = 89.
Code: random_amount = 100 + 89 = 189 octas (0.00000189 APT).
Expected (per docs): 189 * 10^8 octas (189 APT).
Result: User receives 189 octas, which is 10^8 times smaller than intended.

Recommended Mitigation

#[randomness]
entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
let time = timestamp::now_microseconds();
let random_val = time % 401;
- let random_amount = 100 + random_val; // 100-500 APT (in Octas: 10^8 smallest unit)
+ let random_amount = (100 + random_val) * 100_000_000; // 100–500 APT, stored as octas (1 APT = 10^8 octas)
table::add(&mut state.users_claimed_amount, user_addr, random_amount);
}
Updates

Appeal created

bube Lead Judge 9 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect APT value

Support

FAQs

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