VestingWallet.sol 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.0;
  3. import "../token/ERC20/utils/SafeERC20.sol";
  4. import "../utils/Address.sol";
  5. import "../utils/Context.sol";
  6. import "../utils/math/Math.sol";
  7. /**
  8. * @title VestingWallet
  9. * @dev This contract handles the vesting of Eth and ERC20 tokens for a given beneficiary. Custody of multiple tokens
  10. * can be given to this contract, which will release the token to the beneficiary following a given vesting schedule.
  11. * The vesting schedule is customizable through the {vestedAmount} function.
  12. *
  13. * Any token transferred to this contract will follow the vesting schedule as if they were locked from the beginning.
  14. * Consequently, if the vesting has already started, any amount of tokens sent to this contract will (at least partly)
  15. * be immediately releasable.
  16. */
  17. contract VestingWallet is Context {
  18. event EtherReleased(uint256 amount);
  19. event ERC20Released(address token, uint256 amount);
  20. uint256 private _released;
  21. mapping(address => uint256) private _erc20Released;
  22. address private immutable _beneficiary;
  23. uint64 private immutable _start;
  24. uint64 private immutable _duration;
  25. /**
  26. * @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet.
  27. */
  28. constructor(
  29. address beneficiaryAddress,
  30. uint64 startTimestamp,
  31. uint64 durationSeconds
  32. ) {
  33. require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address");
  34. _beneficiary = beneficiaryAddress;
  35. _start = startTimestamp;
  36. _duration = durationSeconds;
  37. }
  38. /**
  39. * @dev The contract should be able to receive Eth.
  40. */
  41. receive() external payable virtual {}
  42. /**
  43. * @dev Getter for the beneficiary address.
  44. */
  45. function beneficiary() public view virtual returns (address) {
  46. return _beneficiary;
  47. }
  48. /**
  49. * @dev Getter for the start timestamp.
  50. */
  51. function start() public view virtual returns (uint256) {
  52. return _start;
  53. }
  54. /**
  55. * @dev Getter for the vesting duration.
  56. */
  57. function duration() public view virtual returns (uint256) {
  58. return _duration;
  59. }
  60. /**
  61. * @dev Amount of eth already released
  62. */
  63. function released() public view virtual returns (uint256) {
  64. return _released;
  65. }
  66. /**
  67. * @dev Amount of token already released
  68. */
  69. function released(address token) public view virtual returns (uint256) {
  70. return _erc20Released[token];
  71. }
  72. /**
  73. * @dev Release the native token (ether) that have already vested.
  74. *
  75. * Emits a {TokensReleased} event.
  76. */
  77. function release() public virtual {
  78. uint256 releasable = vestedAmount(uint64(block.timestamp)) - released();
  79. _released += releasable;
  80. emit EtherReleased(releasable);
  81. Address.sendValue(payable(beneficiary()), releasable);
  82. }
  83. /**
  84. * @dev Release the tokens that have already vested.
  85. *
  86. * Emits a {TokensReleased} event.
  87. */
  88. function release(address token) public virtual {
  89. uint256 releasable = vestedAmount(token, uint64(block.timestamp)) - released(token);
  90. _erc20Released[token] += releasable;
  91. emit ERC20Released(token, releasable);
  92. SafeERC20.safeTransfer(IERC20(token), beneficiary(), releasable);
  93. }
  94. /**
  95. * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve.
  96. */
  97. function vestedAmount(uint64 timestamp) public view virtual returns (uint256) {
  98. return _vestingSchedule(address(this).balance + released(), timestamp);
  99. }
  100. /**
  101. * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve.
  102. */
  103. function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) {
  104. return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp);
  105. }
  106. /**
  107. * @dev Virtual implementation of the vesting formula. This returns the amout vested, as a function of time, for
  108. * an asset given its total historical allocation.
  109. */
  110. function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) {
  111. if (timestamp < start()) {
  112. return 0;
  113. } else if (timestamp > start() + duration()) {
  114. return totalAllocation;
  115. } else {
  116. return (totalAllocation * (timestamp - start())) / duration();
  117. }
  118. }
  119. }