Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/warm-walls-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`VestingWallet`: Add `IERC6372` (Contract Clock interface) support, exposing `clock()` and `CLOCK_MODE()` for timestamp-based operation.
17 changes: 16 additions & 1 deletion contracts/finance/VestingWallet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);

Expand All @@ -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.
*/
Expand Down
5 changes: 5 additions & 0 deletions test/finance/VestingWallet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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 () {
Expand Down