Skip to content

Commit

Permalink
gring (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
hujw77 authored Jun 17, 2024
1 parent 84e0e15 commit 78580c6
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 115 deletions.
13 changes: 9 additions & 4 deletions src/collator/CollatorStakingHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 "./interfaces/INominationPool.sol";
import "./interfaces/IGRING.sol";
import "../governance/interfaces/IGRING.sol";
import "../deposit/interfaces/IDeposit.sol";
import "./interfaces/INominationPool.sol";
import "./NominationPool.sol";
import "./CollatorSet.sol";

Expand Down Expand Up @@ -69,15 +69,13 @@ 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);
}

function _unstake(address collator, address account, uint256 assets) internal {
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);
}
Expand All @@ -92,13 +90,15 @@ 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 {
_unstake(collator, msg.sender, assets);
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 {
Expand All @@ -110,6 +110,8 @@ 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 {
Expand All @@ -122,6 +124,9 @@ 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 {
Expand Down
30 changes: 29 additions & 1 deletion src/deposit/Deposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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
Expand All @@ -22,6 +23,8 @@ contract Deposit is
// precision = 10_000
uint256[37] public INTERESTS;
uint256 private _nextTokenId;
// Governance RING
IGRING public gRING;

struct DepositInfo {
uint64 months;
Expand All @@ -30,6 +33,7 @@ contract Deposit is
}

mapping(uint256 => DepositInfo) public depositOf;
mapping(uint256 => address) public stakedOf;

uint256 public constant MONTH = 30 days;
// Deposit Pallet Account
Expand All @@ -44,13 +48,16 @@ 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(string memory name, string memory symbol) public initializer {
function initialize(address gring, string memory name, string memory symbol) public initializer {
gRING = IGRING(gring);
__DepositInterest_init();
__ERC721_init(name, symbol);
__ERC721Enumerable_init();
Expand Down Expand Up @@ -105,6 +112,8 @@ 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.
Expand Down Expand Up @@ -146,6 +155,25 @@ 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;
Expand Down
2 changes: 2 additions & 0 deletions src/deposit/interfaces/IDeposit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ 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;
}
123 changes: 13 additions & 110 deletions src/governance/GovernanceRing.sol
Original file line number Diff line number Diff line change
@@ -1,136 +1,39 @@
// 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,
AccessControlEnumerableUpgradeable,
ERC20PermitUpgradeable,
ERC20VotesUpgradeable,
ReentrancyGuardUpgradeable
{
using Address for address payable;
using EnumerableSet for EnumerableSet.UintSet;
contract GovernanceRing is Initializable, ERC20Upgradeable, ERC20PermitUpgradeable, ERC20VotesUpgradeable {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);

// 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);
function initialize(string memory name, string memory symbol) public initializer {
__ERC20_init(name, symbol);
__AccessControlEnumerable_init();
__ERC20Permit_init(symbol);
__ERC20Votes_init();
__ReentrancyGuard_init();

_grantRole(DEFAULT_ADMIN_ROLE, admin);
}

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

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();
receive() external payable {
depositFor(msg.sender);
}

function transferFrom(address, address, uint256) public override returns (bool) {
revert();
function depositFor(address account) public payable {
_mint(account, msg.value);
emit Deposit(account, msg.value);
}

function approve(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 clock() public view override returns (uint48) {
Expand Down
9 changes: 9 additions & 0 deletions src/governance/interfaces/IGRING.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// 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;
}

0 comments on commit 78580c6

Please sign in to comment.