diff --git a/contracts/modules/token/TokenController.sol b/contracts/modules/token/TokenController.sol index e70656f775..9d410b856c 100644 --- a/contracts/modules/token/TokenController.sol +++ b/contracts/modules/token/TokenController.sol @@ -34,6 +34,8 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { address public immutable claimsReward; address public immutable stakingPoolFactory; + /* ========== CONSTRUCTOR ========== */ + constructor( address quotationDataAddress, address claimsRewardAddress, @@ -44,52 +46,46 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { stakingPoolFactory = stakingPoolFactoryAddress; } - // TODO: probably better to move this to master - function unlistClaimsReward() external { - token().removeFromWhiteList(claimsReward); - } + /* ========== TOKEN RELATED VIEW FUNCTIONS ========== */ - /* ========== DEPENDENCIES ========== */ - - function token() public view returns (INXMToken) { - return INXMToken(internalContracts[uint(ID.TK)]); + function totalSupply() public override view returns (uint256) { + return token().totalSupply(); } - function pooledStaking() internal view returns (IPooledStaking) { - return IPooledStaking(internalContracts[uint(ID.PS)]); - } + /// Returns the base voting power not the balance. It is used in governance voting as well as in + /// snapshot voting. + /// + /// @dev Caution, this function is improperly named because reconfiguring snapshot voting was + /// not desired. It accounts for the tokens in the user's wallet as well as tokens locked in + /// assessment and legacy staking deposits. V2 staking deposits are excluded because they are + /// delegated to the pool managers instead. + /// TODO: add stake pool balance for pool operators + /// + /// @param _of The member address for which the base voting power is calculated. + function totalBalanceOf(address _of) public override view returns (uint256 amount) { - function assessment() internal view returns (IAssessment) { - return IAssessment(internalContracts[uint(ID.AS)]); - } + amount = token().balanceOf(_of); - function cover() internal view returns (ICover) { - return ICover(internalContracts[uint(ID.CO)]); - } + // This loop can be removed once all cover notes are withdrawn + for (uint256 i = 0; i < lockReason[_of].length; i++) { + amount = amount + _tokensLocked(_of, lockReason[_of][i]); + } - function governance() internal view returns (IGovernance) { - return IGovernance(internalContracts[uint(ID.GV)]); - } + // [todo] Can be removed after PooledStaking is decommissioned + uint stakerReward = pooledStaking().stakerReward(_of); + uint stakerDeposit = pooledStaking().stakerDeposit(_of); - /** - * @dev Just for interface - */ - function changeDependentContractAddress() public override { - internalContracts[uint(ID.TK)] = payable(master.tokenAddress()); - internalContracts[uint(ID.PS)] = master.getLatestAddress("PS"); - internalContracts[uint(ID.AS)] = master.getLatestAddress("AS"); - internalContracts[uint(ID.CO)] = master.getLatestAddress("CO"); - internalContracts[uint(ID.GV)] = master.getLatestAddress("GV"); - } + ( + uint assessmentStake, + /*uint104 rewardsWithdrawableFromIndex*/, + /*uint16 fraudCount*/ + ) = assessment().stakeOf(_of); - /** - * @dev to change the operator address - * @param _newOperator is the new address of operator - */ - function changeOperator(address _newOperator) public override onlyGovernance { - token().changeOperator(_newOperator); + amount += stakerDeposit + stakerReward + assessmentStake; } + /* ========== INTERNAL OPERATOR RELATED MUTATIVE FUNCTIONS ========== */ + /** * @dev Proxies token transfer through this contract to allow staking when members are locked for voting * @param _from Source address @@ -108,29 +104,11 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { } /** - * @dev burns tokens of an address - * @param _of is the address to burn tokens of - * @param amount is the amount to burn - * @return the boolean status of the burning process + * @dev Lock the user's tokens + * @param _of user's address. */ - function burnFrom(address _of, uint amount) public override onlyInternal returns (bool) { - return token().burnFrom(_of, amount); - } - - /** - * @dev Adds an address to whitelist maintained in the contract - * @param _member address to add to whitelist - */ - function addToWhitelist(address _member) public virtual override onlyInternal { - token().addToWhiteList(_member); - } - - /** - * @dev Removes an address from the whitelist in the token - * @param _member address to remove - */ - function removeFromWhitelist(address _member) public override onlyInternal { - token().removeFromWhiteList(_member); + function lockForMemberVote(address _of, uint _days) public override onlyInternal { + token().lockForMemberVote(_of, _days); } /** @@ -143,83 +121,77 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { } /** - * @dev Lock the user's tokens - * @param _of user's address. + * @dev burns tokens of an address + * @param _of is the address to burn tokens of + * @param amount is the amount to burn + * @return the boolean status of the burning process */ - function lockForMemberVote(address _of, uint _days) public override onlyInternal { - token().lockForMemberVote(_of, _days); + function burnFrom(address _of, uint amount) public override onlyInternal returns (bool) { + return token().burnFrom(_of, amount); } - /** - * @dev Unlocks the withdrawable tokens against CLA of a specified addresses - * @param users Addresses of users for whom the tokens are unlocked - */ - function withdrawClaimAssessmentTokens(address[] calldata users) external { - for (uint256 i = 0; i < users.length; i++) { - if (locked[users[i]]["CLA"].claimed) { - continue; - } - uint256 amount = locked[users[i]]["CLA"].amount; - if (amount > 0) { - locked[users[i]]["CLA"].claimed = true; - emit Unlocked(users[i], "CLA", amount); - token().transfer(users[i], amount); - } - } + function _stakingPool(uint poolId) internal view returns (address) { + return StakingPoolLibrary.getAddress(stakingPoolFactory, poolId); } - /** - * @dev Updates Uint Parameters of a code - * @param code whose details we want to update - * @param value value to set - */ - function updateUintParameters(bytes8 code, uint value) external view onlyGovernance { - // silence compiler warnings - code; - value; - revert("TokenController: invalid param code"); + function mintStakingPoolNXMRewards(uint amount, uint poolId) external { + require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); + token().mint(address(this), amount); + stakingPoolNXMBalances[poolId].rewards += amount.toUint128(); } - function getLockReasons(address _of) external override view returns (bytes32[] memory reasons) { - return lockReason[_of]; + function burnStakingPoolNXMRewards(uint amount, uint poolId) external { + require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); + stakingPoolNXMBalances[poolId].rewards -= amount.toUint128(); + token().burn(amount); } - function totalSupply() public override view returns (uint256) { - return token().totalSupply(); + function depositStakedNXM(address from, uint amount, uint poolId) external { + require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); + stakingPoolNXMBalances[poolId].deposits += amount.toUint128(); + token().operatorTransfer(from, amount); } - /// Returns the base voting power not the balance. It is used in governance voting as well as in - /// snapshot voting. - /// - /// @dev Caution, this function is improperly named because reconfiguring snapshot voting was - /// not desired. It accounts for the tokens in the user's wallet as well as tokens locked in - /// assessment and legacy staking deposits. V2 staking deposits are excluded because they are - /// delegated to the pool managers instead. - /// TODO: add stake pool balance for pool operators - /// - /// @param _of The member address for which the base voting power is calculated. - function totalBalanceOf(address _of) public override view returns (uint256 amount) { + function withdrawNXMStakeAndRewards(address to, uint stakeToWithdraw, uint rewardsToWithdraw, uint poolId) external { + require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); + StakingPoolNXMBalances memory poolBalances = stakingPoolNXMBalances[poolId]; + poolBalances.deposits -= stakeToWithdraw.toUint128(); + poolBalances.rewards -= rewardsToWithdraw.toUint128(); + stakingPoolNXMBalances[poolId] = poolBalances; + token().transfer(to, stakeToWithdraw + rewardsToWithdraw); + } - amount = token().balanceOf(_of); + function burnStakedNXM(uint amount, uint poolId) external { + require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); + stakingPoolNXMBalances[poolId].deposits -= amount.toUint128(); + token().burn(amount); + } - // This loop can be removed once all cover notes are withdrawn - for (uint256 i = 0; i < lockReason[_of].length; i++) { - amount = amount + _tokensLocked(_of, lockReason[_of][i]); - } + /* ========== WHITELIST RELATED MUTATIVE FUNCTIONS ========== */ - // [todo] Can be removed after PooledStaking is decommissioned - uint stakerReward = pooledStaking().stakerReward(_of); - uint stakerDeposit = pooledStaking().stakerDeposit(_of); + /** + * @dev Adds an address to whitelist maintained in the contract + * @param _member address to add to whitelist + */ + function addToWhitelist(address _member) public virtual override onlyInternal { + token().addToWhiteList(_member); + } - ( - uint assessmentStake, - /*uint104 rewardsWithdrawableFromIndex*/, - /*uint16 fraudCount*/ - ) = assessment().stakeOf(_of); + /** + * @dev Removes an address from the whitelist in the token + * @param _member address to remove + */ + function removeFromWhitelist(address _member) public override onlyInternal { + token().removeFromWhiteList(_member); + } - amount += stakerDeposit + stakerReward + assessmentStake; + // TODO: probably better to move this to master + function unlistClaimsReward() external { + token().removeFromWhiteList(claimsReward); } + /* ========== USER REWARDS RELATED MUTATIVE FUNCTIONS ========== */ + /// Withdraws governance rewards for the given member address /// @dev This function requires a batchSize that fits in one block. It cannot be 0. function withdrawGovernanceRewards( @@ -289,8 +261,14 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { } } + /* ========== V1 RELATED VIEW FUNCTIONS ========== */ + + function getLockReasons(address _of) external override view returns (bytes32[] memory reasons) { + return lockReason[_of]; + } + /** - * @dev Returns tokens locked for a specified address for a + * @dev Returns tokens locked for a specified address for a * specified reason * * @param _of The address whose tokens are locked @@ -341,6 +319,8 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { } } + /* ========== V1 RELATED MUTATIVE FUNCTIONS ========== */ + // Can be removed once all cover notes are withdrawn function withdrawCoverNote( address user, @@ -383,40 +363,74 @@ contract TokenController is ITokenController, LockHandler, MasterAwareV2 { token().transfer(user, totalAmount); } - function _stakingPool(uint poolId) internal view returns (address) { - return StakingPoolLibrary.getAddress(stakingPoolFactory, poolId); + /** + * @dev Unlocks the withdrawable tokens against CLA of a specified addresses + * @param users Addresses of users for whom the tokens are unlocked + */ + function withdrawClaimAssessmentTokens(address[] calldata users) external { + for (uint256 i = 0; i < users.length; i++) { + if (locked[users[i]]["CLA"].claimed) { + continue; + } + uint256 amount = locked[users[i]]["CLA"].amount; + if (amount > 0) { + locked[users[i]]["CLA"].claimed = true; + emit Unlocked(users[i], "CLA", amount); + token().transfer(users[i], amount); + } + } } - function mintStakingPoolNXMRewards(uint amount, uint poolId) external { - require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); - token().mint(address(this), amount); - stakingPoolNXMBalances[poolId].rewards += amount.toUint128(); + /* ========== DEPENDENCIES ========== */ + + function token() public view returns (INXMToken) { + return INXMToken(internalContracts[uint(ID.TK)]); } - function burnStakingPoolNXMRewards(uint amount, uint poolId) external { - require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); - stakingPoolNXMBalances[poolId].rewards -= amount.toUint128(); - token().burn(amount); + function pooledStaking() internal view returns (IPooledStaking) { + return IPooledStaking(internalContracts[uint(ID.PS)]); } - function depositStakedNXM(address from, uint amount, uint poolId) external { - require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); - stakingPoolNXMBalances[poolId].deposits += amount.toUint128(); - token().operatorTransfer(from, amount); + function assessment() internal view returns (IAssessment) { + return IAssessment(internalContracts[uint(ID.AS)]); } - function withdrawNXMStakeAndRewards(address to, uint stakeToWithdraw, uint rewardsToWithdraw, uint poolId) external { - require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); - StakingPoolNXMBalances memory poolBalances = stakingPoolNXMBalances[poolId]; - poolBalances.deposits -= stakeToWithdraw.toUint128(); - poolBalances.rewards -= rewardsToWithdraw.toUint128(); - stakingPoolNXMBalances[poolId] = poolBalances; - token().transfer(to, stakeToWithdraw + rewardsToWithdraw); + function cover() internal view returns (ICover) { + return ICover(internalContracts[uint(ID.CO)]); } - function burnStakedNXM(uint amount, uint poolId) external { - require(msg.sender == _stakingPool(poolId), "TokenController: msg.sender not staking pool"); - stakingPoolNXMBalances[poolId].deposits -= amount.toUint128(); - token().burn(amount); + function governance() internal view returns (IGovernance) { + return IGovernance(internalContracts[uint(ID.GV)]); + } + + /** + * @dev Just for interface + */ + function changeDependentContractAddress() public override { + internalContracts[uint(ID.TK)] = payable(master.tokenAddress()); + internalContracts[uint(ID.PS)] = master.getLatestAddress("PS"); + internalContracts[uint(ID.AS)] = master.getLatestAddress("AS"); + internalContracts[uint(ID.CO)] = master.getLatestAddress("CO"); + internalContracts[uint(ID.GV)] = master.getLatestAddress("GV"); + } + + /** + * @dev Updates Uint Parameters of a code + * @param code whose details we want to update + * @param value value to set + */ + function updateUintParameters(bytes8 code, uint value) external view onlyGovernance { + // silence compiler warnings + code; + value; + revert("TokenController: invalid param code"); + } + + /** + * @dev to change the operator address + * @param _newOperator is the new address of operator + */ + function changeOperator(address _newOperator) public override onlyGovernance { + token().changeOperator(_newOperator); } }