Skip to content

Commit

Permalink
refactor: 💡 handling token timestamp check
Browse files Browse the repository at this point in the history
  • Loading branch information
MASDXI committed Feb 26, 2025
1 parent 4944ab0 commit 8f6e096
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 28 deletions.
53 changes: 33 additions & 20 deletions contracts/tokens/ERC721/ERC721EXPBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import {ERC721Enumerable} from "@openzeppelin/contracts/token/ERC721/extensions/
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

abstract contract ERC721EXPBase is ERC721, ERC721Enumerable, IERC7858 {
struct AssetStamp {
struct AssetTimeStamp {
uint256 start;
uint256 end;
}

mapping(uint256 => AssetStamp) private _tokensTimestamp;
mapping(uint256 => AssetTimeStamp) private _tokensTimeStamp;

constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {}

Expand All @@ -35,41 +35,54 @@ abstract contract ERC721EXPBase is ERC721, ERC721Enumerable, IERC7858 {
}

function _validation(uint256 tokenId) internal view returns (bool) {
if (_ownerOf(tokenId) == address(0)) return false;
AssetStamp memory timestamp = _tokensTimestamp[tokenId];
if (_ownerOf(tokenId) == address(0)) revert ERC721NonexistentToken(tokenId);
AssetTimeStamp memory timestamp = _tokensTimeStamp[tokenId];
uint256 current = _pointerProvider();
if (current < timestamp.start || current >= timestamp.end) {
// if start and end is {0, 0} mean token non-expirable and return false.
if (timestamp.start == 0 && timestamp.end == 0) {
return false;
} else {
return current >= timestamp.end;
}
// if start and end is {0, 0} mean token non-expirable and return true.
return true;
}

function _updateStamp(uint256 tokenId, uint64 start, uint64 end) internal {
if (start >= end) {
// @TODO revert ERC5007InvalidTime()
function _updateTimeStamp(uint256 tokenId, uint64 start, uint64 end) internal {
if ((start <= end) && (start != 0) && (end != 0)) {
revert ERC7858InvalidTimeStamp(start, end);
}
_tokensTimestamp[tokenId].start = start;
_tokensTimestamp[tokenId].end = end;
// @TODO emit tokenTimeSet(tokenId, start, end);
_tokensTimeStamp[tokenId].start = start;
_tokensTimeStamp[tokenId].end = end;

emit TokenExpiryUpdated(tokenId, start, end);
}

function _mintWithStamp(address to, uint256 tokenId, uint64 start, uint64 end) internal {
function _mintWithTimeStamp(address to, uint256 tokenId, uint64 start, uint64 end) internal {
_mint(to, tokenId);
_updateStamp(tokenId, start, end);
_updateTimeStamp(tokenId, start, end);
}

function _burnAndClearTimeStamp(uint256 tokenId) internal {
_burn(tokenId);
delete _tokensTimeStamp[tokenId];
}

/// @inheritdoc IERC7858
/**
* @dev See {IERC7858-startTime}.
*/
function startTime(uint256 tokenId) public view virtual override returns (uint256) {
return _tokensTimestamp[tokenId].start;
return _tokensTimeStamp[tokenId].start;
}

/// @inheritdoc IERC7858
/**
* @dev See {IERC7858-endTime}.
*/
function endTime(uint256 tokenId) public view virtual override returns (uint256) {
return _tokensTimestamp[tokenId].end;
return _tokensTimeStamp[tokenId].end;
}

/// @inheritdoc IERC7858
/**
* @dev See {IERC7858-isTokenExpired}.
*/
function isTokenExpired(uint256 tokenId) public view returns (bool) {
return _validation(tokenId);
}
Expand Down
18 changes: 11 additions & 7 deletions contracts/tokens/ERC721/extensions/ERC721EpochBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,14 @@ abstract contract ERC721EpochBase is Context, ERC165, IERC721, IERC721Errors, IE
// if the tokenId is not exist before minting it
if (to == address(0)) {
_tokenPointers[tokenId] = 0;
}
if (tokenPointer == 0) {
tokenPointer = pointer;
_tokenPointers[tokenId] = pointer;

emit TokenExpiryUpdated(tokenId, pointer, pointer + _getPointersInWindow());
} else {
if (tokenPointer == 0) {
tokenPointer = pointer;
_tokenPointers[tokenId] = pointer;
} else {
pointer = tokenPointer;
}
pointer = tokenPointer;
}
uint256 epoch = _getEpoch(pointer);

Expand Down Expand Up @@ -373,7 +374,10 @@ abstract contract ERC721EpochBase is Context, ERC165, IERC721, IERC721Errors, IE

/// @dev See {IERC7858-endTime}.
function endTime(uint256 tokenId) external view returns (uint256) {
return _tokenPointers[tokenId] + _getPointersInWindow();
uint256 startTimeCache = _tokenPointers[tokenId];
if (startTimeCache != 0) {
return startTimeCache + _getPointersInWindow();
}
}

/// @dev See {IERC7858Epoch-currentEpoch}.
Expand Down
16 changes: 15 additions & 1 deletion contracts/tokens/ERC721/interfaces/IERC7858.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ interface IERC7858 {
TIME_BASED // block.timestamp
}

/**
* @dev Emitted when the expiration date of a token is set or updated.
* @param tokenId The identifier of the token ERC721 `tokenId`.
* @param startTime The start time of the token (block number or timestamp based on `expiryType`).
* @param endTime The end time of the token (block number or timestamp based on `expiryType`).
*/
event TokenExpiryUpdated(
uint256 indexed tokenId,
uint256 indexed startTime,
uint256 indexed endTime
);

error ERC7858InvalidTimeStamp(uint256 start, uint256 end);

/**
* @dev Returns the type of the expiry.
* @return EXPIRY_TYPE Enum value indicating the unit of an expiry.
Expand All @@ -17,7 +31,7 @@ interface IERC7858 {

/**
* @dev Checks whether a specific token is expired.
* @param Id The identifier representing the tokenId.
* @param tokenId The identifier representing the tokenId.
* @return bool True if the token is expired, false otherwise.
*/
function isTokenExpired(uint256 tokenId) external view returns (bool);
Expand Down

0 comments on commit 8f6e096

Please sign in to comment.