Diff
checker
Testo
Testo
Immagini
Documenti
Excel
Cartelle
Legal
Enterprise
Applicazione per desktop
Prezzi
Accedi
Scarica Diffchecker Desktop
Confronta il testo
Trova la differenza tra due file di testo
Strumenti
Cronologia
Visualizzazione
Layout
Diviso
Unificato
Editor live
Nascondi spazi bianchi
Comprimi invariate
Senza a capo
Livello di dettaglio
Intelligente
Sintassi
Nessuno
Modifica aspetto
Elaborazione
Ignora
Trasforma testo
Vai alla prima modifica
Modifica input
Diffchecker Desktop
Il modo più sicuro per usare Diffchecker. Ottieni l'app Diffchecker Desktop: i tuoi diff non lasciano mai il tuo computer!
Ottieni Desktop
RSETH
Creato
10 mesi fa
Il diff non scade mai
Eliminare
Esporta
Condividere
Spiegare
14 rimozioni
Linee
Totale
Rimosso
Caratteri
Totale
Rimosso
Per continuare a utilizzare questa funzione, aggiorna a
Diff
checker
Pro
Visualizza prezzi
98 linee
Copia tutti
230 aggiunte
Linee
Totale
Aggiunto
Caratteri
Totale
Aggiunto
Per continuare a utilizzare questa funzione, aggiorna a
Diff
checker
Pro
Visualizza prezzi
315 linee
Copia tutti
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
pragma solidity 0.8.27;
import { UtilLib } from "./utils/UtilLib.sol";
import { UtilLib } from "./utils/UtilLib.sol";
import { LRTConfigRoleChecker, ILRTConfig, LRTConstants } from "./utils/LRTConfigRoleChecker.sol";
import { LRTConfigRoleChecker, ILRTConfig, LRTConstants } from "./utils/LRTConfigRoleChecker.sol";
import { ERC20Upgradeable, Initializable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import { ERC20Upgradeable, Initializable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
/// @title rsETH token Contract
/// @title rsETH token Contract
/// @author Kelp DAO
/// @author Kelp DAO
/// @notice The ERC20 contract for the rsETH token
/// @notice The ERC20 contract for the rsETH token
contract RSETH is Initializable, LRTConfigRoleChecker, ERC20Upgradeable, PausableUpgradeable {
contract RSETH is Initializable, LRTConfigRoleChecker, ERC20Upgradeable, PausableUpgradeable {
Copia
Copiato
Copia
Copiato
error DailyMintLimitExceeded(uint256 currentAmount, uint256 maxAmount);
/*//////////////////////////////////////////////////////////////
State Variables
event MaxMintAmountPerDayUpdated(uint256 newMaxMintAmountPerDay);
//////////////////////////////////////////////////////////////*/
Copia
Copiato
Copia
Copiato
/// @notice Maximum amount that can be minted in a 24-hour period
uint256 public maxMintAmountPerDay;
uint256 public maxMintAmountPerDay;
Copia
Copiato
Copia
Copiato
/// @notice Amount minted in the current 24-hour period
uint256 public currentPeriodMintedAmount;
uint256 public currentPeriodMintedAmount;
Copia
Copiato
Copia
Copiato
/// @notice Start time of the current 24-hour period
uint256 public periodStartTime;
uint256 public periodStartTime;
Copia
Copiato
Copia
Copiato
/// @notice Address to which recovered funds are sent
address public custodyAddress;
/// @dev If > 0, transfers TO or FROM this address are blocked until timestamp (24h block)
mapping(address account => uint256 blockedUntil) public transfersBlockedUntil;
/// @dev Permanently exempt addresses mapping (rsETH transfers for these can never be blocked)
mapping(address account => bool isExempt) public isPermanentlyExempt;
/*//////////////////////////////////////////////////////////////
Modifiers
//////////////////////////////////////////////////////////////*/
/// @dev Modifier to check and update daily mint limits
/// @dev Modifier to check and update daily mint limits
/// @param amount The amount to be minted
/// @param amount The amount to be minted
modifier checkDailyMintLimit(uint256 amount) {
modifier checkDailyMintLimit(uint256 amount) {
Copia
Copiato
Copia
Copiato
// Check if we need to reset the period
or initialize the period
// Check if we need to reset the period
if it has been more than 24 hours
if (
periodStartTime == 0 ||
block.timestamp >= periodStartTime + 1 days) {
if (
block.timestamp >= periodStartTime + 1 days) {
currentPeriodMintedAmount = 0;
currentPeriodMintedAmount = 0;
Copia
Copiato
Copia
Copiato
periodStartTime =
block.timestamp
;
periodStartTime =
getCurrentPeriodStartTime()
;
}
}
// Check if minting would exceed the daily limit
// Check if minting would exceed the daily limit
if (currentPeriodMintedAmount + amount > maxMintAmountPerDay) {
if (currentPeriodMintedAmount + amount > maxMintAmountPerDay) {
revert DailyMintLimitExceeded(currentPeriodMintedAmount + amount, maxMintAmountPerDay);
revert DailyMintLimitExceeded(currentPeriodMintedAmount + amount, maxMintAmountPerDay);
}
}
currentPeriodMintedAmount += amount;
currentPeriodMintedAmount += amount;
_;
_;
}
}
Copia
Copiato
Copia
Copiato
/*//////////////////////////////////////////////////////////////
Custom Errors
//////////////////////////////////////////////////////////////*/
error PeriodStartTimeShouldBeWithin24Hours();
error DailyMintLimitExceeded(uint256 currentAmount, uint256 maxAmount);
error TransfersBlocked(address account, uint256 blockedUntil);
error CannotPermanentlyExemptBlockedAddress(address account, uint256 blockedUntil);
error AddressPermanentlyExempt(address account);
error NoActiveTransferBlock(address account);
/*//////////////////////////////////////////////////////////////
Events
//////////////////////////////////////////////////////////////*/
event MaxMintAmountPerDayUpdated(uint256 newMaxMintAmountPerDay);
event FrozenFundsRecovered(address indexed from, address indexed to, uint256 amount);
event UserTransfersBlocked(address indexed user, uint256 until);
event PermanentExemptionAdded(address indexed account);
event CustodyAddressUpdated(address indexed newCustodyAddress);
event PeriodStartTimeSet(uint256 newPeriodStartTime);
/*//////////////////////////////////////////////////////////////
Constructor
//////////////////////////////////////////////////////////////*/
/// @custom:oz-upgrades-unsafe-allow constructor
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
constructor() {
_disableInitializers();
_disableInitializers();
}
}
Copia
Copiato
Copia
Copiato
/*//////////////////////////////////////////////////////////////
Initializers
//////////////////////////////////////////////////////////////*/
/// @dev Initializes the contract
/// @dev Initializes the contract
/// @param admin Admin address
/// @param admin Admin address
/// @param lrtConfigAddr LRT config address
/// @param lrtConfigAddr LRT config address
function initialize(address admin, address lrtConfigAddr) external initializer {
function initialize(address admin, address lrtConfigAddr) external initializer {
UtilLib.checkNonZeroAddress(admin);
UtilLib.checkNonZeroAddress(admin);
UtilLib.checkNonZeroAddress(lrtConfigAddr);
UtilLib.checkNonZeroAddress(lrtConfigAddr);
__ERC20_init("rsETH", "rsETH");
__ERC20_init("rsETH", "rsETH");
__Pausable_init();
__Pausable_init();
lrtConfig = ILRTConfig(lrtConfigAddr);
lrtConfig = ILRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
}
}
Copia
Copiato
Copia
Copiato
/// @notice Initializes the contract with a period start time and the custody address
/// @param _periodStartTime The period start time
/// @param _custodyAddress The custody address for recovered funds
function reinitialize(uint256 _periodStartTime, address _custodyAddress) external reinitializer(2) onlyLRTManager {
if (_periodStartTime > block.timestamp || _periodStartTime <= block.timestamp - 1 days) {
revert PeriodStartTimeShouldBeWithin24Hours();
}
periodStartTime = _periodStartTime;
emit PeriodStartTimeSet(_periodStartTime);
_setCustodyAddress(_custodyAddress);
}
/*//////////////////////////////////////////////////////////////
Manager Functions
//////////////////////////////////////////////////////////////*/
/// @notice Sets the maximum amount that can be minted in 24 hours
/// @notice Sets the maximum amount that can be minted in 24 hours
/// @param _maxMintAmountPerDay The maximum amount that can be minted in 24 hours
/// @param _maxMintAmountPerDay The maximum amount that can be minted in 24 hours
function setMaxMintAmountPerDay(uint256 _maxMintAmountPerDay) external onlyLRTManager {
function setMaxMintAmountPerDay(uint256 _maxMintAmountPerDay) external onlyLRTManager {
maxMintAmountPerDay = _maxMintAmountPerDay;
maxMintAmountPerDay = _maxMintAmountPerDay;
emit MaxMintAmountPerDayUpdated(_maxMintAmountPerDay);
emit MaxMintAmountPerDayUpdated(_maxMintAmountPerDay);
}
}
Copia
Copiato
Copia
Copiato
/// @notice Permanently add accounts to the exempted list (non-reversible)
/// @param accounts Accounts to mark as permanently exempt (cannot have transfers blocked)
function addPermanentExemptions(address[] calldata accounts) external onlyLRTManager {
uint256 length = accounts.length;
for (uint256 i = 0; i < length; ++i) {
address account = accounts[i];
UtilLib.checkNonZeroAddress(account);
// Ensure the account is not currently blocked
uint256 blockedUntil = transfersBlockedUntil[account];
if (blockedUntil != 0) {
if (block.timestamp < blockedUntil) {
revert CannotPermanentlyExemptBlockedAddress(account, blockedUntil);
}
// Auto-clean up expired block
delete transfersBlockedUntil[account];
}
if (!isPermanentlyExempt[account]) {
isPermanentlyExempt[account] = true;
emit PermanentExemptionAdded(account);
}
}
}
/// @notice Block transfers TO and FROM given users for 24 hours
/// @dev Re-applying the block before expiry refreshes the hold to `block.timestamp + 1 days`
/// (i.e. not cumulative; never more than 24h from the latest call). Exempt addresses cannot be blocked.
/// Emits {UserTransfersBlocked} only when the timestamp changes.
/// @param accounts Addresses to block.
function blockUserTransfers(address[] calldata accounts) external onlyLRTManager {
uint256 blockedUntil = block.timestamp + 1 days;
uint256 length = accounts.length;
for (uint256 i = 0; i < length; ++i) {
address account = accounts[i];
if (isPermanentlyExempt[account] || account == address(0)) continue;
uint256 prevBlockedUntil = transfersBlockedUntil[account];
if (blockedUntil != prevBlockedUntil) {
transfersBlockedUntil[account] = blockedUntil;
emit UserTransfersBlocked(account, blockedUntil);
}
}
}
/*//////////////////////////////////////////////////////////////
Pause Management
//////////////////////////////////////////////////////////////*/
/// @dev Triggers stopped state. Contract must not be paused.
function pause() external onlyRole(LRTConstants.PAUSER_ROLE) {
_pause();
}
/// @dev Returns to normal state. Contract must be paused.
function unpause() external onlyLRTAdmin {
_unpause();
}
/*//////////////////////////////////////////////////////////////
Admin Functions
//////////////////////////////////////////////////////////////*/
/// @notice Sets the custody address for recovered funds
/// @param newCustodyAddress The new custody address
function setCustodyAddress(address newCustodyAddress) external onlyLRTAdmin {
_setCustodyAddress(newCustodyAddress);
}
/// @notice Recover the entire balance from a currently blocked, non-exempt address to a designated custody address
/// @dev Only callable by LRT admin. Works only while the block is active.
/// Emits {FrozenFundsRecovered} even if the recovered amount is zero (for transparency and completeness).
function recoverFrozenFunds(address from) external onlyLRTAdmin {
UtilLib.checkNonZeroAddress(from);
UtilLib.checkNonZeroAddress(custodyAddress);
if (isPermanentlyExempt[from]) revert AddressPermanentlyExempt(from);
uint256 blockedUntil = transfersBlockedUntil[from];
if (blockedUntil == 0 || block.timestamp >= blockedUntil) revert NoActiveTransferBlock(from);
uint256 accountBalance = balanceOf(from);
// Bypass transfer block enforcement when transferring to custody address
super._transfer(from, custodyAddress, accountBalance);
emit FrozenFundsRecovered(from, custodyAddress, accountBalance);
}
/*//////////////////////////////////////////////////////////////
Mint & Burn
//////////////////////////////////////////////////////////////*/
/// @notice Mints rsETH when called by an authorized caller
/// @notice Mints rsETH when called by an authorized caller
/// @param to the account to mint to
/// @param to the account to mint to
/// @param amount the amount of rsETH to mint
/// @param amount the amount of rsETH to mint
function mint(
function mint(
address to,
address to,
uint256 amount
uint256 amount
)
)
external
external
onlyRole(LRTConstants.MINTER_ROLE)
onlyRole(LRTConstants.MINTER_ROLE)
whenNotPaused
whenNotPaused
checkDailyMintLimit(amount)
checkDailyMintLimit(amount)
{
{
Copia
Copiato
Copia
Copiato
_enforceNotBlocked(to);
_mint(to, amount);
_mint(to, amount);
}
}
/// @notice Burns rsETH when called by an authorized caller
/// @notice Burns rsETH when called by an authorized caller
/// @param account the account to burn from
/// @param account the account to burn from
/// @param amount the amount of rsETH to burn
/// @param amount the amount of rsETH to burn
function burnFrom(address account, uint256 amount) external onlyRole(LRTConstants.BURNER_ROLE) whenNotPaused {
function burnFrom(address account, uint256 amount) external onlyRole(LRTConstants.BURNER_ROLE) whenNotPaused {
Copia
Copiato
Copia
Copiato
_enforceNotBlocked(account);
_burn(account, amount);
_burn(account, amount);
}
}
Copia
Copiato
Copia
Copiato
/// @dev Triggers stopped state.
/*//////////////////////////////////////////////////////////////
/// @dev Only callable by LRT config manager. Contract must NOT be paused.
View Functions
function pause() external onlyLRTManager {
//////////////////////////////////////////////////////////////*/
_pause();
/// @notice Returns the aligned start timestamp of the effective current 24-hour minting period, accounting for any
/// possibly skipped days
/// @return uint256 The start timestamp of the effective current 24-hour period
function getCurrentPeriodStartTime() public view returns (uint256) {
// Calculate the full (complete) days elapsed since the period start time (floors the result)
uint256 daysElapsed = (block.timestamp - periodStartTime) / 1 days;
return periodStartTime + daysElapsed * 1 days;
}
}
Copia
Copiato
Copia
Copiato
/// @notice
Returns to normal state.
/// @notice
Gets the remaining daily minting limit
/// @dev Only callable by the rsETH admin. Contract must be paused
/// @return uint256 The remaining daily minting limit
function unpause() external onlyLRTAdmin {
function remainingDailyMintLimit() external view returns (uint256) {
_unpause();
if (maxMintAmountPerDay == 0) return 0;
// If we're on a new day but no mint has occurred yet, treat currentPeriodMintedAmount as 0
uint256 effectiveDailyMintAmount = (block.timestamp >= periodStartTime + 1 days) ? 0 : currentPeriodMintedAmount;
return maxMintAmountPerDay > effectiveDailyMintAmount ? maxMintAmountPerDay - effectiveDailyMintAmount : 0;
}
/// @notice Returns the timestamp at which the current effective daily minting period ends,
/// accounting for any skipped days during which no minting occurred
/// @dev A mint executed at exactly this timestamp is counted towards the next period's minting limit
/// @return uint256 The timestamp at which the effective current minting period ends
function getNextDailyLimitResetTimestamp() external view returns (uint256) {
return getCurrentPeriodStartTime() + 1 days;
}
/*//////////////////////////////////////////////////////////////
Internal Functions
//////////////////////////////////////////////////////////////*/
/// @dev Override ERC20 `_transfer` to enforce transfer blocks on `from` and `to` addresses
function _transfer(address from, address to, uint256 amount) internal override {
_enforceNotBlocked(from);
_enforceNotBlocked(to);
super._transfer(from, to, amount);
}
/// @dev Reverts if `account` is currently blocked (used for transfers, mints, and burns)
function _enforceNotBlocked(address account) internal {
// Addresses that are permanently exempt can never be blocked
if (isPermanentlyExempt[account]) return;
// Check if the account has an active transfer block
uint256 blockedUntil = transfersBlockedUntil[account];
if (blockedUntil == 0) return;
if (block.timestamp < blockedUntil) revert TransfersBlocked(account, blockedUntil);
// Auto-clean up expired block
delete transfersBlockedUntil[account];
}
/// @dev Internal function to set the custody address
function _setCustodyAddress(address newCustodyAddress) internal {
UtilLib.checkNonZeroAddress(newCustodyAddress);
custodyAddress = newCustodyAddress;
emit CustodyAddressUpdated(newCustodyAddress);
}
}
}
}
Copia
Copiato
Copia
Copiato
Diff salvati
Testo originale
Apri file
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.27; import { UtilLib } from "./utils/UtilLib.sol"; import { LRTConfigRoleChecker, ILRTConfig, LRTConstants } from "./utils/LRTConfigRoleChecker.sol"; import { ERC20Upgradeable, Initializable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; /// @title rsETH token Contract /// @author Kelp DAO /// @notice The ERC20 contract for the rsETH token contract RSETH is Initializable, LRTConfigRoleChecker, ERC20Upgradeable, PausableUpgradeable { error DailyMintLimitExceeded(uint256 currentAmount, uint256 maxAmount); event MaxMintAmountPerDayUpdated(uint256 newMaxMintAmountPerDay); uint256 public maxMintAmountPerDay; uint256 public currentPeriodMintedAmount; uint256 public periodStartTime; /// @dev Modifier to check and update daily mint limits /// @param amount The amount to be minted modifier checkDailyMintLimit(uint256 amount) { // Check if we need to reset the period or initialize the period if (periodStartTime == 0 || block.timestamp >= periodStartTime + 1 days) { currentPeriodMintedAmount = 0; periodStartTime = block.timestamp; } // Check if minting would exceed the daily limit if (currentPeriodMintedAmount + amount > maxMintAmountPerDay) { revert DailyMintLimitExceeded(currentPeriodMintedAmount + amount, maxMintAmountPerDay); } currentPeriodMintedAmount += amount; _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @dev Initializes the contract /// @param admin Admin address /// @param lrtConfigAddr LRT config address function initialize(address admin, address lrtConfigAddr) external initializer { UtilLib.checkNonZeroAddress(admin); UtilLib.checkNonZeroAddress(lrtConfigAddr); __ERC20_init("rsETH", "rsETH"); __Pausable_init(); lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /// @notice Sets the maximum amount that can be minted in 24 hours /// @param _maxMintAmountPerDay The maximum amount that can be minted in 24 hours function setMaxMintAmountPerDay(uint256 _maxMintAmountPerDay) external onlyLRTManager { maxMintAmountPerDay = _maxMintAmountPerDay; emit MaxMintAmountPerDayUpdated(_maxMintAmountPerDay); } /// @notice Mints rsETH when called by an authorized caller /// @param to the account to mint to /// @param amount the amount of rsETH to mint function mint( address to, uint256 amount ) external onlyRole(LRTConstants.MINTER_ROLE) whenNotPaused checkDailyMintLimit(amount) { _mint(to, amount); } /// @notice Burns rsETH when called by an authorized caller /// @param account the account to burn from /// @param amount the amount of rsETH to burn function burnFrom(address account, uint256 amount) external onlyRole(LRTConstants.BURNER_ROLE) whenNotPaused { _burn(account, amount); } /// @dev Triggers stopped state. /// @dev Only callable by LRT config manager. Contract must NOT be paused. function pause() external onlyLRTManager { _pause(); } /// @notice Returns to normal state. /// @dev Only callable by the rsETH admin. Contract must be paused function unpause() external onlyLRTAdmin { _unpause(); } }
Testo modificato
Apri file
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.27; import { UtilLib } from "./utils/UtilLib.sol"; import { LRTConfigRoleChecker, ILRTConfig, LRTConstants } from "./utils/LRTConfigRoleChecker.sol"; import { ERC20Upgradeable, Initializable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; /// @title rsETH token Contract /// @author Kelp DAO /// @notice The ERC20 contract for the rsETH token contract RSETH is Initializable, LRTConfigRoleChecker, ERC20Upgradeable, PausableUpgradeable { /*////////////////////////////////////////////////////////////// State Variables //////////////////////////////////////////////////////////////*/ /// @notice Maximum amount that can be minted in a 24-hour period uint256 public maxMintAmountPerDay; /// @notice Amount minted in the current 24-hour period uint256 public currentPeriodMintedAmount; /// @notice Start time of the current 24-hour period uint256 public periodStartTime; /// @notice Address to which recovered funds are sent address public custodyAddress; /// @dev If > 0, transfers TO or FROM this address are blocked until timestamp (24h block) mapping(address account => uint256 blockedUntil) public transfersBlockedUntil; /// @dev Permanently exempt addresses mapping (rsETH transfers for these can never be blocked) mapping(address account => bool isExempt) public isPermanentlyExempt; /*////////////////////////////////////////////////////////////// Modifiers //////////////////////////////////////////////////////////////*/ /// @dev Modifier to check and update daily mint limits /// @param amount The amount to be minted modifier checkDailyMintLimit(uint256 amount) { // Check if we need to reset the period if it has been more than 24 hours if (block.timestamp >= periodStartTime + 1 days) { currentPeriodMintedAmount = 0; periodStartTime = getCurrentPeriodStartTime(); } // Check if minting would exceed the daily limit if (currentPeriodMintedAmount + amount > maxMintAmountPerDay) { revert DailyMintLimitExceeded(currentPeriodMintedAmount + amount, maxMintAmountPerDay); } currentPeriodMintedAmount += amount; _; } /*////////////////////////////////////////////////////////////// Custom Errors //////////////////////////////////////////////////////////////*/ error PeriodStartTimeShouldBeWithin24Hours(); error DailyMintLimitExceeded(uint256 currentAmount, uint256 maxAmount); error TransfersBlocked(address account, uint256 blockedUntil); error CannotPermanentlyExemptBlockedAddress(address account, uint256 blockedUntil); error AddressPermanentlyExempt(address account); error NoActiveTransferBlock(address account); /*////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ event MaxMintAmountPerDayUpdated(uint256 newMaxMintAmountPerDay); event FrozenFundsRecovered(address indexed from, address indexed to, uint256 amount); event UserTransfersBlocked(address indexed user, uint256 until); event PermanentExemptionAdded(address indexed account); event CustodyAddressUpdated(address indexed newCustodyAddress); event PeriodStartTimeSet(uint256 newPeriodStartTime); /*////////////////////////////////////////////////////////////// Constructor //////////////////////////////////////////////////////////////*/ /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /*////////////////////////////////////////////////////////////// Initializers //////////////////////////////////////////////////////////////*/ /// @dev Initializes the contract /// @param admin Admin address /// @param lrtConfigAddr LRT config address function initialize(address admin, address lrtConfigAddr) external initializer { UtilLib.checkNonZeroAddress(admin); UtilLib.checkNonZeroAddress(lrtConfigAddr); __ERC20_init("rsETH", "rsETH"); __Pausable_init(); lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /// @notice Initializes the contract with a period start time and the custody address /// @param _periodStartTime The period start time /// @param _custodyAddress The custody address for recovered funds function reinitialize(uint256 _periodStartTime, address _custodyAddress) external reinitializer(2) onlyLRTManager { if (_periodStartTime > block.timestamp || _periodStartTime <= block.timestamp - 1 days) { revert PeriodStartTimeShouldBeWithin24Hours(); } periodStartTime = _periodStartTime; emit PeriodStartTimeSet(_periodStartTime); _setCustodyAddress(_custodyAddress); } /*////////////////////////////////////////////////////////////// Manager Functions //////////////////////////////////////////////////////////////*/ /// @notice Sets the maximum amount that can be minted in 24 hours /// @param _maxMintAmountPerDay The maximum amount that can be minted in 24 hours function setMaxMintAmountPerDay(uint256 _maxMintAmountPerDay) external onlyLRTManager { maxMintAmountPerDay = _maxMintAmountPerDay; emit MaxMintAmountPerDayUpdated(_maxMintAmountPerDay); } /// @notice Permanently add accounts to the exempted list (non-reversible) /// @param accounts Accounts to mark as permanently exempt (cannot have transfers blocked) function addPermanentExemptions(address[] calldata accounts) external onlyLRTManager { uint256 length = accounts.length; for (uint256 i = 0; i < length; ++i) { address account = accounts[i]; UtilLib.checkNonZeroAddress(account); // Ensure the account is not currently blocked uint256 blockedUntil = transfersBlockedUntil[account]; if (blockedUntil != 0) { if (block.timestamp < blockedUntil) { revert CannotPermanentlyExemptBlockedAddress(account, blockedUntil); } // Auto-clean up expired block delete transfersBlockedUntil[account]; } if (!isPermanentlyExempt[account]) { isPermanentlyExempt[account] = true; emit PermanentExemptionAdded(account); } } } /// @notice Block transfers TO and FROM given users for 24 hours /// @dev Re-applying the block before expiry refreshes the hold to `block.timestamp + 1 days` /// (i.e. not cumulative; never more than 24h from the latest call). Exempt addresses cannot be blocked. /// Emits {UserTransfersBlocked} only when the timestamp changes. /// @param accounts Addresses to block. function blockUserTransfers(address[] calldata accounts) external onlyLRTManager { uint256 blockedUntil = block.timestamp + 1 days; uint256 length = accounts.length; for (uint256 i = 0; i < length; ++i) { address account = accounts[i]; if (isPermanentlyExempt[account] || account == address(0)) continue; uint256 prevBlockedUntil = transfersBlockedUntil[account]; if (blockedUntil != prevBlockedUntil) { transfersBlockedUntil[account] = blockedUntil; emit UserTransfersBlocked(account, blockedUntil); } } } /*////////////////////////////////////////////////////////////// Pause Management //////////////////////////////////////////////////////////////*/ /// @dev Triggers stopped state. Contract must not be paused. function pause() external onlyRole(LRTConstants.PAUSER_ROLE) { _pause(); } /// @dev Returns to normal state. Contract must be paused. function unpause() external onlyLRTAdmin { _unpause(); } /*////////////////////////////////////////////////////////////// Admin Functions //////////////////////////////////////////////////////////////*/ /// @notice Sets the custody address for recovered funds /// @param newCustodyAddress The new custody address function setCustodyAddress(address newCustodyAddress) external onlyLRTAdmin { _setCustodyAddress(newCustodyAddress); } /// @notice Recover the entire balance from a currently blocked, non-exempt address to a designated custody address /// @dev Only callable by LRT admin. Works only while the block is active. /// Emits {FrozenFundsRecovered} even if the recovered amount is zero (for transparency and completeness). function recoverFrozenFunds(address from) external onlyLRTAdmin { UtilLib.checkNonZeroAddress(from); UtilLib.checkNonZeroAddress(custodyAddress); if (isPermanentlyExempt[from]) revert AddressPermanentlyExempt(from); uint256 blockedUntil = transfersBlockedUntil[from]; if (blockedUntil == 0 || block.timestamp >= blockedUntil) revert NoActiveTransferBlock(from); uint256 accountBalance = balanceOf(from); // Bypass transfer block enforcement when transferring to custody address super._transfer(from, custodyAddress, accountBalance); emit FrozenFundsRecovered(from, custodyAddress, accountBalance); } /*////////////////////////////////////////////////////////////// Mint & Burn //////////////////////////////////////////////////////////////*/ /// @notice Mints rsETH when called by an authorized caller /// @param to the account to mint to /// @param amount the amount of rsETH to mint function mint( address to, uint256 amount ) external onlyRole(LRTConstants.MINTER_ROLE) whenNotPaused checkDailyMintLimit(amount) { _enforceNotBlocked(to); _mint(to, amount); } /// @notice Burns rsETH when called by an authorized caller /// @param account the account to burn from /// @param amount the amount of rsETH to burn function burnFrom(address account, uint256 amount) external onlyRole(LRTConstants.BURNER_ROLE) whenNotPaused { _enforceNotBlocked(account); _burn(account, amount); } /*////////////////////////////////////////////////////////////// View Functions //////////////////////////////////////////////////////////////*/ /// @notice Returns the aligned start timestamp of the effective current 24-hour minting period, accounting for any /// possibly skipped days /// @return uint256 The start timestamp of the effective current 24-hour period function getCurrentPeriodStartTime() public view returns (uint256) { // Calculate the full (complete) days elapsed since the period start time (floors the result) uint256 daysElapsed = (block.timestamp - periodStartTime) / 1 days; return periodStartTime + daysElapsed * 1 days; } /// @notice Gets the remaining daily minting limit /// @return uint256 The remaining daily minting limit function remainingDailyMintLimit() external view returns (uint256) { if (maxMintAmountPerDay == 0) return 0; // If we're on a new day but no mint has occurred yet, treat currentPeriodMintedAmount as 0 uint256 effectiveDailyMintAmount = (block.timestamp >= periodStartTime + 1 days) ? 0 : currentPeriodMintedAmount; return maxMintAmountPerDay > effectiveDailyMintAmount ? maxMintAmountPerDay - effectiveDailyMintAmount : 0; } /// @notice Returns the timestamp at which the current effective daily minting period ends, /// accounting for any skipped days during which no minting occurred /// @dev A mint executed at exactly this timestamp is counted towards the next period's minting limit /// @return uint256 The timestamp at which the effective current minting period ends function getNextDailyLimitResetTimestamp() external view returns (uint256) { return getCurrentPeriodStartTime() + 1 days; } /*////////////////////////////////////////////////////////////// Internal Functions //////////////////////////////////////////////////////////////*/ /// @dev Override ERC20 `_transfer` to enforce transfer blocks on `from` and `to` addresses function _transfer(address from, address to, uint256 amount) internal override { _enforceNotBlocked(from); _enforceNotBlocked(to); super._transfer(from, to, amount); } /// @dev Reverts if `account` is currently blocked (used for transfers, mints, and burns) function _enforceNotBlocked(address account) internal { // Addresses that are permanently exempt can never be blocked if (isPermanentlyExempt[account]) return; // Check if the account has an active transfer block uint256 blockedUntil = transfersBlockedUntil[account]; if (blockedUntil == 0) return; if (block.timestamp < blockedUntil) revert TransfersBlocked(account, blockedUntil); // Auto-clean up expired block delete transfersBlockedUntil[account]; } /// @dev Internal function to set the custody address function _setCustodyAddress(address newCustodyAddress) internal { UtilLib.checkNonZeroAddress(newCustodyAddress); custodyAddress = newCustodyAddress; emit CustodyAddressUpdated(newCustodyAddress); } }
Trovare la differenza