Root + Impact
Description
- 
Users should be able to stake multiple Rapper NFTs per address. 
- 
The specific issue is StakeInfo stored at staker_addr without token_id keying, overwriting on multiple stakes and limiting to one implicitly. 
        public entry fun stake(staker: &signer, rapper_token: Object<Token>) {
        let staker_addr = signer::address_of(staker);
        let token_id = object::object_address(&rapper_token);
        move_to(staker, StakeInfo {
            start_time_seconds: timestamp::now_seconds(),
            owner: staker_addr,
        })
        one_shot::transfer_record_only(token_id, staker_addr, @battle_addr);
        object::transfer(staker, rapper_token, @battle_addr);
        event::emit(StakedEvent {
            owner: staker_addr,
            token_id,
            start_time: timestamp::now_seconds(),
        })
    }
Risk
Likelihood: Medium
Impact: Medium
Proof of Concept
#[test(module_owner = @battle_addr, staker = @0x123)]
#[expected_failure] 
fun test_staking_limited_one_per_address(module_owner: &signer, staker: &signer) {
    
    battle_addr::one_shot::init_module(module_owner);
    
    battle_addr::one_shot::mint_rapper(module_owner, signer::address_of(staker));
    battle_addr::one_shot::mint_rapper(module_owner, signer::address_of(staker));
    
    let rapper1 = /* assume */
    battle_addr::streets::stake(staker, rapper1);
    
    let rapper2 = /* assume */
    battle_addr::streets::stake(staker, rapper2);
}
Recommended Mitigation
- struct StakeInfo has key, store { ... } // No token_id
+ struct StakeInfo has key { stakes: table::Table<address, StakeInfoEntry> } // Add table for multi-stake