diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e42c92..55f43c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +## [1.2.0-dev.2](https://github.com/VenusProtocol/solidity-utilities/compare/v1.2.0-dev.1...v1.2.0-dev.2) (2023-12-27) + + +### Features + +* set compiler config similar to other packages ([8cc9b56](https://github.com/VenusProtocol/solidity-utilities/commit/8cc9b560e38b0692023b536be0ae3cbb3f228aa2)) + +## [1.2.0-dev.1](https://github.com/VenusProtocol/solidity-utilities/compare/v1.1.1-dev.1...v1.2.0-dev.1) (2023-12-21) + + +### Features + +* add TimeManagerV5 and TimeManagerV8 ([29db1cd](https://github.com/VenusProtocol/solidity-utilities/commit/29db1cdc8455a04736fcc2fc5e5cf6221aa5050d)) + + +### Bug Fixes + +* change contract name ([066450f](https://github.com/VenusProtocol/solidity-utilities/commit/066450f79d1c0872ed9baa39f55ebb2952ebb33f)) +* comments and revert condition ([d037cf3](https://github.com/VenusProtocol/solidity-utilities/commit/d037cf33114552e730aee83e209bd4c937d73703)) +* netscape ([05d1962](https://github.com/VenusProtocol/solidity-utilities/commit/05d19627e649cc456e15dcf2da9671d19ccfe4fa)) + +## [1.1.1-dev.1](https://github.com/VenusProtocol/solidity-utilities/compare/v1.1.0...v1.1.1-dev.1) (2023-12-07) + + +### Bug Fixes + +* added seconds per year ([0ac205b](https://github.com/VenusProtocol/solidity-utilities/commit/0ac205b92d2a84b9832c764f21bab09bc2a8cda8)) +* lint ([212e959](https://github.com/VenusProtocol/solidity-utilities/commit/212e9590568ba433a2d5b7b40445374143f20561)) + ## [1.1.0](https://github.com/VenusProtocol/solidity-utilities/compare/v1.0.1...v1.1.0) (2023-11-07) diff --git a/contracts/TimeManagerV5.sol b/contracts/TimeManagerV5.sol new file mode 100644 index 0000000..59ba7c3 --- /dev/null +++ b/contracts/TimeManagerV5.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.5.16; + +contract TimeManagerV5 { + /// @dev The approximate number of seconds per year + uint256 public constant SECONDS_PER_YEAR = 31_536_000; + + /// @notice Number of blocks per year or seconds per year + uint256 public blocksOrSecondsPerYear; + + /// @dev Sets true when block timestamp is used + bool public isTimeBased; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[47] private __gap; + + /** + * @dev Retrieves the current slot + * @return Current slot + */ + function() view returns (uint256) private _getCurrentSlot; + + /** + * @param timeBased_ A boolean indicating whether the contract is based on time or block + * If timeBased is true than blocksPerYear_ param is ignored as blocksOrSecondsPerYear is set to SECONDS_PER_YEAR + * @param blocksPerYear_ The number of blocks per year + */ + constructor(bool timeBased_, uint256 blocksPerYear_) public { + if (!timeBased_ && blocksPerYear_ == 0) { + revert("Invalid blocks per year"); + } + if (timeBased_ && blocksPerYear_ != 0) { + revert("Invalid time based configuration"); + } + + isTimeBased = timeBased_; + blocksOrSecondsPerYear = timeBased_ ? SECONDS_PER_YEAR : blocksPerYear_; + _getCurrentSlot = timeBased_ ? _getBlockTimestamp : _getBlockNumber; + } + + /** + * @dev Function to simply retrieve block number or block timestamp + * @return Current block number or block timestamp + */ + function getBlockNumberOrTimestamp() public view returns (uint256) { + return _getCurrentSlot(); + } + + /** + * @dev Returns the current timestamp in seconds + * @return The current timestamp + */ + function _getBlockTimestamp() private view returns (uint256) { + return block.timestamp; + } + + /** + * @dev Returns the current block number + * @return The current block number + */ + function _getBlockNumber() private view returns (uint256) { + return block.number; + } +} diff --git a/contracts/TimeManagerV8.sol b/contracts/TimeManagerV8.sol new file mode 100644 index 0000000..e36f339 --- /dev/null +++ b/contracts/TimeManagerV8.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.13; + +import { SECONDS_PER_YEAR } from "./constants.sol"; + +abstract contract TimeManagerV8 { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + uint256 public immutable blocksOrSecondsPerYear; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + bool public immutable isTimeBased; + + /** + * @dev This empty reserved space is put in place to allow future versions to add new + * variables without shifting down storage in the inheritance chain + * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps + */ + uint256[48] private __gap; + + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + function() view returns (uint256) private immutable _getCurrentSlot; + + /// @notice Thrown when blocks per year is invalid + error InvalidBlocksPerYear(); + + /// @notice Thrown when time based but blocks per year is provided + error InvalidTimeBasedConfiguration(); + + /** + * @param timeBased_ A boolean indicating whether the contract is based on time or block + * If timeBased is true than blocksPerYear_ param is ignored as blocksOrSecondsPerYear is set to SECONDS_PER_YEAR + * @param blocksPerYear_ The number of blocks per year + * @custom:error InvalidBlocksPerYear is thrown if blocksPerYear entered is zero and timeBased is false + * @custom:error InvalidTimeBasedConfiguration is thrown if blocksPerYear entered is non zero and timeBased is true + * @custom:oz-upgrades-unsafe-allow constructor + */ + constructor(bool timeBased_, uint256 blocksPerYear_) { + if (!timeBased_ && blocksPerYear_ == 0) { + revert InvalidBlocksPerYear(); + } + + if (timeBased_ && blocksPerYear_ != 0) { + revert InvalidTimeBasedConfiguration(); + } + + isTimeBased = timeBased_; + blocksOrSecondsPerYear = timeBased_ ? SECONDS_PER_YEAR : blocksPerYear_; + _getCurrentSlot = timeBased_ ? _getBlockTimestamp : _getBlockNumber; + } + + /** + * @dev Function to simply retrieve block number or block timestamp + * @return Current block number or block timestamp + */ + function getBlockNumberOrTimestamp() public view virtual returns (uint256) { + return _getCurrentSlot(); + } + + /** + * @dev Returns the current timestamp in seconds + * @return The current timestamp + */ + function _getBlockTimestamp() private view returns (uint256) { + return block.timestamp; + } + + /** + * @dev Returns the current block number + * @return The current block number + */ + function _getBlockNumber() private view returns (uint256) { + return block.number; + } +} diff --git a/contracts/constants.sol b/contracts/constants.sol index 9e6d9a5..5730cf8 100644 --- a/contracts/constants.sol +++ b/contracts/constants.sol @@ -6,3 +6,6 @@ uint256 constant EXP_SCALE = 1e18; /// @dev A unit (literal one) in EXP_SCALE, usually used in additions/subtractions uint256 constant MANTISSA_ONE = EXP_SCALE; + +/// @dev The approximate number of seconds per year +uint256 constant SECONDS_PER_YEAR = 31_536_000; diff --git a/hardhat.config.ts b/hardhat.config.ts index f80b120..4b06192 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -36,10 +36,22 @@ const config: HardhatUserConfig = { settings: { optimizer: { enabled: true, - details: { - yul: !process.env.CI, + runs: 200, + }, + outputSelection: { + "*": { + "*": ["storageLayout"], }, }, + }, + }, + { + version: "0.5.16", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, outputSelection: { "*": { "*": ["storageLayout"], diff --git a/package.json b/package.json index 1b154bb..58eb4dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@venusprotocol/solidity-utilities", - "version": "1.1.0", + "version": "1.2.0-dev.2", "description": "Solidity code used by other Venus projects", "files": [ "artifacts", diff --git a/tests/hardhat/TimeManagerV5.ts b/tests/hardhat/TimeManagerV5.ts new file mode 100644 index 0000000..f27c852 --- /dev/null +++ b/tests/hardhat/TimeManagerV5.ts @@ -0,0 +1,34 @@ +import chai from "chai"; +import { ethers } from "hardhat"; + +const { expect } = chai; + +describe("TimeManagerV5: tests", async () => { + let timeManager: ethers.Contracts; + describe("For block number", async () => { + const blocksPerYear = 10512000; + beforeEach(async () => { + const timeManagerV5 = await ethers.getContractFactory("TimeManagerV5"); + timeManager = await timeManagerV5.deploy(false, blocksPerYear); + }); + + it("Retrieves block timestamp", async () => { + const currentBlockNumber = (await ethers.provider.getBlock("latest")).number; + expect(await timeManager.getBlockNumberOrTimestamp()).to.be.equal(currentBlockNumber); + expect(await timeManager.blocksOrSecondsPerYear()).to.be.equal(blocksPerYear); + }); + }); + describe("For block timestamp", async () => { + beforeEach(async () => { + const timeManagerV5 = await ethers.getContractFactory("TimeManagerV5"); + timeManager = await timeManagerV5.deploy(true, 0); + }); + + it("Retrieves block timestamp", async () => { + const secondsPerYear = await timeManager.SECONDS_PER_YEAR(); + const currentBlocktimestamp = (await ethers.provider.getBlock("latest")).timestamp; + expect(await timeManager.getBlockNumberOrTimestamp()).to.be.equal(currentBlocktimestamp); + expect(await timeManager.blocksOrSecondsPerYear()).to.be.equal(secondsPerYear); + }); + }); +});