Skip to content

farming-pool: get_admin panics on unwrap if contract is not initialized #34

Description

@prodbycorne

Problem

Several private helpers call unwrap() on storage reads that have no fallback:

fn get_admin(env: &Env) -> Address {
    env.storage().instance().get(&DataKey::Admin).unwrap()  // panics if uninitialized
}

fn get_stake_token(env: &Env) -> Address {
    env.storage().instance().get(&DataKey::StakeToken).unwrap()  // panics if uninitialized
}

If any public function (e.g. stake, lock_assets, pause) is called before initialize, the contract panics with an opaque XDR host error instead of returning a typed PoolError::NotInitialized.

This also means any function that calls get_admin or get_stake_token internally has an implicit panic path that is not visible in the function signature.

Impact

  • Denial of service: a misconfigured deployment (where init is not called — see issue farming-pool: create_pool deploys contract but never calls initialize #11) causes every subsequent call to panic, and there is no recovery without redeploying
  • Poor debuggability: host panics produce opaque error codes; PoolError::NotInitialized produces a readable, matchable error

Fix

Add an initialization guard function and replace all unwrap() in production paths:

fn require_initialized(env: &Env) -> Result<(), PoolError> {
    if !env.storage().instance().has(&DataKey::Admin) {
        return Err(PoolError::NotInitialized);
    }
    Ok(())
}

fn get_admin(env: &Env) -> Result<Address, PoolError> {
    env.storage().instance().get(&DataKey::Admin)
        .ok_or(PoolError::NotInitialized)
}

All public functions should call require_initialized(&env)? as the first line (after auth where applicable).

Acceptance Criteria

  • require_initialized guard added
  • get_admin and get_stake_token return Result, not T
  • Every public function calls require_initialized before any logic
  • Test: calling stake on uninitialized contract returns Err(PoolError::NotInitialized)
  • Test: calling pause on uninitialized contract returns Err(PoolError::NotInitialized)
  • No unwrap() in any non-test code path

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignbugSomething isn't workingfarming-poolFarmingPool contractsecuritySecurity vulnerability or hardening

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions