From 9662d532f0b4d81e2a9d6fe5d113095a1e4a695c Mon Sep 17 00:00:00 2001 From: ogarciarevett Date: Thu, 10 Oct 2024 01:22:06 +0200 Subject: [PATCH] Feat: Splitting Reward contract for only native rewards --- contracts/libraries/LibRewards.sol | 53 ++++++ contracts/soulbounds/RewardsNative.sol | 178 +++--------------- .../LootDrop.t.sol => Rewards/Rewards.t.sol} | 0 .../RewardsAddToken.t.sol} | 0 .../RewardsBurn.t.sol} | 0 .../RewardsClaim.t.sol} | 0 .../RewardsMint.t.sol} | 0 .../RewardsTransfer.t.sol} | 0 .../RewardsWithdraw.t.sol} | 0 9 files changed, 75 insertions(+), 156 deletions(-) create mode 100644 contracts/libraries/LibRewards.sol rename test/{LootDropHQ/LootDrop.t.sol => Rewards/Rewards.t.sol} (100%) rename test/{LootDropHQ/LootDropAddToken.t.sol => Rewards/RewardsAddToken.t.sol} (100%) rename test/{LootDropHQ/LootDropBurn.t.sol => Rewards/RewardsBurn.t.sol} (100%) rename test/{LootDropHQ/LootDropClaim.t.sol => Rewards/RewardsClaim.t.sol} (100%) rename test/{LootDropHQ/LootDropMint.t.sol => Rewards/RewardsMint.t.sol} (100%) rename test/{LootDropHQ/LootDropTransfer.t.sol => Rewards/RewardsTransfer.t.sol} (100%) rename test/{LootDropHQ/LootDropWithdraw.t.sol => Rewards/RewardsWithdraw.t.sol} (100%) diff --git a/contracts/libraries/LibRewards.sol b/contracts/libraries/LibRewards.sol new file mode 100644 index 0000000..9e12c77 --- /dev/null +++ b/contracts/libraries/LibRewards.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +// @author Summon.xyz Team - https://summon.xyz +// @contributors: [ @ogarciarevett, @vasinl124] +//.................................................................................................................................................... +//....................&&&&&&.......................................................................................................................... +//..................&&&&&&&&&&&....................................................................................................................... +//..............X.....&&&&&&&&&&&&.................................................................................................................... +//............&&&&&&.....&&&&&&&&&&&.................................................................................................................. +//............&&&&&&&&&.....&&&&&..................................................................................................................... +//............&&&&&&&&&&&&.........&.............&&&&&&&&&&&&..&&&&....&&&&.&&&&&&&&..&&&&&&&.&&&&&&&&..&&&&&&&&.&&&&&&&&&&&&.&&&&&....&&&&........... +//...............&&&&&&&&&&&&.....&&$............&&&&..........&&&&....&&&&.&&&&&&&&.&&&&&&&&..&&&&&&&&.&&&&&&&&.&&&&&&&&&&&&.&&&&&&&..&&&&........... +//............&.....&&&&&&&&&&&&..................&&&&&&&&&&&..&&&&....&&&&.&&&&..&&&&&&.&&&&..&&&&.&&&&&&..&&&&.&&&&....&&&&.&&&&.&&&&&&&&........... +//............&&.......&&&&&&&&&&&&......................&&&&..&&&&&&&&&&&&.&&&&..&&&&&..&&&&..&&&&..&&&&...&&&&.&&&&&&&&&&&&.&&&&...&&&&&&........... +//................&&&.....&&&&&&&&&&+............&&&&&&&&&&&&...&&&&&&&&&&..&&&&...&&&&..&&&&.&&&&&..&&&&...&&&&.&&&&&&&&&&&&.&&&&....&&&&&........... +//.............&&&&&&&&&.....&&&&&&&.................................................................................................................. +//.............&&&&&&&&&&&&.....&&&................................................................................................................... +//.................&&&&&&&&&&&........................................................................................................................ +//....................&&&&&&&......................................................................................................................... +//.................................................................................................................................................... + +library LibRewards { + + struct RewardTokenOld { + uint256 tokenId; + string tokenUri; + uint256 rewardAmount; // depending of the erc20 token decimal + bool isEther; + } + + struct Reward { + uint256 rewardAmount; + } + + struct RewardToken { + uint256 tokenId; + string tokenUri; + Reward[] rewards; + uint256 maxSupply; + } +} + +library TestLibItems { + enum Tier { + NONE, + COMMON, + UNCOMMON, + RARE, + LEGENDARY, + MYTHICAL + } +} diff --git a/contracts/soulbounds/RewardsNative.sol b/contracts/soulbounds/RewardsNative.sol index b712a6e..6ecc37c 100644 --- a/contracts/soulbounds/RewardsNative.sol +++ b/contracts/soulbounds/RewardsNative.sol @@ -1,8 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.24; - - // @author Summon.xyz Team - https://summon.xyz // @contributors: [ @ogarciarevett, @vasinl124] //.................................................................................................................................................... @@ -22,16 +20,8 @@ pragma solidity ^0.8.24; //....................&&&&&&&......................................................................................................................... //.................................................................................................................................................... -import { ERC1155 } from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; -import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; -import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { ERC1155Burnable } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol"; -import { ERC1155Supply } from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol"; -import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; -import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; +import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol"; import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; @@ -40,7 +30,7 @@ import { Initializable } from "@openzeppelin/contracts/proxy/utils/Initializable import { AdminERC1155Soulbound } from "../soulbounds/AdminERC1155Soulbound.sol"; import { ERCWhitelistSignature } from "../ercs/ERCWhitelistSignature.sol"; -import { LibItems } from "../libraries/LibItems.sol"; +import { LibRewards } from "../libraries/LibRewards.sol"; error AddressIsZero(); error InvalidTokenId(); @@ -61,8 +51,7 @@ contract Rewards is Pausable, ReentrancyGuard, Initializable, - ERC1155Holder, - ERC721Holder + ERC1155Holder { bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); bytes32 public constant MANAGER_ROLE = keccak256("MANAGER_ROLE"); @@ -74,10 +63,9 @@ contract Rewards is uint256[] public itemIds; mapping(uint256 => bool) private tokenExists; - mapping(uint256 => LibItems.RewardToken) public tokenRewards; + mapping(uint256 => LibRewards.RewardToken) public tokenRewards; mapping(uint256 => bool) public isTokenMintPaused; // tokenId => bool - default is false mapping(uint256 => bool) public isClaimRewardPaused; // tokenId => bool - default is false - mapping(uint256 => mapping(uint256 => uint256)) private erc721RewardCurrentIndex; // rewardTokenId => rewardIndex => erc721RewardCurrentIndex mapping(uint256 => uint256) public currentRewardSupply; // rewardTokenId => currentRewardSupply event TokenAdded(uint256 indexed tokenId); @@ -93,6 +81,7 @@ contract Rewards is function initialize( address _devWallet, + address _adminWallet, address _managerWallet, address _minterWallet, address _rewardTokenAddress @@ -107,7 +96,7 @@ contract Rewards is } rewardTokenContract = AdminERC1155Soulbound(_rewardTokenAddress); - _grantRole(DEFAULT_ADMIN_ROLE, _devWallet); + _grantRole(DEFAULT_ADMIN_ROLE, _adminWallet); _grantRole(DEV_CONFIG_ROLE, _devWallet); _grantRole(MANAGER_ROLE, _managerWallet); _grantRole(MINTER_ROLE, _minterWallet); @@ -151,7 +140,7 @@ contract Rewards is _unpause(); } - function _validateTokenInputs(LibItems.RewardToken calldata _token) private view { + function _validateTokenInputs(LibRewards.RewardToken calldata _token) private view { if (_token.maxSupply == 0) { revert InvalidAmount(); } @@ -163,42 +152,18 @@ contract Rewards is if (isTokenExist(_token.tokenId)) { revert DupTokenId(); } - - for (uint256 i = 0; i < _token.rewards.length; i++) { - LibItems.Reward memory reward = _token.rewards[i]; - if (reward.rewardType != LibItems.RewardType.ETHER) { - if (reward.rewardTokenAddress == address(0)) { - revert AddressIsZero(); - } - } - - if (reward.rewardType == LibItems.RewardType.ERC721) { - if ( - reward.rewardTokenIds.length == 0 || - reward.rewardTokenIds.length != reward.rewardAmount * _token.maxSupply - ) { - revert InvalidInput(); - } - } - - if (reward.rewardType != LibItems.RewardType.ERC721 && reward.rewardAmount == 0) { - revert InvalidAmount(); - } - } } - function _calculateETHRequiredForToken(LibItems.RewardToken calldata _token) private pure returns (uint256) { + function _calculateETHRequiredForToken(LibRewards.RewardToken calldata _token) private pure returns (uint256) { uint256 totalETHRequired; for (uint256 i = 0; i < _token.rewards.length; i++) { - LibItems.Reward memory reward = _token.rewards[i]; - if (reward.rewardType == LibItems.RewardType.ETHER) { - totalETHRequired += reward.rewardAmount; - } + LibRewards.Reward memory reward = _token.rewards[i]; + totalETHRequired += reward.rewardAmount; } return totalETHRequired * _token.maxSupply; } - function _createTokenAndDepositRewards(LibItems.RewardToken calldata _token) private { + function _createTokenAndDepositRewards(LibRewards.RewardToken calldata _token) private { // have to approve all the assets first // Validate token inputs _validateTokenInputs(_token); @@ -211,26 +176,10 @@ contract Rewards is address _from = _msgSender(); address _to = address(this); - for (uint256 i = 0; i < _token.rewards.length; i++) { - LibItems.Reward memory reward = _token.rewards[i]; - if (reward.rewardType == LibItems.RewardType.ERC20) { - IERC20 token = IERC20(reward.rewardTokenAddress); - SafeERC20.safeTransferFrom(token, _from, _to, reward.rewardAmount * _token.maxSupply); - } else if (reward.rewardType == LibItems.RewardType.ERC721) { - IERC721 token = IERC721(reward.rewardTokenAddress); - for (uint256 j = 0; j < reward.rewardTokenIds.length; j++) { - _transferERC721(token, _from, _to, reward.rewardTokenIds[j]); - } - } else if (reward.rewardType == LibItems.RewardType.ERC1155) { - IERC1155 token = IERC1155(reward.rewardTokenAddress); - _transferERC1155(token, _from, _to, reward.rewardTokenId, reward.rewardAmount * _token.maxSupply); - } - } - emit TokenAdded(_token.tokenId); } - function createTokenAndDepositRewards(LibItems.RewardToken calldata _token) public payable onlyRole(MANAGER_ROLE) { + function createTokenAndDepositRewards(LibRewards.RewardToken calldata _token) public payable onlyRole(MANAGER_ROLE) { uint256 _ethRequired = _calculateETHRequiredForToken(_token); if (msg.value < _ethRequired) { @@ -241,7 +190,7 @@ contract Rewards is } function createMultipleTokensAndDepositRewards( - LibItems.RewardToken[] calldata _tokens + LibRewards.RewardToken[] calldata _tokens ) external payable onlyRole(MANAGER_ROLE) { uint256 totalETHRequired; @@ -271,42 +220,18 @@ contract Rewards is /** * @dev Allows the contract owner to withdraw all available assets from the contract. - * @param _rewardType The type of reward to withdraw. * @param _to The address to send the assets to. - * @param _tokenAddress The address of the token to withdraw. (required for ERC20, ERC721, and ERC1155 tokens) - * @param _tokenIds The token IDs to withdraw. (required for ERC721 and ERC1155 tokens) * @param _amounts The amounts to withdraw. (required for ETHER, ERC20, and ERC1155 tokens) */ function withdrawAssets( - LibItems.RewardType _rewardType, address _to, - address _tokenAddress, // required for ERC20, ERC721, and ERC1155 - uint256[] calldata _tokenIds, // required for ERC721 and ERC1155 - uint256[] calldata _amounts // required for ETHER, ERC20, and ERC1155 + uint256[] calldata _amounts ) external onlyRole(MANAGER_ROLE) { if (_to == address(0)) { revert AddressIsZero(); } - address _from = address(this); - - if (_rewardType == LibItems.RewardType.ETHER) { - _transferEther(payable(_to), _amounts[0]); - } else if (_rewardType == LibItems.RewardType.ERC20) { - _transferERC20(IERC20(_tokenAddress), _to, _amounts[0]); - } else if (_rewardType == LibItems.RewardType.ERC721) { - IERC721 token = IERC721(_tokenAddress); - for (uint256 i = 0; i < _tokenIds.length; i++) { - _transferERC721(token, _from, _to, _tokenIds[i]); - } - } else if (_rewardType == LibItems.RewardType.ERC1155) { - if (_tokenIds.length != _amounts.length) { - revert InvalidLength(); - } - for (uint256 i = 0; i < _tokenIds.length; i++) { - _transferERC1155(IERC1155(_tokenAddress), _from, _to, _tokenIds[i], _amounts[i]); - } - } + _transferEther(payable(_to), _amounts[0]); } function _transferEther(address payable _to, uint256 _amount) private { @@ -320,23 +245,6 @@ contract Rewards is } } - function _transferERC20(IERC20 _token, address _to, uint256 _amount) private { - uint256 balanceInContract = _token.balanceOf(address(this)); - if (balanceInContract < _amount) { - revert InsufficientBalance(); - } - - SafeERC20.safeTransfer(_token, _to, _amount); - } - - function _transferERC721(IERC721 _token, address _from, address _to, uint256 _tokenId) private { - _token.safeTransferFrom(_from, _to, _tokenId); - } - - function _transferERC1155(IERC1155 _token, address _from, address _to, uint256 _tokenId, uint256 _amount) private { - _token.safeTransferFrom(_from, _to, _tokenId, _amount, ""); - } - function claimReward(uint256 _tokenId) external nonReentrant whenNotPaused { _claimReward(_msgSender(), _tokenId); } @@ -347,12 +255,6 @@ contract Rewards is } } - function adminClaimReward(address _to, uint256[] calldata _tokenIds) external onlyRole(MANAGER_ROLE) whenNotPaused { - for (uint256 i = 0; i < _tokenIds.length; i++) { - _claimReward(_to, _tokenIds[i]); - } - } - function _claimReward(address _to, uint256 _rewardTokenId) private { if (isClaimRewardPaused[_rewardTokenId]) { revert ClaimRewardPaused(); @@ -374,37 +276,13 @@ contract Rewards is } function _distributeReward(address _to, uint256 _rewardTokenId) private { - LibItems.RewardToken memory _rewardToken = tokenRewards[_rewardTokenId]; - LibItems.Reward[] memory rewards = _rewardToken.rewards; + LibRewards.RewardToken memory _rewardToken = tokenRewards[_rewardTokenId]; + LibRewards.Reward[] memory rewards = _rewardToken.rewards; for (uint256 i = 0; i < rewards.length; i++) { - LibItems.Reward memory reward = rewards[i]; + LibRewards.Reward memory reward = rewards[i]; address _from = address(this); - - if (reward.rewardType == LibItems.RewardType.ETHER) { - _transferEther(payable(_to), reward.rewardAmount); - } else if (reward.rewardType == LibItems.RewardType.ERC20) { - _transferERC20(IERC20(reward.rewardTokenAddress), _to, reward.rewardAmount); - } else if (reward.rewardType == LibItems.RewardType.ERC721) { - uint256 currentIndex = erc721RewardCurrentIndex[_rewardTokenId][i]; - uint256[] memory tokenIds = reward.rewardTokenIds; - for (uint256 j = 0; j < reward.rewardAmount; j++) { - if (currentIndex >= tokenIds.length) { - revert InsufficientBalance(); - } - _transferERC721(IERC721(reward.rewardTokenAddress), _from, _to, tokenIds[currentIndex + j]); - } - - erc721RewardCurrentIndex[_rewardTokenId][i] += reward.rewardAmount; - } else if (reward.rewardType == LibItems.RewardType.ERC1155) { - _transferERC1155( - IERC1155(reward.rewardTokenAddress), - _from, - _to, - reward.rewardTokenId, - reward.rewardAmount - ); - } + _transferEther(payable(_to), reward.rewardAmount); } emit Claimed(_to, _rewardTokenId, 1); @@ -482,29 +360,17 @@ contract Rewards is returns ( string memory tokenUri, uint256 maxSupply, - LibItems.RewardType[] memory rewardTypes, - uint256[] memory rewardAmounts, - address[] memory rewardTokenAddresses, - uint256[][] memory rewardTokenIds, - uint256[] memory rewardTokenId + uint256[] memory rewardAmounts ) { tokenUri = tokenRewards[tokenId].tokenUri; maxSupply = tokenRewards[tokenId].maxSupply; - LibItems.Reward[] memory rewards = tokenRewards[tokenId].rewards; + LibRewards.Reward[] memory rewards = tokenRewards[tokenId].rewards; - rewardTypes = new LibItems.RewardType[](rewards.length); rewardAmounts = new uint256[](rewards.length); - rewardTokenAddresses = new address[](rewards.length); - rewardTokenIds = new uint256[][](rewards.length); - rewardTokenId = new uint256[](rewards.length); for (uint i = 0; i < rewards.length; i++) { - rewardTypes[i] = rewards[i].rewardType; rewardAmounts[i] = rewards[i].rewardAmount; - rewardTokenAddresses[i] = rewards[i].rewardTokenAddress; - rewardTokenIds[i] = rewards[i].rewardTokenIds; - rewardTokenId[i] = rewards[i].rewardTokenId; } } @@ -563,7 +429,7 @@ contract Rewards is // Fallback function is called when msg.data is not empty fallback() external payable {} - function adminVerifySignature( + function devVerifySignature( address to, uint256 nonce, bytes calldata data, diff --git a/test/LootDropHQ/LootDrop.t.sol b/test/Rewards/Rewards.t.sol similarity index 100% rename from test/LootDropHQ/LootDrop.t.sol rename to test/Rewards/Rewards.t.sol diff --git a/test/LootDropHQ/LootDropAddToken.t.sol b/test/Rewards/RewardsAddToken.t.sol similarity index 100% rename from test/LootDropHQ/LootDropAddToken.t.sol rename to test/Rewards/RewardsAddToken.t.sol diff --git a/test/LootDropHQ/LootDropBurn.t.sol b/test/Rewards/RewardsBurn.t.sol similarity index 100% rename from test/LootDropHQ/LootDropBurn.t.sol rename to test/Rewards/RewardsBurn.t.sol diff --git a/test/LootDropHQ/LootDropClaim.t.sol b/test/Rewards/RewardsClaim.t.sol similarity index 100% rename from test/LootDropHQ/LootDropClaim.t.sol rename to test/Rewards/RewardsClaim.t.sol diff --git a/test/LootDropHQ/LootDropMint.t.sol b/test/Rewards/RewardsMint.t.sol similarity index 100% rename from test/LootDropHQ/LootDropMint.t.sol rename to test/Rewards/RewardsMint.t.sol diff --git a/test/LootDropHQ/LootDropTransfer.t.sol b/test/Rewards/RewardsTransfer.t.sol similarity index 100% rename from test/LootDropHQ/LootDropTransfer.t.sol rename to test/Rewards/RewardsTransfer.t.sol diff --git a/test/LootDropHQ/LootDropWithdraw.t.sol b/test/Rewards/RewardsWithdraw.t.sol similarity index 100% rename from test/LootDropHQ/LootDropWithdraw.t.sol rename to test/Rewards/RewardsWithdraw.t.sol