One Shot: Reloaded

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

Battles accept zero-value bets

Author Revealed upon completion

Logic Flaw

Description

  • Normal behavior:

    • Players should risk a positive amount of CRED when entering the arena.

    • Both defender and challenger should deposit matching stakes to form a prize pool.

  • Actual behavior:

    • The function rap_battle::go_on_stage_or_battle does not validate bet_amount > 0.

    • As a result, players can initiate and complete battles with bet = 0, creating battles with no economic value.

// rap_battle.move
if (arena.defender == @0x0) {
@> arena.defender_bet = bet_amount; // can be 0
let first_bet = coin::withdraw<cred_token::CRED>(player, bet_amount);
coin::merge(&mut arena.prize_pool, first_bet);
...
}
// @> No check for bet_amount > 0

Risk

Likelihood:

  • High: every player can call with bet_amount = 0.

  • No conditions prevent this; it will always succeed.

Impact:

  • No funds are lost.

  • However, battles become meaningless (zero reward, still cost gas).

  • Players may farm battle stats (wins) without economic risk.

  • Undermines the credibility of CRED tokenomics.

Proof of Concept

#[test(battle_addr = @0x42, alice = @0xa11ce)]
public fun test_defender_can_bet_zero(battle_addr: &signer, alice: &signer) {
rap_battle::test_init(battle_addr);
let (alice_obj, _) =
one_shot::test_mint_to_player_and_return_object(battle_addr, alice);
// Bug: Defender can enter arena with bet_amount = 0
rap_battle::go_on_stage_or_battle(alice, alice_obj, 0);
// Test passes: zero bet accepted without abort.
}

Note: This issue is independent of the arena initialization bug. Even if the BattleArena resource is properly initialized, the function still accepts bet_amount = 0, which breaks economic logic.

Test confirms: battle accepts bet_amount = 0.

Running Move unit tests
[ PASS ] 0x42::bet_validation_poc::test_defender_can_bet_zero
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
"Result": "Success"
}

Recommended Mitigation

Add explicit validation that bets must be strictly positive:

public entry fun go_on_stage_or_battle(
player: &signer,
rapper_token: Object<Token>,
bet_amount: u64
) acquires BattleArena {
+ assert!(bet_amount > 0, E_INVALID_BET);
...
}

Support

FAQs

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