From 5a54b00a05734e7854896e3076b545a43e511827 Mon Sep 17 00:00:00 2001 From: MASDXI Date: Thu, 24 Oct 2024 14:49:44 +0700 Subject: [PATCH] refactor: lint format, function name, and ERC1155 contract storage Signed-off-by: MASDXI --- .../abstracts/LightWeightSlidingWindow.sol | 8 ++-- contracts/abstracts/SlidingWindow.sol | 6 +-- contracts/devs/SlidingWindowDev.sol | 6 +-- contracts/tokens/ERC1155/ERC1155EXPBase.sol | 28 ++++++++------ .../ERC1155EXPNearestExpiryQuery.sol | 2 +- .../ERC1155/extensions/ERC1155Whitelist.sol | 2 +- contracts/tokens/ERC20/ERC20EXPBase.sol | 12 +++--- contracts/tokens/ERC721/ERC721EXPBase.sol | 37 ++++++++++++++++--- .../ERC721EXPNearestExpiryQuery.sol | 4 +- .../ERC721/extensions/ERC721Whitelist.sol | 2 +- .../ERC20EXPWhitelist/Whitelist.test.ts | 2 +- 11 files changed, 71 insertions(+), 38 deletions(-) diff --git a/contracts/abstracts/LightWeightSlidingWindow.sol b/contracts/abstracts/LightWeightSlidingWindow.sol index 5ad3a29..97cfcf1 100644 --- a/contracts/abstracts/LightWeightSlidingWindow.sol +++ b/contracts/abstracts/LightWeightSlidingWindow.sol @@ -5,12 +5,12 @@ pragma solidity >=0.8.0 <0.9.0; /// @author Kiwari Labs import {ISlidingWindow} from "../interfaces/ISlidingWindow.sol"; -import {SlidingWindow as slide} from "../utils/LightWeightSlidingWindow.sol"; +import {SlidingWindow as Slide} from "../utils/LightWeightSlidingWindow.sol"; abstract contract SlidingWindow is ISlidingWindow { - using slide for slide.SlidingWindowState; + using Slide for Slide.SlidingWindowState; - slide.SlidingWindowState private _slidingWindow; + Slide.SlidingWindowState private _slidingWindow; constructor(uint256 blockNumber_, uint16 blockTime_, uint8 frameSize_) { _slidingWindow._startBlockNumber = blockNumber_ != 0 ? blockNumber_ : _blockNumberProvider(); @@ -128,7 +128,7 @@ abstract contract SlidingWindow is ISlidingWindow { /// @dev This function returns the `_slotSize` attribute from the provided sliding window state `self`, /// which represents the number of slots per era in the sliding window configuration. function _getSlotPerEra() internal pure returns (uint8) { - return slide.getSlotPerEra(); + return Slide.getSlotPerEra(); } /// @inheritdoc ISlidingWindow diff --git a/contracts/abstracts/SlidingWindow.sol b/contracts/abstracts/SlidingWindow.sol index ad41ad2..e0cf21a 100644 --- a/contracts/abstracts/SlidingWindow.sol +++ b/contracts/abstracts/SlidingWindow.sol @@ -5,12 +5,12 @@ pragma solidity >=0.8.0 <0.9.0; /// @author Kiwari Labs import {ISlidingWindow} from "../interfaces/ISlidingWindow.sol"; -import {SlidingWindow as slide} from "../utils/SlidingWindow.sol"; +import {SlidingWindow as Slide} from "../utils/SlidingWindow.sol"; abstract contract SlidingWindow is ISlidingWindow { - using slide for slide.SlidingWindowState; + using Slide for Slide.SlidingWindowState; - slide.SlidingWindowState private _slidingWindow; + Slide.SlidingWindowState private _slidingWindow; /// @notice Constructs the Sliding Window Contract with the initial parameters. /// @dev Initializes the sliding window with the provided parameters. diff --git a/contracts/devs/SlidingWindowDev.sol b/contracts/devs/SlidingWindowDev.sol index be534bb..433a51e 100644 --- a/contracts/devs/SlidingWindowDev.sol +++ b/contracts/devs/SlidingWindowDev.sol @@ -5,12 +5,12 @@ pragma solidity >=0.8.0 <0.9.0; /// @author Kiwari Labs import {ISlidingWindow} from "../interfaces/ISlidingWindow.sol"; -import {SlidingWindow as slide} from "./LibSlidingWindowDev.sol"; +import {SlidingWindow as Slide} from "./LibSlidingWindowDev.sol"; abstract contract SlidingWindow is ISlidingWindow { - using slide for slide.SlidingWindowState; + using Slide for Slide.SlidingWindowState; - slide.SlidingWindowState private _slidingWindow; + Slide.SlidingWindowState private _slidingWindow; /// @notice Constructs the Sliding Window Contract with the initial parameters. /// @dev Initializes the sliding window with the provided parameters. diff --git a/contracts/tokens/ERC1155/ERC1155EXPBase.sol b/contracts/tokens/ERC1155/ERC1155EXPBase.sol index e79e718..722e8c5 100644 --- a/contracts/tokens/ERC1155/ERC1155EXPBase.sol +++ b/contracts/tokens/ERC1155/ERC1155EXPBase.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.0 <0.9.0; /// @title ERC1155EXP Base abstract contract /// @author Kiwari Labs -import {SlidingWindow} from "../../abstracts/SlidingWindow.sol"; +import {SlidingWindow as Slide} from "../../utils/SlidingWindow.sol"; import {SortedCircularDoublyLinkedList as SCDLL} from "../../utils/LightWeightSortedCircularDoublyLinkedList.sol"; import {IERC1155EXPBase} from "../../interfaces/IERC1155EXPBase.sol"; import {IERC1155} from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; @@ -14,8 +14,9 @@ import {IERC1155MetadataURI} from "@openzeppelin/contracts/token/ERC1155/extensi /// Since NFTs are always unique with a balance of 1, tracking expiration or balances based on FIFO is less relevant. /// However, FIFO method can still be useful for managing fungible tokens within the same contract. -abstract contract ERC1155EXPBase is IERC1155, IERC1155EXPBase, IERC1155MetadataURI, SlidingWindow { +abstract contract ERC1155EXPBase is IERC1155, IERC1155EXPBase, IERC1155MetadataURI { using SCDLL for SCDLL.List; + using Slide for Slide.SlidingWindowState; struct Slot { uint256 slotBalance; @@ -23,20 +24,25 @@ abstract contract ERC1155EXPBase is IERC1155, IERC1155EXPBase, IERC1155MetadataU SCDLL.List list; } + uint24 private BLOCK_TIME; // shared blocktime configuration for all tokenIds + mapping(uint256 id => mapping(address account => mapping(uint256 era => mapping(uint8 slot => Slot)))) private _balances; + mapping(uint256 id => Slide.SlidingWindowState) private _slidingWindowTokens; + // initialized default expired period if use _mint(to , id, value, data) + // passing config when mint with _mint(to, id, value, data) + mapping(address account => mapping(address operator => bool)) private _operatorApprovals; /// @notice Constructor function to initialize the token contract with specified parameters. - /// @dev Initializes the token contract by setting the name, symbol, and initializing the sliding window parameters. - /// @param blockNumber_ The starting block number for the sliding window. - /// @param blockTime_ The duration of each block in milliseconds.. - constructor( - uint256 blockNumber_, - uint16 blockTime_, - uint8 frameSize_, - uint8 slotSize_ - ) SlidingWindow(blockNumber_, blockTime_, frameSize_, slotSize_) {} + /// @dev Initializes the token contract by setting the name, symbol. + constructor() { + // initialized contract for default configuration for all token that not pass config. + } + + function _blockNumberProvider() internal view virtual returns (uint256) { + return block.number; + } // @TODO finish other method } diff --git a/contracts/tokens/ERC1155/extensions/ERC1155EXPNearestExpiryQuery.sol b/contracts/tokens/ERC1155/extensions/ERC1155EXPNearestExpiryQuery.sol index 06a2278..3c84e61 100644 --- a/contracts/tokens/ERC1155/extensions/ERC1155EXPNearestExpiryQuery.sol +++ b/contracts/tokens/ERC1155/extensions/ERC1155EXPNearestExpiryQuery.sol @@ -12,4 +12,4 @@ abstract contract ERC1155EXPNearestExpiryQuery is ERC1155EXPBase { uint256 _spendableBalances; uint256 _unspendableBalances; } -} \ No newline at end of file +} diff --git a/contracts/tokens/ERC1155/extensions/ERC1155Whitelist.sol b/contracts/tokens/ERC1155/extensions/ERC1155Whitelist.sol index 6db06f4..53b2adb 100644 --- a/contracts/tokens/ERC1155/extensions/ERC1155Whitelist.sol +++ b/contracts/tokens/ERC1155/extensions/ERC1155Whitelist.sol @@ -12,4 +12,4 @@ abstract contract ERC1155EXPWhitelist is ERC1155EXPBase { uint256 _spendableBalances; uint256 _unspendableBalances; } -} \ No newline at end of file +} diff --git a/contracts/tokens/ERC20/ERC20EXPBase.sol b/contracts/tokens/ERC20/ERC20EXPBase.sol index be5f17d..e76b271 100644 --- a/contracts/tokens/ERC20/ERC20EXPBase.sol +++ b/contracts/tokens/ERC20/ERC20EXPBase.sol @@ -27,7 +27,7 @@ abstract contract ERC20EXPBase is Context, IERC20, IERC20Metadata, IERC20Errors, mapping(address account => mapping(uint256 era => mapping(uint8 slot => Slot))) private _balances; mapping(address account => mapping(address spneder => uint256 balance)) private _allowances; - mapping(uint256 blockNumber => uint256 balance) private _worldBlockBalance; + mapping(uint256 blockNumber => uint256 balance) private _worldBlockBalances; /// @notice Constructor function to initialize the token contract with specified parameters. /// @dev Initializes the token contract by setting the name, symbol, and initializing the sliding window parameters. @@ -166,7 +166,7 @@ abstract contract ERC20EXPBase is Context, IERC20, IERC20Metadata, IERC20Errors, _recipient.blockBalances[blockNumberCache] += value; } _recipient.list.insert(blockNumberCache, ("")); - _worldBlockBalance[blockNumberCache] += value; + _worldBlockBalances[blockNumberCache] += value; } else { // Burn token. (uint256 fromEra, uint256 toEra, uint8 fromSlot, uint8 toSlot) = _frame(blockNumberCache); @@ -192,7 +192,7 @@ abstract contract ERC20EXPBase is Context, IERC20, IERC20Metadata, IERC20Errors, pendingValue -= balanceCache; _spender.slotBalance -= balanceCache; _spender.blockBalances[key] -= balanceCache; - _worldBlockBalance[key] -= balanceCache; + _worldBlockBalances[key] -= balanceCache; } key = _spender.list.next(key); _spender.list.remove(_spender.list.previous(key)); @@ -200,7 +200,7 @@ abstract contract ERC20EXPBase is Context, IERC20, IERC20Metadata, IERC20Errors, unchecked { _spender.slotBalance -= pendingValue; _spender.blockBalances[key] -= pendingValue; - _worldBlockBalance[key] -= pendingValue; + _worldBlockBalances[key] -= pendingValue; } pendingValue = 0; } @@ -410,11 +410,11 @@ abstract contract ERC20EXPBase is Context, IERC20, IERC20Metadata, IERC20Errors, } /// @notice Retrieves the total balance stored at a specific block. - /// @dev This function returns the balance of the given block from the internal `_worldBlockBalance` mapping. + /// @dev This function returns the balance of the given block from the internal `_worldBlockBalances` mapping. /// @param blockNumber The block number for which the balance is being queried. /// @return balance The total balance stored at the given block number. function getBlockBalance(uint256 blockNumber) external view virtual returns (uint256) { - return _worldBlockBalance[blockNumber]; + return _worldBlockBalances[blockNumber]; } /// @inheritdoc IERC20Metadata diff --git a/contracts/tokens/ERC721/ERC721EXPBase.sol b/contracts/tokens/ERC721/ERC721EXPBase.sol index c79603c..204f418 100644 --- a/contracts/tokens/ERC721/ERC721EXPBase.sol +++ b/contracts/tokens/ERC721/ERC721EXPBase.sol @@ -21,7 +21,15 @@ import {ERC721Utils} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Util /// @notice First-In-First-Out (FIFO) not suitable for ERC721 cause each token is unique it's need to be selective to spend. /// However we still maintain list of blockNumber that store token is sorted list. -abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC721EXPBase, IERC721Metadata, SlidingWindow { +abstract contract ERC721EXPBase is + Context, + ERC165, + IERC721, + IERC721Errors, + IERC721EXPBase, + IERC721Metadata, + SlidingWindow +{ using EnumSet for EnumSet.UintSet; using SCDLL for SCDLL.List; using Strings for uint256; @@ -37,8 +45,8 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC } mapping(address account => mapping(uint256 era => mapping(uint8 slot => Slot))) private _balances; - mapping(uint256 tokenId => uint256 blockNumber) private _mintedBlockOfToken; - mapping(uint256 blockNumber => uint256 balance) private _worldBlockBalance; + mapping(uint256 tokenId => uint256 blockNumber) private _mintedBlockOfTokens; + mapping(uint256 blockNumber => uint256 balance) private _worldBlockBalances; mapping(uint256 tokenId => address) private _owners; mapping(uint256 tokenId => address) private _tokenApprovals; @@ -134,7 +142,7 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC } function _isExpired(uint256 tokenId) internal view returns (bool) { - if (_blockNumberProvider() - _mintedBlockOfToken[tokenId] >= _getFrameSizeInBlockLength()) { + if (_blockNumberProvider() - _worldBlockBalances[tokenId] >= _getFrameSizeInBlockLength()) { return true; } } @@ -216,7 +224,7 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC // revert ERC721ExpiredToken(tokenId); } address from = _ownerOf(tokenId); - uint256 mintedBlockCache = _mintedBlockOfToken[tokenId]; + uint256 mintedBlockCache = _mintedBlockOfTokens[tokenId]; (uint256 era, uint8 slot) = _calculateEraAndSlot(mintedBlockCache); Slot storage _spender = _balances[from][era][slot]; @@ -269,6 +277,7 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC if (previousOwner != address(0)) { revert ERC721InvalidSender(address(0)); } + _worldBlockBalances[_blockNumberProvider()] += 1; } function _burn(uint256 tokenId) internal { @@ -276,6 +285,7 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC if (previousOwner == address(0)) { revert ERC721NonexistentToken(tokenId); } + _worldBlockBalances[_blockNumberProvider()] -= 1; } function _transfer(address from, address to, uint256 tokenId) internal { @@ -340,6 +350,15 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC } } + function balanceOf(address owner) public view virtual returns (uint256) { + if (owner == address(0)) { + revert ERC721InvalidOwner(address(0)); + } + uint256 blockNumberCache = _blockNumberProvider(); + (uint256 fromEra, uint256 toEra, uint8 fromSlot, uint8 toSlot) = _frame(blockNumberCache); + return _lookBackBalance(owner, fromEra, toEra, fromSlot, toSlot, blockNumberCache); + } + function _safeTransfer(address from, address to, uint256 tokenId) internal { _safeTransfer(from, to, tokenId, ""); } @@ -358,6 +377,14 @@ abstract contract ERC721EXPBase is Context, ERC165, IERC721, IERC721Errors, IERC ERC721Utils.checkOnERC721Received(_msgSender(), address(0), to, tokenId, data); } + /// @notice Retrieves the total balance stored at a specific block. + /// @dev This function returns the balance of the given block from the internal `_worldBlockBalances` mapping. + /// @param blockNumber The block number for which the balance is being queried. + /// @return balance The total balance stored at the given block number. + function getBlockBalance(uint256 blockNumber) external view virtual returns (uint256) { + return _worldBlockBalances[blockNumber]; + } + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return interfaceId == type(IERC721).interfaceId || diff --git a/contracts/tokens/ERC721/extensions/ERC721EXPNearestExpiryQuery.sol b/contracts/tokens/ERC721/extensions/ERC721EXPNearestExpiryQuery.sol index fb6e316..4fbd753 100644 --- a/contracts/tokens/ERC721/extensions/ERC721EXPNearestExpiryQuery.sol +++ b/contracts/tokens/ERC721/extensions/ERC721EXPNearestExpiryQuery.sol @@ -15,13 +15,13 @@ abstract contract ERC721EXPNearestExpiryQuery is ERC721EXPBase { /// @param account The address of the account whose unexpired block balance is being queried. /// @return tokenIds The array of tokenId at the nearest unexpired block for the specified account. /// @return blockNumber The block number at which the nearest unexpired balance was found. - function _getNearestExpireBalanceOf(address account) internal view returns (uint256 [] memory, uint256) { + function _getNearestExpireBalanceOf(address account) internal view returns (uint256[] memory, uint256) { uint256 blockNumberCache = _blockNumberProvider(); uint256 blockLengthCache = _getFrameSizeInBlockLength(); (uint256 fromEra, , uint8 fromSlot, ) = _safeFrame(blockNumberCache); Slot storage _account = _slotOf(account, fromEra, fromSlot); uint256 blockNumberIndexCache = _account.list.head(); - uint256 [] memory tokenIds; + uint256[] memory tokenIds; unchecked { while (blockNumberCache - blockNumberIndexCache >= blockLengthCache) { if (blockNumberCache == 0) { diff --git a/contracts/tokens/ERC721/extensions/ERC721Whitelist.sol b/contracts/tokens/ERC721/extensions/ERC721Whitelist.sol index 36a4052..25bdbdd 100644 --- a/contracts/tokens/ERC721/extensions/ERC721Whitelist.sol +++ b/contracts/tokens/ERC721/extensions/ERC721Whitelist.sol @@ -12,4 +12,4 @@ abstract contract ERC721EXPWhitelist is ERC721EXPBase { uint256 _spendableBalances; uint256 _unspendableBalances; } -} \ No newline at end of file +} diff --git a/test/tokens/ERC20/extensions/ERC20EXPWhitelist/Whitelist.test.ts b/test/tokens/ERC20/extensions/ERC20EXPWhitelist/Whitelist.test.ts index 3a3b2ce..c88bdf3 100644 --- a/test/tokens/ERC20/extensions/ERC20EXPWhitelist/Whitelist.test.ts +++ b/test/tokens/ERC20/extensions/ERC20EXPWhitelist/Whitelist.test.ts @@ -3,7 +3,7 @@ import {deployERC20EXPWhitelist} from "../../../../utils.test"; import { EVENT_WHITELIST_GRANTED, EVENT_WHITELIST_REVOKED, - ERROR_EXIST_IN_WHITELIST, + ERROR_EXIST_IN_WHITELIST, ERROR_NOT_EXIST_IN_WHITELIST, } from "../../../../constant.test";