From 7e7ef8b1accff4a31ba8cb0a33f085497d15bf12 Mon Sep 17 00:00:00 2001 From: echo Date: Tue, 18 Jun 2024 00:43:23 +0800 Subject: [PATCH] Revert "gring (#12)" This reverts commit 78580c668d263e567a760178d2d5e22ab1924ee1. --- src/collator/CollatorStakingHub.sol | 13 +-- src/deposit/Deposit.sol | 30 +------ src/deposit/interfaces/IDeposit.sol | 2 - src/governance/GovernanceRing.sol | 123 ++++++++++++++++++++++++--- src/governance/interfaces/IGRING.sol | 9 -- 5 files changed, 115 insertions(+), 62 deletions(-) delete mode 100644 src/governance/interfaces/IGRING.sol diff --git a/src/collator/CollatorStakingHub.sol b/src/collator/CollatorStakingHub.sol index 625d052..516feb7 100644 --- a/src/collator/CollatorStakingHub.sol +++ b/src/collator/CollatorStakingHub.sol @@ -6,9 +6,9 @@ import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; -import "../governance/interfaces/IGRING.sol"; -import "../deposit/interfaces/IDeposit.sol"; import "./interfaces/INominationPool.sol"; +import "./interfaces/IGRING.sol"; +import "../deposit/interfaces/IDeposit.sol"; import "./NominationPool.sol"; import "./CollatorSet.sol"; @@ -69,6 +69,7 @@ contract CollatorStakingHub is ReentrancyGuardUpgradeable, CollatorSet { address pool = poolOf[collator]; require(pool != address(0), "!collator"); INominationPool(pool).stake(account, assets); + IGRING(gRING).mint(account, assets); emit Staked(pool, collator, account, assets); } @@ -76,6 +77,7 @@ contract CollatorStakingHub is ReentrancyGuardUpgradeable, CollatorSet { require(stakingLocks[collator][account] < block.timestamp, "!locked"); address pool = poolOf[collator]; require(pool != address(0), "!collator"); + IGRING(gRING).burn(account, assets); INominationPool(pool).withdraw(account, assets); emit Unstaked(pool, collator, account, assets); } @@ -90,7 +92,6 @@ contract CollatorStakingHub is ReentrancyGuardUpgradeable, CollatorSet { _stake(collator, msg.sender, msg.value); _increaseVotes(collator, _assetsToVotes(commissionOf[collator], msg.value), oldPrev, newPrev); stakedRINGOf[msg.sender] += msg.value; - IGRING(gRING).depositFor{value: msg.value}(msg.sender); } function unstakeRING(address collator, uint256 assets, address oldPrev, address newPrev) public nonReentrant { @@ -98,7 +99,6 @@ contract CollatorStakingHub is ReentrancyGuardUpgradeable, CollatorSet { payable(msg.sender).sendValue(assets); _reduceVotes(collator, _assetsToVotes(commissionOf[collator], assets), oldPrev, newPrev); stakedRINGOf[msg.sender] -= assets; - IGRING(gRING).withdrawTo(msg.sender, assets); } function stakeDeposit(address collator, uint256 depositId, address oldPrev, address newPrev) public nonReentrant { @@ -110,8 +110,6 @@ contract CollatorStakingHub is ReentrancyGuardUpgradeable, CollatorSet { _stake(collator, account, assets); _increaseVotes(collator, _assetsToVotes(commissionOf[collator], assets), oldPrev, newPrev); require(_stakedDeposits[account].add(depositId), "!add"); - IDeposit(DEPOSIT).lock(depositId); - IGRING(gRING).transferFrom(address(this), account, assets); } function unstakeDeposit(uint256 depositId, address oldPrev, address newPrev) public nonReentrant { @@ -124,9 +122,6 @@ contract CollatorStakingHub is ReentrancyGuardUpgradeable, CollatorSet { _unstake(info.collator, info.account, info.assets); _reduceVotes(info.collator, _assetsToVotes(commissionOf[info.collator], info.assets), oldPrev, newPrev); require(_stakedDeposits[account].remove(depositId), "!remove"); - IGRING(gRING).transferFrom(account, address(this), info.assets); - IDeposit(DEPOSIT).unlock(depositId); - payable(account).sendValue(info.assets); } function collect(uint256 commission, address oldPrev, address newPrev) public nonReentrant { diff --git a/src/deposit/Deposit.sol b/src/deposit/Deposit.sol index bd50283..f31b3f8 100644 --- a/src/deposit/Deposit.sol +++ b/src/deposit/Deposit.sol @@ -7,7 +7,6 @@ import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721Enumer import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; -import "../governance/interfaces/IGRING.sol"; import "./interfaces/IKTON.sol"; contract Deposit is @@ -23,8 +22,6 @@ contract Deposit is // precision = 10_000 uint256[37] public INTERESTS; uint256 private _nextTokenId; - // Governance RING - IGRING public gRING; struct DepositInfo { uint64 months; @@ -33,7 +30,6 @@ contract Deposit is } mapping(uint256 => DepositInfo) public depositOf; - mapping(uint256 => address) public stakedOf; uint256 public constant MONTH = 30 days; // Deposit Pallet Account @@ -48,16 +44,13 @@ contract Deposit is ); event DepositClaimed(uint256 indexed depositId, address indexed account, uint256 value); event ClaimWithPenalty(uint256 indexed depositId, address indexed account, uint256 penalty); - event Lock(uint256 indexed depositId, address sender); - event UnLock(uint256 indexed depositId, address sender); modifier onlySystem() { require(msg.sender == DEPOSIT_PALLET); _; } - function initialize(address gring, string memory name, string memory symbol) public initializer { - gRING = IGRING(gring); + function initialize(string memory name, string memory symbol) public initializer { __DepositInterest_init(); __ERC721_init(name, symbol); __ERC721Enumerable_init(); @@ -112,8 +105,6 @@ contract Deposit is _disableInitializers(); } - receive() external payable {} - /// @dev Migrate user's deposit from Deposit Pallet to Deposit smart contract. /// The amount of the deposit value must be passed in via msg.value. /// @notice Only Deposit Pallet Account could call this function. @@ -155,25 +146,6 @@ contract Deposit is emit ClaimWithPenalty(depositId, msg.sender, penalty); } - function lock(uint256 depositId) public nonReentrant { - address sender = msg.sender; - transferFrom(sender, address(this), depositId); - stakedOf[depositId] = sender; - uint256 assets = assetsOf(depositId); - gRING.depositFor{value: assets}(sender); - emit Lock(sender, depositId); - } - - function unlock(uint256 depositId) public nonReentrant { - address sender = msg.sender; - require(stakedOf[depositId] == sender, "!auth"); - transferFrom(address(this), sender, depositId); - delete stakedOf[depositId]; - uint256 assets = assetsOf(depositId); - gRING.withdrawTo(sender, assets); - emit UnLock(sender, depositId); - } - function assetsOf(uint256 id) public view returns (uint256) { _requireOwned(id); return depositOf[id].value; diff --git a/src/deposit/interfaces/IDeposit.sol b/src/deposit/interfaces/IDeposit.sol index 5f44ac3..1be39f2 100644 --- a/src/deposit/interfaces/IDeposit.sol +++ b/src/deposit/interfaces/IDeposit.sol @@ -5,6 +5,4 @@ import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; interface IDeposit is IERC721 { function assetsOf(uint256 id) external view returns (uint256); - function lock(uint256 depositId) external; - function unlock(uint256 depositId) external; } diff --git a/src/governance/GovernanceRing.sol b/src/governance/GovernanceRing.sol index 628484a..ab4786a 100644 --- a/src/governance/GovernanceRing.sol +++ b/src/governance/GovernanceRing.sol @@ -1,19 +1,54 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.20; +import "@openzeppelin/contracts/utils/Address.sol"; +import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/extensions/AccessControlEnumerableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "../deposit/interfaces/IDeposit.sol"; -contract GovernanceRing is Initializable, ERC20Upgradeable, ERC20PermitUpgradeable, ERC20VotesUpgradeable { - event Deposit(address indexed dst, uint256 wad); - event Withdrawal(address indexed src, uint256 wad); +contract GovernanceRing is + Initializable, + ERC20Upgradeable, + AccessControlEnumerableUpgradeable, + ERC20PermitUpgradeable, + ERC20VotesUpgradeable, + ReentrancyGuardUpgradeable +{ + using Address for address payable; + using EnumerableSet for EnumerableSet.UintSet; - function initialize(string memory name, string memory symbol) public initializer { + // depositId => user + mapping(uint256 => address) public depositorOf; + // user => token => assets + mapping(address => mapping(address => uint256)) public wrapAssets; + // user => wrap depositIds + mapping(address => EnumerableSet.UintSet) private _wrapDeposits; + IDeposit public DEPOSIT; + + address public constant RING = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE"); + + event Wrap(address indexed account, address indexed token, uint256 assets); + event Unwrap(address indexed account, address indexed token, uint256 assets); + event WrapDeposit(address indexed account, address indexed token, uint256 depositId); + event UnwrapDeposit(address indexed account, address indexed token, uint256 depositId); + + function initialize(address admin, address dps, string memory name, string memory symbol) public initializer { + DEPOSIT = IDeposit(dps); __ERC20_init(name, symbol); + __AccessControlEnumerable_init(); __ERC20Permit_init(symbol); __ERC20Votes_init(); + __ReentrancyGuard_init(); + + _grantRole(DEFAULT_ADMIN_ROLE, admin); } /// @custom:oz-upgrades-unsafe-allow constructor @@ -21,19 +56,81 @@ contract GovernanceRing is Initializable, ERC20Upgradeable, ERC20PermitUpgradeab _disableInitializers(); } - receive() external payable { - depositFor(msg.sender); + function mint(address to, uint256 assets) public onlyRole(MINTER_ROLE) { + _mint(to, assets); + } + + function burn(address from, uint256 assets) public onlyRole(BURNER_ROLE) { + _burn(from, assets); + } + + function _wrap(address account, address token, uint256 assets) internal { + _mint(account, assets); + wrapAssets[account][token] += assets; + emit Wrap(account, token, assets); + } + + function _unwrap(address account, address token, uint256 assets) internal { + _burn(account, assets); + wrapAssets[account][token] -= assets; + emit Unwrap(account, token, assets); + } + + function wrapRING() public payable nonReentrant { + _wrap(msg.sender, RING, msg.value); + } + + function unwrapRING(uint256 assets) public nonReentrant { + _unwrap(msg.sender, RING, assets); + payable(msg.sender).sendValue(assets); + } + + function wrapDeposit(uint256 depositId) public nonReentrant { + address account = msg.sender; + DEPOSIT.transferFrom(account, address(this), depositId); + uint256 assets = DEPOSIT.assetsOf(depositId); + depositorOf[depositId] = account; + require(_wrapDeposits[account].add(depositId), "!add"); + _wrap(account, address(DEPOSIT), assets); + emit WrapDeposit(account, address(DEPOSIT), assets); + } + + function unwrapDeposit(uint256 depositId) public nonReentrant { + address account = msg.sender; + require(depositorOf[depositId] == account, "!account"); + uint256 assets = DEPOSIT.assetsOf(depositId); + _unwrap(account, address(DEPOSIT), assets); + require(_wrapDeposits[account].remove(depositId), "!remove"); + DEPOSIT.transferFrom(address(this), account, depositId); + emit UnwrapDeposit(account, address(DEPOSIT), depositId); + } + + function wrapDepositsOf(address account) public view returns (uint256[] memory) { + return _wrapDeposits[account].values(); + } + + function wrapDepositsLength(address account) public view returns (uint256) { + return _wrapDeposits[account].length(); + } + + function wrapDepositsAt(address account, uint256 index) public view returns (uint256) { + return _wrapDeposits[account].at(index); + } + + function wrapDepositsContains(address account, uint256 depositId) public view returns (bool) { + return _wrapDeposits[account].contains(depositId); + } + + function transfer(address, uint256) public override returns (bool) { + revert(); } - function depositFor(address account) public payable { - _mint(account, msg.value); - emit Deposit(account, msg.value); + function transferFrom(address, address, uint256) public override returns (bool) { + revert(); } - function withdrawTo(address account, uint256 wad) public { - _burn(msg.sender, wad); - payable(msg.sender).transfer(wad); - emit Withdrawal(account, wad); + function approve(address, uint256) public override returns (bool) { + revert(); } function clock() public view override returns (uint48) { diff --git a/src/governance/interfaces/IGRING.sol b/src/governance/interfaces/IGRING.sol deleted file mode 100644 index de973b7..0000000 --- a/src/governance/interfaces/IGRING.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.4.24; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -interface IGRING is IERC20 { - function depositFor(address account) external payable; - function withdrawTo(address account, uint256 wad) external; -}