diff --git a/.changeset/warm-walls-glow.md b/.changeset/warm-walls-glow.md new file mode 100644 index 00000000000..33e62d0057a --- /dev/null +++ b/.changeset/warm-walls-glow.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`VestingWallet`: Add `IERC6372` (Contract Clock interface) support, exposing `clock()` and `CLOCK_MODE()` for timestamp-based operation. diff --git a/contracts/finance/VestingWallet.sol b/contracts/finance/VestingWallet.sol index eabf8859fbd..ac30a19720a 100644 --- a/contracts/finance/VestingWallet.sol +++ b/contracts/finance/VestingWallet.sol @@ -8,6 +8,8 @@ import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; import {Address} from "../utils/Address.sol"; import {Context} from "../utils/Context.sol"; import {Ownable} from "../access/Ownable.sol"; +import {IERC6372} from "../interfaces/IERC6372.sol"; +import {Time} from "../utils/types/Time.sol"; /** * @dev A vesting wallet is an ownable contract that can receive native currency and ERC-20 tokens, and release these @@ -33,7 +35,7 @@ import {Ownable} from "../access/Ownable.sol"; * at 50% of the vesting period, the beneficiary can withdraw 50 A as ERC20 and 25 A as native currency (totaling 75 A). * Consider disabling one of the withdrawal methods. */ -contract VestingWallet is Context, Ownable { +contract VestingWallet is Context, Ownable, IERC6372 { event EtherReleased(uint256 amount); event ERC20Released(address indexed token, uint256 amount); @@ -51,6 +53,19 @@ contract VestingWallet is Context, Ownable { _duration = durationSeconds; } + /** + * @dev Clock used for the vesting schedule, based on {Time-timestamp}. + */ + function clock() public view virtual returns (uint48) { + return Time.timestamp(); + } + + /// @inheritdoc IERC6372 + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public pure virtual returns (string memory) { + return "mode=timestamp"; + } + /** * @dev The contract should be able to receive Eth. */ diff --git a/test/finance/VestingWallet.test.js b/test/finance/VestingWallet.test.js index b89258d65b8..2f0d9f78e90 100644 --- a/test/finance/VestingWallet.test.js +++ b/test/finance/VestingWallet.test.js @@ -6,6 +6,7 @@ const { min } = require('../helpers/math'); const time = require('../helpers/time'); const { envSetup, shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); +const { shouldBehaveLikeERC6372 } = require('../governance/utils/ERC6372.behavior'); async function fixture() { const amount = ethers.parseEther('100'); @@ -45,6 +46,10 @@ describe('VestingWallet', function () { expect(await this.mock.end()).to.equal(this.start + this.duration); }); + describe('ERC-6372 clock', function () { + shouldBehaveLikeERC6372('timestamp'); + }); + describe('vesting schedule', function () { describe('Eth vesting', function () { beforeEach(async function () {