Token Vesting

The contract doesn't have the ability to revoke, but you can add it via inheritance. Here's some untested code that can work as a start:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/finance/VestingWallet.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

contract RevocableVestingWallet is VestingWallet, Ownable {
    uint256 returned;
    mapping (address => uint256) erc20Returned;

    constructor(address beneficiaryAddress, uint64 startTimestamp, uint64 durationSeconds)
        VestingWallet(beneficiaryAddress, startTimestamp, durationSeconds)
    {}

    function revoke() public onlyOwner {
        uint256 balance = address(this).balance;
        uint256 returnable = balance - releasable();
        Address.sendValue(payable(msg.sender), returnable);
        returned += returnable;
    }

    function revoke(address token) public onlyOwner {
        uint256 balance = IERC20(token).balanceOf(address(this));
        uint256 returnable = balance - releasable(token);
        SafeERC20.safeTransfer(IERC20(token), msg.sender, returnable);
        erc20Returned[token] += returnable;
    }

    function released() public view override returns (uint256) {
        return super.released() + returned;
    }

    function released(address token) public view override returns (uint256) {
        return super.released(token) + erc20Returned[token];
    }
}

The one downside here is that through the released getters it will appear as though the funds returned to the owner have been released. I could not find a way around this.

Is there a math formula to prove how linear vesting work and how it became simplified? Would love to know more about it