Contract fails to deliver promised returns, but doesn't lose value
Description
Finding
The README says migration permission can be revoked at any time, but that is not true in Staking.sol: https://github.com/Folks-Finance/folks-staking-contracts/blob/3131a2d46b5afa76f606bf08adfd85452a47e2d8/src/Staking.sol#L77-L82
setMigrationPermit() requires the target address to currently hold MIGRATOR_ROLE. So if a user approves a migrator and that role is later revoked, calling setMigrationPermit(migrator, false) reverts with MigratorNotFound, leaving the old permit stored in migrationPermits.
If the same address receives MIGRATOR_ROLE again later, the old approval becomes usable again and migratePositionsFrom() can be called without any fresh user action.
Impact
Users cannot revoke a previously granted migration permit once the role is removed. The old permit remains onchain. Re-granting MIGRATOR_ROLE makes the stale approval usable again.
Recommendation
Allow setMigrationPermit(migrator, false) even if migrator no longer has MIGRATOR_ROLE.
Proof of Concept
forge test --match-test test_PoC_Info_MigrationPermitReactivatesAfterRoleRegrant -vv