Last active
January 20, 2023 06:47
-
-
Save KBPsystem777/b1c1d4b84106cb82e10a880ff5d716cf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.17; | |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | |
import "@openzeppelin/contracts/access/Ownable.sol"; | |
import "@openzeppelin/contracts/security/Pausable.sol"; | |
import "./ManageLife.sol"; | |
import "./MLInvestorsNFT.sol"; | |
/** | |
* @notice An ERC-20 contract for ManageLife. | |
* Token Symbol: MLIFE ($MLIFE) | |
* This contract manages token rewards issued to ManageLife homeowners and investors. | |
* This contract also handles native token functions (EIP20 Token Standard). | |
* | |
* @author https://managelife.co | |
*/ | |
contract Life is ERC20, Ownable, Pausable { | |
/** | |
* @notice Mapping to get the start of staking for each NFTs. | |
* Start of stake data is in UNIX timestamp form. | |
*/ | |
mapping(uint256 => uint64) public startOfStakingRewards; | |
/// @notice Maximum token supply | |
uint256 public constant MAX_SUPPLY = 5000000000000000000000000000; | |
/// Instance of the MLIFE NFT contract | |
ManageLife private _manageLifeToken; | |
/// Instance of the NFTi contract | |
ManageLifeInvestorsNFT private _investorsNft; | |
/// Set initial token supply before deploying. | |
constructor() ERC20("Life", "MLIFE") { | |
_mint(msg.sender, 2000000000000000000000000000); | |
} | |
event StakingClaimed(address indexed claimaint, uint256 tokenId); | |
event TokensBurned(address indexed burnFrom, uint256 amount); | |
/// @notice Security feature to Pause smart contracts transactions | |
function pause() external whenNotPaused onlyOwner { | |
_pause(); | |
} | |
/// @notice Unpausing the Paused transactions feature. | |
function unpause() external whenPaused onlyOwner { | |
_unpause(); | |
} | |
/** | |
* @notice Set the MLIFE's NFT contract address. | |
* @dev Important to set this after deployment. | |
* @param manageLifeToken_ Address of the MLIFE NFT contract | |
*/ | |
function setManageLifeToken( | |
address manageLifeToken_ | |
) external onlyOwner whenNotPaused { | |
_manageLifeToken = ManageLife(manageLifeToken_); | |
} | |
/** | |
* @notice Set the NFTi contract address. | |
* @dev Important to set this after deployment. | |
* @param investorsNft_ Contract address of NFTi contract. | |
*/ | |
function setNftiToken( | |
address investorsNft_ | |
) external onlyOwner whenNotPaused { | |
_investorsNft = ManageLifeInvestorsNFT(investorsNft_); | |
} | |
/** | |
* @notice Return the MLIFE's contract address. | |
* @dev If set, this will return the MLIFE contract address | |
* @return address | |
*/ | |
function manageLifeToken() external view returns (address) { | |
return address(_manageLifeToken); | |
} | |
/**x | |
* @notice Return the NFTi's contract address. | |
* @dev If set, this will return the NFTi contract address. | |
* @return address . | |
*/ | |
function manageLifeInvestorsNft() external view returns (address) { | |
return address(_investorsNft); | |
} | |
/** | |
* @notice Initialize the Staking for an NFT. | |
* | |
* @dev Reverts if the caller is not the MLIFE contract address, | |
* MLIFE contact address is not set and if the contract is on-paused status. | |
* | |
* @param tokenId TokenId of the NFT to start stake. | |
*/ | |
function initStakingRewards(uint256 tokenId) external whenNotPaused { | |
require( | |
address(_manageLifeToken) != address(0), | |
"ManageLife token is not set" | |
); | |
// Making sure the one who will trigger this function are only ManageLife NFT and NFTi contracts: | |
require( | |
msg.sender == address(_manageLifeToken), | |
"Only ManageLife token" | |
); | |
startOfStakingRewards[tokenId] = uint64(block.timestamp); | |
} | |
/** | |
* @notice Update the start of stake of an NFT. | |
* | |
* @dev Since staking reward is based on time, this function will | |
* reset the stake start of an NFT that just recently claimed a token reward. | |
* This will be also an on-demand operation where the admins needs to reset | |
* the start of stake of an NFT, based off UNIX time. | |
* | |
* @param tokenId TokenID of an NFT. | |
* @param newStartDate New start of stake of an NFT. This param should be based on | |
* UNIX timestamp and into uint64 type. | |
*/ | |
function updateStartOfStaking( | |
uint256 tokenId, | |
uint64 newStartDate | |
) external { | |
require( | |
msg.sender == owner() || msg.sender == address(_manageLifeToken), | |
"Ony admins can execute this operation" | |
); | |
startOfStakingRewards[tokenId] = newStartDate; | |
} | |
/** | |
* @notice Returns the claimable $LIFE token of an NFT. | |
* | |
* @dev MLIFE contract is dependent on this function in calculating | |
* the estimated staking rewards of an MLIFE. | |
* Formula in calculating the reward: | |
* Rewards = Current timestamp - StartOfStake timestamp * Life token issuance rate. | |
* | |
* @param tokenId MLIFE's tokenId. | |
* @return uint256 | |
*/ | |
function claimableStakingRewards( | |
uint256 tokenId | |
) public view returns (uint256) { | |
if (uint64(block.timestamp) < startOfStakingRewards[tokenId]) { | |
return 0; | |
} | |
return | |
(uint64(block.timestamp) - startOfStakingRewards[tokenId]) * | |
_manageLifeToken.lifeTokenIssuanceRate(tokenId); | |
} | |
/** | |
* @notice Burns $LIFE token from a sender's account. Assuming that sender holds $LIFE tokens. | |
* @param amount Amount to burn. | |
*/ | |
function burnLifeTokens(uint256 amount) external { | |
_burn(msg.sender, amount); | |
} | |
/** | |
* @notice Function to mint additional token supply. | |
* | |
* @dev Newly minted amount will be credited to the contract owner. | |
* Prevents minting of new tokens if 5B supply is reached. | |
* | |
* @param _amount Additional amount to be minted. | |
*/ | |
function mint(uint256 _amount) external onlyOwner isMaxSupply(_amount) { | |
_mint(msg.sender, _amount); | |
} | |
/** | |
* @notice Mint $LIFE token rewards for NFTi Investors. | |
* | |
* @dev NFTi contract depends on this function to mint $LIFE | |
* token rewards to investors. Newly minted tokens here will be | |
* credited directly to the investor's wallet address and NOT on the admin wallet. | |
* Minting new token supply if 5B LIFE token supply is reached. | |
* | |
* @param investorAddress Wallet address of the investor. | |
* @param _amount Amount to be minted on the investor's address. Amount is based on the | |
* calculated staking rewards from NFTi contract. | |
*/ | |
function mintInvestorsRewards( | |
address investorAddress, | |
uint256 _amount | |
) external isMaxSupply(_amount) { | |
_mint(investorAddress, _amount); | |
} | |
/** | |
* @notice Claim $LIFE token staking rewards. | |
* | |
* @dev MLIFE's rewards issuance is reliant on this function. | |
* Once the user claim the rewards, this function will mint the | |
* tokens directly on the homeowner's wallet. | |
* Notes: | |
* - ML's admin or deployer wallet cannot claim $LIFE rewards. | |
* - Setting the MLIFE contract address is prerequisite in running this function. | |
* - This function can only be called by MLIFE holders. | |
* - A percentage of the token reward will be burned. Percentage will be determined by the ML admin. | |
* - Burn call will be handled separately by the frontend app. | |
* | |
* @param tokenId MLIFE's tokenId. | |
*/ | |
function claimStakingRewards(uint256 tokenId) public whenNotPaused { | |
require( | |
address(_manageLifeToken) != address(0), | |
"ManageLife token is not set" | |
); | |
/// @dev Making sure that admin wallet will not own token rewards. | |
require( | |
_manageLifeToken.ownerOf(tokenId) != owner(), | |
"Platform wallet cannot claim" | |
); | |
/// @dev Making sure that only admin and MLIFE owners will claim the rewards. | |
require( | |
msg.sender == owner() || | |
msg.sender == _manageLifeToken.ownerOf(tokenId) || | |
msg.sender == address(_manageLifeToken), | |
"Unauthorized." | |
); | |
/// @dev Adding require check to comply with the maximum token supply. | |
require( | |
totalSupply() + claimableStakingRewards(tokenId) <= MAX_SUPPLY, | |
"$LIFE supply is maxed" | |
); | |
/*** @notice Variable containers that holds the claimable amounts of the user. */ | |
uint256 rewards = claimableStakingRewards(tokenId); | |
/** | |
* @dev If the answer on the above questions are true, | |
* mint new ERC20 $LIFE tokens. Claimable amount will be minted on the property owner. | |
* At the same time, a percentage of the claimed reward will be burned | |
* which will be handled separately by the frontend app. | |
*/ | |
_mint(_manageLifeToken.ownerOf(tokenId), rewards); | |
/** | |
* @dev Resetting the startOfStakingsRewards of the token to make | |
* sure their claimable rewards will reset as well. | |
*/ | |
startOfStakingRewards[tokenId] = uint64(block.timestamp); | |
emit StakingClaimed(msg.sender, rewards); | |
} | |
/** | |
* @notice Custom access modifier to make sure that the caller of transactions are member of ML. | |
* @dev This identifies if the caller is an MLIFE or NFTi holder. | |
* @param tokenId TokenId of the NFT that needs to be checked. | |
*/ | |
modifier onlyMembers(uint256 tokenId) { | |
require( | |
msg.sender == _manageLifeToken.ownerOf(tokenId) || | |
msg.sender == _investorsNft.ownerOf(tokenId), | |
"Only NFT holders can execute this" | |
); | |
_; | |
} | |
/** | |
* @notice Custom access modifier to make sure minting will not exceed. | |
* @dev This makes sure that the LIFE max supply is 5B. | |
* @param amount new amount to be minted. | |
*/ | |
modifier isMaxSupply(uint256 amount) { | |
require(totalSupply() + amount <= MAX_SUPPLY, "$LIFE supply is maxed"); | |
_; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment