// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {ANftF} from "../../core/ANftF.sol"; import {AbstractRegulatoryModule} from "../AbstractRegulatoryModule.sol"; /** * @notice `TransferLimitsModule` is an example of a possible implementation of a regulatory module, * which adds rules for minimum and maximum amount for transfers. */ abstract contract TransferLimitsModule is AbstractRegulatoryModule { bytes32 public constant MAX_DAILY_TRANSFER_LIMIT_TOPIC = keccak256("MAX_DAILY_TRANSFER_LIMIT"); struct TransferData { uint256 lastTransferTimestamp; uint256 amountOfTransfers; } uint256 private _maxDailyTransferLimit; mapping(address => TransferData) private _transferData; function __TransferLimitsModule_init( uint256 maxDailyTransferValue_ ) internal onlyInitializing { _maxDailyTransferLimit = maxDailyTransferValue_; } function transferred(ANftF.Context memory ctx_) public virtual override onlyANftF { if (_isNewDay(ctx_.from)) { _transferData[ctx_.from].amountOfTransfers = 0; } _transferData[ctx_.from].amountOfTransfers++; _transferData[ctx_.from].lastTransferTimestamp = block.timestamp; super.transferred(ctx_); } function setMaxDailyTransferLimit( uint256 maxDailyTransferLimit_ ) public virtual onlyRole(_moduleRole()) { _maxDailyTransferLimit = maxDailyTransferLimit_; } function getDailyTransferLimits() public view virtual returns (uint256 maxDailyTransferLimit_) { return _maxDailyTransferLimit; } function _handlerer() internal virtual override { _setHandler(MAX_DAILY_TRANSFER_LIMIT_TOPIC, _handleMaxDailyTransferLimitTopic); } function _handleMaxDailyTransferLimitTopic( ANftF.Context memory ctx_ ) internal view virtual returns (bool) { return _isNewDay(ctx_.from) || _transferData[ctx_.from].amountOfTransfers < _maxDailyTransferLimit; } function _isNewDay(address user_) public view virtual returns (bool) { return block.timestamp / 1 days - _transferData[user_].lastTransferTimestamp / 1 days >= 1; } uint256[48] private _gap; }