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

Unit Confusion Causes Users to Receive Negligible Payouts (0.000001–0.000005 APT)

Root + Impact

Description

  • Root Cause: The get_random_slice function assigns amounts as raw integers (100–500), but APT uses octas (10^8 per APT). This results in payouts of 100–500 octas (0.000001–0.000005 APT) instead of the intended 100–500 APT.

  • Intended Behavior: Users should receive 100–500 APT (10^10–5×10^10 octas) as advertised in the protocol’s rules.

  • Actual Behavior: Users receive 100–500 octas, 10^8 times smaller than intended, rendering payouts negligible and breaking the protocol’s economic model.

// Root cause in the codebase with @> marks to highlight the relevant section
@> let random_amount = 100 + random_val;
table::add(&mut state.users_claimed_amount, user_addr, random_amount);

Risk

  • Likelihood: Guaranteed

    • Every registration and claim uses raw integers, not scaled to octas.

    • Affects all users consistently.

  • Impact: High

    • Users receive negligible payouts, causing dissatisfaction and financial disputes.

    • Undermines trust and the protocol’s promise of substantial rewards.

Attack Flow

  1. The owner funds the contract with sufficient APT (e.g., 10,000 APT).

  2. A user is registered via register_pizza_lover or get_random_slice, assigned 100–500 units.

  3. The user claims their slice, receiving only 100–500 octas (0.000001–0.000005 APT).

  4. Users complain, as the payout is far below the advertised 100–500 APT.

Proof of Concept

#[test(deployer = @pizza_drop, user = @0x123, framework = @0x1)]
fun test_unit_confusion(deployer: &signer, user: &signer, framework: &signer) acquires State, ModuleData {
use aptos_framework::account;
use aptos_framework::timestamp;
use aptos_framework::aptos_coin;
// Setup
timestamp::set_time_has_started_for_testing(framework);
let (burn_cap, mint_cap) = aptos_coin::initialize_for_test(framework);
account::create_account_for_test(@pizza_drop);
account::create_account_for_test(signer::address_of(user));
init_module(deployer);
// Fund contract
let funding_amount = 100000 * 100_000_000; // 100,000 APT in octas
let deployer_coins = coin::mint<AptosCoin>(funding_amount, &mint_cap);
coin::register<AptosCoin>(deployer);
coin::deposit<AptosCoin>(@pizza_drop, deployer_coins);
fund_pizza_drop(deployer, 10000 * 100_000_000);
// Register and claim
register_pizza_lover(deployer, signer::address_of(user));
claim_pizza_slice(user);
// Verify negligible payout
let user_balance = coin::balance<AptosCoin>(signer::address_of(user));
assert!(user_balance >= 100 && user_balance <= 500, 1); // In octas, not APT
assert!(user_balance < 100 * 100_000_000, 2); // Far less than 100 APT
// Clean up
coin::destroy_burn_cap(burn_cap);
coin::destroy_mint_cap(mint_cap);
}

Recommended Mitigation

- remove this code
+ add this code
+ const OCTAS_PER_APT: u64 = 100_000_000;
- let random_amount = 100 + random_val;
+ let random_amount = (100 + random_val) * OCTAS_PER_APT;
Reasoning: Scaling amounts by 10^8 ensures payouts are in APT as intended. The constant OCTAS_PER_APT clarifies the unit conversion, aligning with Aptos’ coin standard and preventing economic errors.
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.