Description:
Smart contract deployed on Ethereum with Factory features.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.19;
// src/core/BaseReentrancy.sol
abstract contract BaseReentrancy {
// ----------------------------------------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------------------------------------
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
// ----------------------------------------------------------------------------------------------------
// Errors
// ----------------------------------------------------------------------------------------------------
error ReentrantCall();
// ----------------------------------------------------------------------------------------------------
// Storage layout
// ----------------------------------------------------------------------------------------------------
uint256 private _status;
// ----------------------------------------------------------------------------------------------------
// Modifiers
// ----------------------------------------------------------------------------------------------------
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == _ENTERED) {
revert ReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
// src/core/interfaces/IOperableResource.sol
interface IOperableResource {
function owner() external view returns (address);
function operatorAddress() external view returns (address);
}
// src/core/interfaces/IResourceBasedTimelockedCall.sol
interface IResourceBasedTimelockedCall {
error Unauthorized();
error HashRequired();
error HashAlreadyEnqueued();
error HashNotEnqueued();
error TimelockInPlace();
error InvalidTimelockDuration();
error InvalidResourceAddress();
struct TimelockedCallInfo {
uint256 targetEpoch; // The unix epoch at which the hash can be consumed
address createdBy; // The address of the scheduler
}
/// @notice Triggers when a hash is scheduled for further execution
event HashScheduled(bytes32 h, address postedBy);
/// @notice Triggers when a hash is consumed by the address specified.
event HashConsumed(bytes32 h, address consumerAddress);
/// @notice Triggers when a hash is cancelled.
event HashCancelled(bytes32 h, address consumerAddress);
function schedule(bytes32 h) external;
function cancel(bytes32 h) external;
function consume(bytes32 h) external;
function hashExists(bytes32 h) external view returns (bool);
function getInfo(bytes32 h) external view returns (TimelockedCallInfo memory);
}
// src/core/ResourceBasedTimelockedCall.sol
/**
* @title Allows a resource to schedule and consume time-locked hashes.
*/
contract ResourceBasedTimelockedCall is IResourceBasedTimelockedCall, BaseReentrancy {
/// @dev A reasonable time-window for manipulating the block timestamp as a miner.
uint256 constant internal _TIMESTAMP_MANIPULATION_WINDOW = 5 minutes;
/// @notice The address of the operable smart contract.
IOperableResource public immutable RESOURCE;
/// @notice The time-lock duration of the consumer.
uint256 public immutable TIMELOCK_DURATION;
/// @notice The time-lock info of a given hash.
mapping (bytes32 => TimelockedCallInfo) public queue;
/// @dev Throws if the sender is not the expected resource address.
modifier onlyResource() {
if (msg.sender != address(RESOURCE)) revert Unauthorized();
_;
}
constructor(
address newResource,
uint256 newTimeLockDuration
) {
if (newTimeLockDuration < _TIMESTAMP_MANIPULATION_WINDOW) revert InvalidTimelockDuration();
RESOURCE = IOperableResource(newResource);
TIMELOCK_DURATION = newTimeLockDuration;
}
/**
* @notice Schedules a hash for further execution.
* @dev Throws if the sender is not the expected resource, nor the owner/operator of such resource.
* @param h Specifies the hash to schedule.
*/
function schedule(bytes32 h) external override nonReentrant {
if (h == bytes32(0)) revert HashRequired();
if (queue[h].createdBy != address(0)) revert HashAlreadyEnqueued();
queue[h] = TimelockedCallInfo({
createdBy: msg.sender,
targetEpoch: block.timestamp + TIMELOCK_DURATION
});
emit HashScheduled(h, msg.sender);
// Validate the message sender
_enforceValidSender();
}
/**
* @notice Cancels an existing hash.
* @param h Specifies the hash to cancel.
*/
function cancel(bytes32 h) external nonReentrant {
if (queue[h].createdBy == address(0)) revert HashNotEnqueued();
delete queue[h];
emit HashCancelled(h, msg.sender);
// Validate the message sender
_enforceValidSender();
}
/**
* @notice Consumes the hash specified.
* @dev Throws if the sender is not the expected resource.
* @param h Specifies the hash to consume.
*/
function consume(bytes32 h) external override nonReentrant onlyResource {
if (queue[h].targetEpoch < 1) revert HashNotEnqueued();
if (block.timestamp < queue[h].targetEpoch) revert TimelockInPlace();
delete queue[h];
emit HashConsumed(h, msg.sender);
}
/**
* @notice Indicates if the hash specified was enqueued.
* @param h Specifies the hash to evaluate.
* @return bool Returns true if the hash specified was enqueued.
*/
function hashExists(bytes32 h) external override view returns (bool) {
return queue[h].targetEpoch > 0;
}
/**
* @notice Gets the details of the hash specified.
* @param h Specifies the hash to evaluate.
* @return TimelockedCallInfo Returns a struct containing the details.
*/
function getInfo(bytes32 h) external override view returns (TimelockedCallInfo memory) {
return queue[h];
}
/// @dev Throws if the sender is not the expected resource, nor the owner/operator of such resource.
function _enforceValidSender() private view {
address theOwner = RESOURCE.owner();
address theOperator = RESOURCE.operatorAddress();
if (
(msg.sender != address(RESOURCE)) &&
(msg.sender != theOwner) &&
(msg.sender != theOperator)
) revert Unauthorized();
}
}
Submitted on: 2025-09-26 17:50:22
Comments
Log in to comment.
No comments yet.