Merge branch 'master' into next-v5.0
This commit is contained in:
9
contracts/mocks/token/ERC20ExcessDecimalsMock.sol
Normal file
9
contracts/mocks/token/ERC20ExcessDecimalsMock.sol
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ERC20ExcessDecimalsMock {
|
||||
function decimals() public pure returns (uint256) {
|
||||
return type(uint256).max;
|
||||
}
|
||||
}
|
||||
13
contracts/mocks/token/ERC20ForceApproveMock.sol
Normal file
13
contracts/mocks/token/ERC20ForceApproveMock.sol
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
|
||||
// contract that replicate USDT (0xdac17f958d2ee523a2206206994597c13d831ec7) approval beavior
|
||||
abstract contract ERC20ForceApproveMock is ERC20 {
|
||||
function approve(address spender, uint256 amount) public virtual override returns (bool) {
|
||||
require(amount == 0 || allowance(msg.sender, spender) == 0, "USDT approval failure");
|
||||
return super.approve(spender, amount);
|
||||
}
|
||||
}
|
||||
16
contracts/mocks/token/ERC20Mock.sol
Normal file
16
contracts/mocks/token/ERC20Mock.sol
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
|
||||
contract ERC20Mock is ERC20 {
|
||||
constructor() ERC20("ERC20Mock", "E20M") {}
|
||||
|
||||
function mint(address account, uint256 amount) external {
|
||||
_mint(account, amount);
|
||||
}
|
||||
|
||||
function burn(address account, uint256 amount) external {
|
||||
_burn(account, amount);
|
||||
}
|
||||
}
|
||||
@ -2,20 +2,27 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ERC20NoReturnMock {
|
||||
mapping(address => uint256) private _allowances;
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
|
||||
function transfer(address, uint256) public {}
|
||||
|
||||
function transferFrom(address, address, uint256) public {}
|
||||
|
||||
function approve(address, uint256) public {}
|
||||
|
||||
function setAllowance(address account, uint256 allowance_) public {
|
||||
_allowances[account] = allowance_;
|
||||
abstract contract ERC20NoReturnMock is ERC20 {
|
||||
function transfer(address to, uint256 amount) public override returns (bool) {
|
||||
super.transfer(to, amount);
|
||||
assembly {
|
||||
return(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function allowance(address owner, address) public view returns (uint256) {
|
||||
return _allowances[owner];
|
||||
function transferFrom(address from, address to, uint256 amount) public override returns (bool) {
|
||||
super.transferFrom(from, to, amount);
|
||||
assembly {
|
||||
return(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function approve(address spender, uint256 amount) public override returns (bool) {
|
||||
super.approve(spender, amount);
|
||||
assembly {
|
||||
return(0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,9 +5,7 @@ pragma solidity ^0.8.0;
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
import "../../token/ERC20/extensions/draft-ERC20Permit.sol";
|
||||
|
||||
contract ERC20PermitNoRevertMock is ERC20, ERC20Permit {
|
||||
constructor() ERC20("ERC20PermitNoRevertMock", "ERC20PermitNoRevertMock") ERC20Permit("ERC20PermitNoRevertMock") {}
|
||||
|
||||
abstract contract ERC20PermitNoRevertMock is ERC20Permit {
|
||||
function permitThatMayRevert(
|
||||
address owner,
|
||||
address spender,
|
||||
|
||||
39
contracts/mocks/token/ERC20Reentrant.sol
Normal file
39
contracts/mocks/token/ERC20Reentrant.sol
Normal file
@ -0,0 +1,39 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
import "../../token/ERC20/extensions/ERC4626.sol";
|
||||
|
||||
contract ERC20Reentrant is ERC20("TEST", "TST") {
|
||||
enum Type {
|
||||
No,
|
||||
Before,
|
||||
After
|
||||
}
|
||||
|
||||
Type private _reenterType;
|
||||
address private _reenterTarget;
|
||||
bytes private _reenterData;
|
||||
|
||||
function scheduleReenter(Type when, address target, bytes calldata data) external {
|
||||
_reenterType = when;
|
||||
_reenterTarget = target;
|
||||
_reenterData = data;
|
||||
}
|
||||
|
||||
function functionCall(address target, bytes memory data) public returns (bytes memory) {
|
||||
return Address.functionCall(target, data);
|
||||
}
|
||||
|
||||
function _update(address from, address to, uint256 amount) internal override {
|
||||
if (_reenterType == Type.Before) {
|
||||
_reenterType = Type.No;
|
||||
functionCall(_reenterTarget, _reenterData);
|
||||
}
|
||||
super._update(from, to, amount);
|
||||
if (_reenterType == Type.After) {
|
||||
_reenterType = Type.No;
|
||||
functionCall(_reenterTarget, _reenterData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,26 +2,18 @@
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ERC20ReturnFalseMock {
|
||||
mapping(address => uint256) private _allowances;
|
||||
import "../../token/ERC20/ERC20.sol";
|
||||
|
||||
function transfer(address, uint256) public pure returns (bool) {
|
||||
abstract contract ERC20ReturnFalseMock is ERC20 {
|
||||
function transfer(address, uint256) public pure override returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) public pure returns (bool) {
|
||||
function transferFrom(address, address, uint256) public pure override returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function approve(address, uint256) public pure returns (bool) {
|
||||
function approve(address, uint256) public pure override returns (bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function setAllowance(address account, uint256 allowance_) public {
|
||||
_allowances[account] = allowance_;
|
||||
}
|
||||
|
||||
function allowance(address owner, address) public view returns (uint256) {
|
||||
return _allowances[owner];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract ERC20ReturnTrueMock {
|
||||
mapping(address => uint256) private _allowances;
|
||||
|
||||
function transfer(address, uint256) public pure returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function transferFrom(address, address, uint256) public pure returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function approve(address, uint256) public pure returns (bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function setAllowance(address account, uint256 allowance_) public {
|
||||
_allowances[account] = allowance_;
|
||||
}
|
||||
|
||||
function allowance(address owner, address) public view returns (uint256) {
|
||||
return _allowances[owner];
|
||||
}
|
||||
}
|
||||
252
contracts/mocks/token/ERC20VotesLegacyMock.sol
Normal file
252
contracts/mocks/token/ERC20VotesLegacyMock.sol
Normal file
@ -0,0 +1,252 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/extensions/ERC20Permit.sol";
|
||||
import "../../utils/math/Math.sol";
|
||||
import "../../governance/utils/IVotes.sol";
|
||||
import "../../utils/math/SafeCast.sol";
|
||||
import "../../utils/cryptography/ECDSA.sol";
|
||||
|
||||
/**
|
||||
* @dev Copied from the master branch at commit 86de1e8b6c3fa6b4efa4a5435869d2521be0f5f5
|
||||
*/
|
||||
abstract contract ERC20VotesLegacyMock is IVotes, ERC20Permit {
|
||||
struct Checkpoint {
|
||||
uint32 fromBlock;
|
||||
uint224 votes;
|
||||
}
|
||||
|
||||
bytes32 private constant _DELEGATION_TYPEHASH =
|
||||
keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
|
||||
|
||||
mapping(address => address) private _delegates;
|
||||
mapping(address => Checkpoint[]) private _checkpoints;
|
||||
Checkpoint[] private _totalSupplyCheckpoints;
|
||||
|
||||
/**
|
||||
* @dev Get the `pos`-th checkpoint for `account`.
|
||||
*/
|
||||
function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoint memory) {
|
||||
return _checkpoints[account][pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get number of checkpoints for `account`.
|
||||
*/
|
||||
function numCheckpoints(address account) public view virtual returns (uint32) {
|
||||
return SafeCast.toUint32(_checkpoints[account].length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Get the address `account` is currently delegating to.
|
||||
*/
|
||||
function delegates(address account) public view virtual override returns (address) {
|
||||
return _delegates[account];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Gets the current votes balance for `account`
|
||||
*/
|
||||
function getVotes(address account) public view virtual override returns (uint256) {
|
||||
uint256 pos = _checkpoints[account].length;
|
||||
unchecked {
|
||||
return pos == 0 ? 0 : _checkpoints[account][pos - 1].votes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Retrieve the number of votes for `account` at the end of `blockNumber`.
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `blockNumber` must have been already mined
|
||||
*/
|
||||
function getPastVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
|
||||
require(blockNumber < block.number, "ERC20Votes: block not yet mined");
|
||||
return _checkpointsLookup(_checkpoints[account], blockNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.
|
||||
* It is NOT the sum of all the delegated votes!
|
||||
*
|
||||
* Requirements:
|
||||
*
|
||||
* - `blockNumber` must have been already mined
|
||||
*/
|
||||
function getPastTotalSupply(uint256 blockNumber) public view virtual override returns (uint256) {
|
||||
require(blockNumber < block.number, "ERC20Votes: block not yet mined");
|
||||
return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Lookup a value in a list of (sorted) checkpoints.
|
||||
*/
|
||||
function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber) private view returns (uint256) {
|
||||
// We run a binary search to look for the earliest checkpoint taken after `blockNumber`.
|
||||
//
|
||||
// Initially we check if the block is recent to narrow the search range.
|
||||
// During the loop, the index of the wanted checkpoint remains in the range [low-1, high).
|
||||
// With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.
|
||||
// - If the middle checkpoint is after `blockNumber`, we look in [low, mid)
|
||||
// - If the middle checkpoint is before or equal to `blockNumber`, we look in [mid+1, high)
|
||||
// Once we reach a single value (when low == high), we've found the right checkpoint at the index high-1, if not
|
||||
// out of bounds (in which case we're looking too far in the past and the result is 0).
|
||||
// Note that if the latest checkpoint available is exactly for `blockNumber`, we end up with an index that is
|
||||
// past the end of the array, so we technically don't find a checkpoint after `blockNumber`, but it works out
|
||||
// the same.
|
||||
uint256 length = ckpts.length;
|
||||
|
||||
uint256 low = 0;
|
||||
uint256 high = length;
|
||||
|
||||
if (length > 5) {
|
||||
uint256 mid = length - Math.sqrt(length);
|
||||
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (low < high) {
|
||||
uint256 mid = Math.average(low, high);
|
||||
if (_unsafeAccess(ckpts, mid).fromBlock > blockNumber) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
unchecked {
|
||||
return high == 0 ? 0 : _unsafeAccess(ckpts, high - 1).votes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Delegate votes from the sender to `delegatee`.
|
||||
*/
|
||||
function delegate(address delegatee) public virtual override {
|
||||
_delegate(_msgSender(), delegatee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Delegates votes from signer to `delegatee`
|
||||
*/
|
||||
function delegateBySig(
|
||||
address delegatee,
|
||||
uint256 nonce,
|
||||
uint256 expiry,
|
||||
uint8 v,
|
||||
bytes32 r,
|
||||
bytes32 s
|
||||
) public virtual override {
|
||||
require(block.timestamp <= expiry, "ERC20Votes: signature expired");
|
||||
address signer = ECDSA.recover(
|
||||
_hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
);
|
||||
require(nonce == _useNonce(signer), "ERC20Votes: invalid nonce");
|
||||
_delegate(signer, delegatee);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).
|
||||
*/
|
||||
function _maxSupply() internal view virtual returns (uint224) {
|
||||
return type(uint224).max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Move voting power when tokens are transferred.
|
||||
*
|
||||
* Emits a {IVotes-DelegateVotesChanged} event.
|
||||
*/
|
||||
function _update(address from, address to, uint256 amount) internal virtual override {
|
||||
super._update(from, to, amount);
|
||||
|
||||
if (from == address(0)) {
|
||||
require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes");
|
||||
_writeCheckpoint(_totalSupplyCheckpoints, _add, amount);
|
||||
}
|
||||
|
||||
if (to == address(0)) {
|
||||
_writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);
|
||||
}
|
||||
|
||||
_moveVotingPower(delegates(from), delegates(to), amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Change delegation for `delegator` to `delegatee`.
|
||||
*
|
||||
* Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}.
|
||||
*/
|
||||
function _delegate(address delegator, address delegatee) internal virtual {
|
||||
address currentDelegate = delegates(delegator);
|
||||
uint256 delegatorBalance = balanceOf(delegator);
|
||||
_delegates[delegator] = delegatee;
|
||||
|
||||
emit DelegateChanged(delegator, currentDelegate, delegatee);
|
||||
|
||||
_moveVotingPower(currentDelegate, delegatee, delegatorBalance);
|
||||
}
|
||||
|
||||
function _moveVotingPower(address src, address dst, uint256 amount) private {
|
||||
if (src != dst && amount > 0) {
|
||||
if (src != address(0)) {
|
||||
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[src], _subtract, amount);
|
||||
emit DelegateVotesChanged(src, oldWeight, newWeight);
|
||||
}
|
||||
|
||||
if (dst != address(0)) {
|
||||
(uint256 oldWeight, uint256 newWeight) = _writeCheckpoint(_checkpoints[dst], _add, amount);
|
||||
emit DelegateVotesChanged(dst, oldWeight, newWeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _writeCheckpoint(
|
||||
Checkpoint[] storage ckpts,
|
||||
function(uint256, uint256) view returns (uint256) op,
|
||||
uint256 delta
|
||||
) private returns (uint256 oldWeight, uint256 newWeight) {
|
||||
uint256 pos = ckpts.length;
|
||||
|
||||
unchecked {
|
||||
Checkpoint memory oldCkpt = pos == 0 ? Checkpoint(0, 0) : _unsafeAccess(ckpts, pos - 1);
|
||||
|
||||
oldWeight = oldCkpt.votes;
|
||||
newWeight = op(oldWeight, delta);
|
||||
|
||||
if (pos > 0 && oldCkpt.fromBlock == block.number) {
|
||||
_unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight);
|
||||
} else {
|
||||
ckpts.push(
|
||||
Checkpoint({fromBlock: SafeCast.toUint32(block.number), votes: SafeCast.toUint224(newWeight)})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _add(uint256 a, uint256 b) private pure returns (uint256) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
function _subtract(uint256 a, uint256 b) private pure returns (uint256) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
|
||||
*/
|
||||
function _unsafeAccess(Checkpoint[] storage ckpts, uint256 pos) private pure returns (Checkpoint storage result) {
|
||||
assembly {
|
||||
mstore(0, ckpts.slot)
|
||||
result.slot := add(keccak256(0, 0x20), pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/extensions/ERC4626.sol";
|
||||
|
||||
abstract contract ERC4626DecimalsMock is ERC4626 {
|
||||
using Math for uint256;
|
||||
|
||||
uint8 private immutable _decimals;
|
||||
|
||||
constructor(uint8 decimals_) {
|
||||
_decimals = decimals_;
|
||||
}
|
||||
|
||||
function decimals() public view virtual override returns (uint8) {
|
||||
return _decimals;
|
||||
}
|
||||
|
||||
function _initialConvertToShares(
|
||||
uint256 assets,
|
||||
Math.Rounding rounding
|
||||
) internal view virtual override returns (uint256 shares) {
|
||||
return assets.mulDiv(10 ** decimals(), 10 ** super.decimals(), rounding);
|
||||
}
|
||||
|
||||
function _initialConvertToAssets(
|
||||
uint256 shares,
|
||||
Math.Rounding rounding
|
||||
) internal view virtual override returns (uint256 assets) {
|
||||
return shares.mulDiv(10 ** super.decimals(), 10 ** decimals(), rounding);
|
||||
}
|
||||
}
|
||||
16
contracts/mocks/token/ERC4626Mock.sol
Normal file
16
contracts/mocks/token/ERC4626Mock.sol
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/extensions/ERC4626.sol";
|
||||
|
||||
contract ERC4626Mock is ERC4626 {
|
||||
constructor(address underlying) ERC20("ERC4626Mock", "E4626M") ERC4626(IERC20(underlying)) {}
|
||||
|
||||
function mint(address account, uint256 amount) external {
|
||||
_mint(account, amount);
|
||||
}
|
||||
|
||||
function burn(address account, uint256 amount) external {
|
||||
_burn(account, amount);
|
||||
}
|
||||
}
|
||||
17
contracts/mocks/token/ERC4626OffsetMock.sol
Normal file
17
contracts/mocks/token/ERC4626OffsetMock.sol
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/extensions/ERC4626.sol";
|
||||
|
||||
abstract contract ERC4626OffsetMock is ERC4626 {
|
||||
uint8 private immutable _offset;
|
||||
|
||||
constructor(uint8 offset_) {
|
||||
_offset = offset_;
|
||||
}
|
||||
|
||||
function _decimalsOffset() internal view virtual override returns (uint8) {
|
||||
return _offset;
|
||||
}
|
||||
}
|
||||
40
contracts/mocks/token/ERC4646FeesMock.sol
Normal file
40
contracts/mocks/token/ERC4646FeesMock.sol
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../docs/ERC4626Fees.sol";
|
||||
|
||||
abstract contract ERC4626FeesMock is ERC4626Fees {
|
||||
uint256 private immutable _entryFeeBasePointValue;
|
||||
address private immutable _entryFeeRecipientValue;
|
||||
uint256 private immutable _exitFeeBasePointValue;
|
||||
address private immutable _exitFeeRecipientValue;
|
||||
|
||||
constructor(
|
||||
uint256 entryFeeBasePoint,
|
||||
address entryFeeRecipient,
|
||||
uint256 exitFeeBasePoint,
|
||||
address exitFeeRecipient
|
||||
) {
|
||||
_entryFeeBasePointValue = entryFeeBasePoint;
|
||||
_entryFeeRecipientValue = entryFeeRecipient;
|
||||
_exitFeeBasePointValue = exitFeeBasePoint;
|
||||
_exitFeeRecipientValue = exitFeeRecipient;
|
||||
}
|
||||
|
||||
function _entryFeeBasePoint() internal view virtual override returns (uint256) {
|
||||
return _entryFeeBasePointValue;
|
||||
}
|
||||
|
||||
function _entryFeeRecipient() internal view virtual override returns (address) {
|
||||
return _entryFeeRecipientValue;
|
||||
}
|
||||
|
||||
function _exitFeeBasePoint() internal view virtual override returns (uint256) {
|
||||
return _exitFeeBasePointValue;
|
||||
}
|
||||
|
||||
function _exitFeeRecipient() internal view virtual override returns (address) {
|
||||
return _exitFeeRecipientValue;
|
||||
}
|
||||
}
|
||||
40
contracts/mocks/token/VotesTimestamp.sol
Normal file
40
contracts/mocks/token/VotesTimestamp.sol
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "../../token/ERC20/extensions/ERC20Votes.sol";
|
||||
import "../../token/ERC20/extensions/ERC20VotesComp.sol";
|
||||
import "../../token/ERC721/extensions/ERC721Votes.sol";
|
||||
|
||||
abstract contract ERC20VotesTimestampMock is ERC20Votes {
|
||||
function clock() public view virtual override returns (uint48) {
|
||||
return SafeCast.toUint48(block.timestamp);
|
||||
}
|
||||
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function CLOCK_MODE() public view virtual override returns (string memory) {
|
||||
return "mode=timestamp";
|
||||
}
|
||||
}
|
||||
|
||||
abstract contract ERC20VotesCompTimestampMock is ERC20VotesComp {
|
||||
function clock() public view virtual override returns (uint48) {
|
||||
return SafeCast.toUint48(block.timestamp);
|
||||
}
|
||||
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function CLOCK_MODE() public view virtual override returns (string memory) {
|
||||
return "mode=timestamp";
|
||||
}
|
||||
}
|
||||
|
||||
abstract contract ERC721VotesTimestampMock is ERC721Votes {
|
||||
function clock() public view virtual override returns (uint48) {
|
||||
return SafeCast.toUint48(block.timestamp);
|
||||
}
|
||||
|
||||
// solhint-disable-next-line func-name-mixedcase
|
||||
function CLOCK_MODE() public view virtual override returns (string memory) {
|
||||
return "mode=timestamp";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user