pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract ReptilianCorporation is ERC721, Ownable { uint256 public constant MAX_SUPPLY = 4444; uint256 public constant REMIX_BURN_RATIO = 10; // 1 $REMIX token = 10 $CORP tokens uint256 public constant MAX_REMIX_BURNS = 111; // Max $REMIX burns for $CORP tokens string private _tokenTicker; string private _collectionName; address private whitelistContract; address private remixBurnContract; address private erc20Token; // Constructor to set token name, symbol and initial contract owner constructor(string memory ticker_, string memory collectionName_, address owner_) ERC721(collectionName_, ticker_) { _tokenTicker = ticker_; _collectionName = collectionName_; transferOwnership(owner_); } // Function to set the whitelist contract address function setWhitelistContract(address contractAddress) external onlyOwner { whitelistContract = contractAddress; } // Function to set the $REMIX burn contract address function setRemixBurnContract(address contractAddress) external onlyOwner { remixBurnContract = contractAddress; } // Function to set the ERC20 token address function setERC20Token(address tokenAddress) external onlyOwner { erc20Token = tokenAddress; } } // Function to mint $CORP tokens function mintCorpToken(address to) external { require(totalSupply() < MAX_SUPPLY, "Maximum supply reached"); require(whitelistContract != address(0), "Whitelist contract not set"); require(IWhitelist(whitelistContract).isWhitelisted(msg.sender), "Minter not whitelisted"); _safeMint(to, totalSupply() + 1); } // Function to burn $REMIX tokens and receive $CORP tokens function burnRemixToken(uint256 amount) external { require(remixBurnContract != address(0), "$REMIX burn contract not set"); require(erc20Token != address(0), "ERC20 token not set"); require(amount > 0, "Amount must be greater than zero"); require(amount <= ERC20(erc20Token).balanceOf(msg.sender), "Insufficient balance"); uint256 corpAmount = amount * REMIX_BURN_RATIO; require(totalSupply() + corpAmount <= MAX_SUPPLY, "Maximum supply reached"); uint256 burnCount = IRemixBurn(remixBurnContract).burnForCorp(msg.sender, amount); require(burnCount <= MAX_REMIX_BURNS, "Maximum $REMIX burns reached"); for (uint256 i = 0; i < corpAmount; i++) { _safeMint(msg.sender, totalSupply() + 1); } // Emit event emit BurnRemix(msg.sender, amount, burnCount, corpAmount); } // Function to stake $SHARES tokens function stakeShares(uint256 amount) external { require(amount > 0, "Amount must be greater than zero"); require(erc20Token != address(0), "ERC20 token not set"); require(ERC20(erc20Token).balanceOf(msg.sender) >= amount, "Insufficient balance"); if (totalStakedShares == 0 && totalStakedTime == 0) { lastStakeTime = block.timestamp; } uint256 sharesToMint = calculateSharesToMint(amount); totalStakedShares += sharesToMint; totalStakedTime += (block.timestamp - lastStakeTime) * sharesToMint; lastStakeTime = block.timestamp; ERC20(erc20Token).transferFrom(msg.sender, address(this), amount); _mint(msg.sender, sharesToMint); // Emit event emit StakeShares(msg.sender, amount, sharesToMint); } // Function to calculate the amount of $SHARES to mint for a given staked amount function calculateSharesToMint(uint256 amount) public view returns (uint256) { if (totalStakedShares == 0) { return amount * INITIAL_SHARES_PER_ETHER; } else { uint256 timePassed = block.timestamp - lastStakeTime; uint256 timeWeightedShares = totalStakedShares * timePassed; uint256 sharesToMint = (timeWeightedShares * INFLATION_RATE * amount) / (totalStakedTime * INFLATION_DIVISOR); return sharesToMint; } } // Function to unstake $SHARES tokens function unstakeShares(uint256 amount) external { require(amount > 0, "Amount must be greater than zero"); require(balanceOf(msg.sender) >= amount, "Insufficient staked balance"); uint256 sharesToBurn = amount; if (totalStakedShares > 0 && totalStakedTime > 0) { uint256 timePassed = block.timestamp - lastStakeTime; uint256 timeWeightedShares = totalStakedShares * timePassed; uint256 sharesToMint = (timeWeightedShares * INFLATION_RATE * amount) / (totalStakedTime * INFLATION_DIVISOR); sharesToBurn += sharesToMint; totalStakedShares -= amount; totalStakedTime -= (timePassed * amount); lastStakeTime = block.timestamp; } _burn(msg.sender, sharesToBurn); ERC20(erc20Token).transfer(msg.sender, amount); // Emit event emit UnstakeShares(msg.sender, amount, sharesToBurn - amount); } // Function to mint $CORP tokens function mintCorp(uint256 amount) external { require(ERC721(erc721Token).balanceOf(msg.sender) > 0, "Must own at least one $CORP NFT to mint"); require(amount > 0, "Amount must be greater than zero"); require(ERC20(erc20Token).balanceOf(address(this)) >= amount, "Insufficient $SHARES balance in contract"); ERC20(erc20Token).transferFrom(msg.sender, address(this), amount); ERC721(erc721Token).mint(msg.sender, amount); // Emit event emit MintCorp(msg.sender, amount); } // Function to calculate the reward amount for staking $SHARES tokens function calculateStakingReward(address staker) external view returns (uint256) { uint256 sharesBalance = ERC20(erc20Token).balanceOf(staker); uint256 totalShares = ERC20(erc20Token).totalSupply(); uint256 totalCorp = ERC721(erc721Token).totalSupply(); uint256 inflationRate = 10; uint256 rewardAmount = (sharesBalance * totalCorp * inflationRate) / totalShares; return rewardAmount; } // Function to burn $REMIX tokens to mint $CORP tokens function burnToMint(uint256 amount) external { require(msg.sender == remixContract, "Caller must be the $REMIX contract"); require(amount > 0, "Amount must be greater than zero"); require(ERC20(remixToken).balanceOf(msg.sender) >= amount, "Caller does not have enough $REMIX tokens"); require(totalBurned.add(amount) <= burnCap, "Burn cap reached"); // Calculate amount of $CORP tokens to mint uint256 mintAmount = amount.mul(10); // Mint $CORP tokens to the caller ERC721(erc721Token).mint(msg.sender, mintAmount); // Increase the total burned amount totalBurned = totalBurned.add(amount); // Emit event emit BurnToMint(msg.sender, amount, mintAmount); } // Function to stake $SHARES tokens and earn $CORP tokens function stakeShares(uint256 amount) external { require(amount > 0, "Amount must be greater than zero"); require(ERC20(sharesToken).balanceOf(msg.sender) >= amount, "Caller does not have enough $SHARES tokens"); // Calculate reward amount uint256 rewardAmount = calculateSharesReward(msg.sender); // Transfer $SHARES tokens from caller to contract ERC20(sharesToken).transferFrom(msg.sender, address(this), amount); // Update staking information staking[msg.sender].stakedAmount = staking[msg.sender].stakedAmount.add(amount); staking[msg.sender].lastStakeTime = block.timestamp; // Increase total staked amount totalStaked = totalStaked.add(amount); // Mint reward $CORP tokens to caller if (rewardAmount > 0) { ERC721(erc721Token).mint(msg.sender, rewardAmount); } // Emit event emit SharesStaked(msg.sender, amount, rewardAmount); } // Function to calculate $CORP rewards for a given user based on their staked $SHARES tokens function calculateSharesReward(address user) public view returns (uint256) { uint256 stakedAmount = staking[user].stakedAmount; uint256 lastStakeTime = staking[user].lastStakeTime; if (stakedAmount == 0 || lastStakeTime == 0) { return 0; } uint256 rewardAmount = stakedAmount.mul(block.timestamp.sub(lastStakeTime)).mul(stakingRewardRate).div(100).div(365 days); return rewardAmount; } // Function to mint $CORP tokens using $SHARES tokens as payment function mintFromStakedShares(uint256 amount) public { address sender = _msgSender(); // Calculate the $CORP token amount based on the sender's staked $SHARES tokens uint256 corpAmount = calculateSharesReward(sender); require(corpAmount >= amount, "Not enough $CORP rewards"); // Transfer the $SHARES tokens from the sender to the contract shares.transferFrom(sender, address(this), amount); // Mint the corresponding $CORP tokens to the sender corp.mint(sender, corpAmount); // Update the staking information for the sender staking[sender].lastStakeTime = block.timestamp; staking[sender].stakedAmount = staking[sender].stakedAmount.sub(amount); } // Function to burn $REMIX tokens and mint $CORP tokens function burnToMint(uint256 amount) public { address sender = _msgSender(); // Ensure that the $REMIX contract is authorized to burn tokens require(remix.isBurner(sender), "Not authorized to burn tokens"); // Calculate the corresponding $CORP token amount based on the burn ratio uint256 corpAmount = amount.mul(10); require(corpAmount <= maxCorpMintAmount, "Mint amount exceeds maximum"); // Burn the $REMIX tokens from the sender's balance remix.burn(sender, amount); // Mint the corresponding $CORP tokens to the sender corp.mint(sender, corpAmount); } // Function to stake $SHARES tokens and earn $CORP and $SHARES tokens function stakeShares(uint256 amount) public { address sender = _msgSender(); // Ensure that the sender has approved the contract to spend their $SHARES tokens require(shares.allowance(sender, address(this)) >= amount, "Allowance not set for shares"); // Calculate the corresponding staking rewards based on the current inflation rate uint256 inflationRate = getInflationRate(); uint256 corpReward = amount.mul(inflationRate).div(100); uint256 sharesReward = corpReward.div(2); require(corpReward.add(corp.totalSupply()) <= maxCorpMintAmount, "Mint amount exceeds maximum"); // Transfer the $SHARES tokens from the sender to the contract shares.transferFrom(sender, address(this), amount); // Mint the corresponding $CORP and $SHARES tokens to the sender corp.mint(sender, corpReward); shares.mint(sender, sharesReward); // Update the sender's staking information stakingInfo[sender].sharesStaked = stakingInfo[sender].sharesStaked.add(amount); stakingInfo[sender].lastStakedTimestamp = block.timestamp; emit SharesStaked(sender, amount, corpReward, sharesReward); } // Function to allow deployer to mint the erc20 token for giveaways function mintToken(uint256 amount) public onlyOwner { require(totalSupply.add(amount) <= MAX_SUPPLY, "Cannot mint more than the maximum supply"); _balances[msg.sender] = _balances[msg.sender].add(amount); totalSupply = totalSupply.add(amount); emit Transfer(address(0), msg.sender, amount); }
0.4.18