Beginner FriendlyGameFi
100 EXP
View results
Submission Details
Impact: low
Likelihood: high
Invalid

Missing Input Validation

Root + Impact

Description

  • The contract should validate all input parameters to prevent waste of gas fees and ensure proper function behavior.

  • Several functions lack basic input validation, allowing operations with invalid or zero values that waste gas and could cause confusion.

public entry fun fund_pizza_drop(owner: &signer, amount: u64) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
assert!(signer::address_of(owner) == state.owner, E_NOT_OWNER);
let resource_addr = get_resource_address();
coin::transfer<AptosCoin>(owner, resource_addr, amount); // @> No check if amount > 0
state.balance = state.balance + amount;
}
public entry fun register_pizza_lover(owner: &signer, user: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
assert!(signer::address_of(owner) == state.owner, E_NOT_OWNER);
get_random_slice(user); // @> No validation of user address
event::emit(PizzaLoverRegistered {
user: user,
});
}

Risk

Likelihood:

  • Users can accidentally call functions with zero amounts or invalid parameters

  • No validation means these calls will succeed but accomplish nothing useful

  • Common user error when interacting with smart contracts

Impact

Impact:

  • Waste of gas fees for meaningless transactions

  • Confusion in event logs with zero-value operations

  • Potential for accidental operations that don't achieve intended results

  • Poor user experience due to lack of clear error messages

Proof of Concept

#[test]
fun test_zero_amount_funding() acquires ModuleData, State {
// Setup contract
init_module(deployer);
let initial_balance = get_pizza_pool_balance();
// Fund with zero amount - should be prevented but isn't
fund_pizza_drop(deployer, 0);
let final_balance = get_pizza_pool_balance();
// Balance doesn't change, but gas was wasted
assert!(initial_balance == final_balance, 1);
// Transaction succeeded but accomplished nothing
}
#[test]
fun test_invalid_address_operations() acquires ModuleData, State {
// Setup contract
init_module(deployer);
// These should be prevented but currently succeed
register_pizza_lover(deployer, @0x0); // Zero address
// User can even "claim" with zero address (though it would fail at coin operations)
assert!(is_registered(@0x0), 1);
}

Recommended Mitigation

public entry fun fund_pizza_drop(owner: &signer, amount: u64) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
assert!(signer::address_of(owner) == state.owner, E_NOT_OWNER);
+
+ // Validate funding amount
+ assert!(amount > 0, E_INVALID_AMOUNT);
+
+ // Optional: Set reasonable limits
+ assert!(amount <= MAX_FUNDING_AMOUNT, E_AMOUNT_TOO_LARGE);
let resource_addr = get_resource_address();
coin::transfer<AptosCoin>(owner, resource_addr, amount);
state.balance = state.balance + amount;
}
public entry fun register_pizza_lover(owner: &signer, user: address) acquires ModuleData, State {
let state = borrow_global_mut<State>(get_resource_address());
assert!(signer::address_of(owner) == state.owner, E_NOT_OWNER);
+
+ // Validate user address
+ assert!(user != @0x0, E_INVALID_ADDRESS);
+ assert!(user != @0x1, E_INVALID_ADDRESS); // Avoid system addresses
+
+ // Check if already registered
+ assert!(!table::contains(&state.users_claimed_amount, user), E_ALREADY_REGISTERED);
get_random_slice(user);
event::emit(PizzaLoverRegistered {
user: user,
});
}
+ // Add input validation helper functions
+ fun validate_address(addr: address) {
+ assert!(addr != @0x0, E_INVALID_ADDRESS);
+ assert!(addr != @0x1, E_INVALID_ADDRESS);
+ assert!(addr != @0x2, E_INVALID_ADDRESS);
+ assert!(addr != @0x3, E_INVALID_ADDRESS);
+ }
+ fun validate_amount(amount: u64, min_amount: u64, max_amount: u64) {
+ assert!(amount >= min_amount, E_AMOUNT_TOO_SMALL);
+ assert!(amount <= max_amount, E_AMOUNT_TOO_LARGE);
+ }
+ // Add constants for validation
+ const MIN_FUNDING_AMOUNT: u64 = 1;
+ const MAX_FUNDING_AMOUNT: u64 = 1000000000000; // 10,000 APT in Octas
+ const MIN_SLICE_AMOUNT: u64 = 100;
+ const MAX_SLICE_AMOUNT: u64 = 500;
+ // Enhanced funding function with comprehensive validation
+ public entry fun fund_pizza_drop_v2(owner: &signer, amount: u64) acquires ModuleData, State {
+ let state = borrow_global_mut<State>(get_resource_address());
+ assert!(signer::address_of(owner) == state.owner, E_NOT_OWNER);
+
+ // Comprehensive amount validation
+ validate_amount(amount, MIN_FUNDING_AMOUNT, MAX_FUNDING_AMOUNT);
+
+ // Check owner has sufficient balance
+ let owner_balance = coin::balance<AptosCoin>(signer::address_of(owner));
+ assert!(owner_balance >= amount, E_INSUFFICIENT_OWNER_BALANCE);
+
+ let resource_addr = get_resource_address();
+ coin::transfer<AptosCoin>(owner, resource_addr, amount);
+ state.balance = state.balance + amount;
+
+ event::emit(PizzaDropFunded {
+ owner: signer::address_of(owner),
+ amount: amount,
+ new_balance: state.balance,
+ });
+ }
+ // Add parameter validation to view functions
+ #[view]
+ public fun get_claimed_amount(user: address): u64 acquires ModuleData, State {
+ validate_address(user);
+
+ let state = borrow_global<State>(get_resource_address());
+ if (!table::contains(&state.users_claimed_amount, user)) {
+ return 0
+ };
+ let amount = table::borrow(&state.users_claimed_amount, user);
+ *amount
+ }
+ // Add new events
+ #[event]
+ struct PizzaDropFunded has drop, store {
+ owner: address,
+ amount: u64,
+ new_balance: u64,
+ }
+ // Add new error codes
+ const E_INVALID_AMOUNT: u64 = 12;
+ const E_AMOUNT_TOO_SMALL: u64 = 13;
+ const E_AMOUNT_TOO_LARGE: u64 = 14;
+ const E_INVALID_ADDRESS: u64 = 15;
+ const E_INSUFFICIENT_OWNER_BALANCE: u64 = 16;
Updates

Appeal created

bube Lead Judge 10 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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