// SPDX-License-Identifier: MIT pragma solidity ^0.8.18; import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; interface Vesting { function getTotalTokens(IERC20 _token, address _beneficiary) external view returns(uint256); } // Moves voting power with the normally private `_moveVotingPower` function by calling the `_afterTokenTransfer` function. // see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/dfef6a68ee18dbd2e1f5a099061a3b8a0e404485/contracts/token/ERC20/extensions/ERC20Votes.sol#LL217C6-L217C6 // see https://github.com/OpenZeppelin/openzeppelin-contracts/blob/dfef6a68ee18dbd2e1f5a099061a3b8a0e404485/contracts/token/ERC20/ERC20.sol#L364 abstract contract ERC20VotesVestable is ERC20Votes, Ownable { Vesting vest; // to be called after tokens have been transferred to the vesting contract function setUpVestedVotingPower(address _vestingAddress, address[] memory _vestees) external onlyOwner { if (address(vest) != address(0)) revert(); vest = Vesting(_vestingAddress); for (uint i = 0; i < _vestees.length; i++) { address a = _vestees[i]; super._afterTokenTransfer(_vestingAddress, a, vest.getTotalTokens(this, a)); } } function _afterTokenTransfer(address _from, address _to, uint256 _amount) internal override { // if it's the vesting contract, don't transfer any voting power when it leaves vesting, the // power will remain with whoever it's been delegated to already if (address(vest) != _from) { super._afterTokenTransfer(_from, _to, _amount); } } function _delegate(address _delegator, address _delegatee) internal override { super._delegate(_delegator, _delegatee); uint256 vestingBalance = vest.getTotalTokens(this, _delegator); if (vestingBalance > 0) { // add the vesting balance to the new delegatee's voting power super._afterTokenTransfer(delegates(_delegator), _delegatee, vestingBalance); } } }
0.7.1