Overview
The factory contract has transfer_admin but the farming-pool contract has no equivalent. Once a pool is deployed, its admin address is immutable. This creates operational risks:
- If the admin key is compromised, there is no recovery path — the pool must be abandoned
- Governance handoffs (e.g., DAO multisig taking over) require redeploying the pool, losing all staker history
- Factory's
transfer_admin sets a precedent that admin rotation is expected, yet pool contracts don't support it
Required Change
Add transfer_admin to FarmingPool, mirroring the factory implementation:
/// Admin: transfer admin rights to . Current admin must authorise.
///
/// Emits a event with .
pub fn transfer_admin(env: Env, new_admin: Address) -> Result<(), PoolError> {
let current = get_admin(&env);
current.require_auth();
bump_instance(&env);
env.storage().instance().set(&DataKey::Admin, &new_admin);
env.events().publish(
(symbol_short!("pool"), symbol_short!("adm_xfr")),
(current, new_admin),
);
Ok(())
}
Also add a get_admin public read function (currently the admin address is only internally accessible):
pub fn admin(env: Env) -> Address {
bump_instance(&env);
get_admin(&env)
}
Acceptance Criteria
Overview
The factory contract has
transfer_adminbut the farming-pool contract has no equivalent. Once a pool is deployed, its admin address is immutable. This creates operational risks:transfer_adminsets a precedent that admin rotation is expected, yet pool contracts don't support itRequired Change
Add
transfer_admintoFarmingPool, mirroring the factory implementation:Also add a
get_adminpublic read function (currently the admin address is only internally accessible):Acceptance Criteria
transfer_adminimplemented on FarmingPooladmin()public getter addedtransfer_adminreturnsErr(PoolError::Unauthorized)adm_xfrevent emitted with old and new adminpause,set_global_multiplier, etc.