Untitled diff

Created Diff never expires
20 removals
Words removed20
Total words672
Words removed (%)2.98
235 lines
20 additions
Words added20
Total words672
Words added (%)2.98
235 lines
// SPDX-License-Identifier: Unlicensed
// SPDX-License-Identifier: Unlicensed
pragma solidity ^0.8.20;
pragma solidity ^0.8.20;


import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {MerkleProof} from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import {IRouter} from "./interfaces/IRouter.sol";
import {IRouter} from "./interfaces/IRouter.sol";


contract MEOWMiner {
contract CoqInuMiner {
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;


uint256 public EGGS_TO_HATCH_1MINERS = 864000;
uint256 public EGGS_TO_HATCH_1MINERS = 864000;
uint256 PSN = 10000;
uint256 PSN = 10000;
uint256 PSNH = 5000;
uint256 PSNH = 5000;
bool public initialized = false;
bool public initialized = false;


IERC20 public MEOW;
IERC20 public COQ;
IRouter public ROUTER;
IRouter public ROUTER;
bytes32 public merkleRoot;
bytes32 public merkleRoot;


address public treasuryAddress;
address public treasuryAddress;
address public owner;
address public owner;


mapping(address => uint256) public hatcheryMiners;
mapping(address => uint256) public hatcheryMiners;
mapping(address => uint256) public claimedEggs;
mapping(address => uint256) public claimedEggs;
mapping(address => uint256) public lastHatch;
mapping(address => uint256) public lastHatch;
mapping(address => uint256) public lastWithdraw;
mapping(address => uint256) public lastWithdraw;
mapping(address => address) public referrals;
mapping(address => address) public referrals;


uint256 constant HATCH_STEP = 1 days;
uint256 constant HATCH_STEP = 1 days;
uint256 constant HATCH_STEP_MODIFIER = 0.1e18;
uint256 constant HATCH_STEP_MODIFIER = 0.1e18;
uint256 constant BASE_PERCENTAGE = 0.5e18;
uint256 constant BASE_PERCENTAGE = 0.5e18;


uint256 public marketMEOW;
uint256 public marketCoq;


modifier onlyOwner() {
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
require(msg.sender == owner, "not owner");
_;
_;
}
}


constructor(address _treasuryAddress, bytes32 _merkleRoot) {
constructor(address _treasuryAddress, bytes32 _merkleRoot) {
owner = msg.sender;
owner = msg.sender;


MEOW = IERC20(0x8aD25B0083C9879942A64f00F20a70D3278f6187);
COQ = IERC20(0x420FcA0121DC28039145009570975747295f2329);
ROUTER = IRouter(0x60aE616a2155Ee3d9A68541Ba4544862310933d4);
ROUTER = IRouter(0x60aE616a2155Ee3d9A68541Ba4544862310933d4);


treasuryAddress = _treasuryAddress;
treasuryAddress = _treasuryAddress;
merkleRoot = _merkleRoot;
merkleRoot = _merkleRoot;
}
}


function compound(address ref) public {
function compound(address ref) public {
require(initialized);
require(initialized);
if (ref == msg.sender) {
if (ref == msg.sender) {
ref = address(0);
ref = address(0);
}
}
if (
if (
referrals[msg.sender] == address(0) &&
referrals[msg.sender] == address(0) &&
referrals[msg.sender] != msg.sender
referrals[msg.sender] != msg.sender
) {
) {
referrals[msg.sender] = ref;
referrals[msg.sender] = ref;
}
}
uint256 eggsUsed = getMyEggs();
uint256 eggsUsed = getMyEggs();


uint256 newMiners = eggsUsed / EGGS_TO_HATCH_1MINERS;
uint256 newMiners = eggsUsed / EGGS_TO_HATCH_1MINERS;
hatcheryMiners[msg.sender] += newMiners;
hatcheryMiners[msg.sender] += newMiners;
claimedEggs[msg.sender] = 0;
claimedEggs[msg.sender] = 0;
lastHatch[msg.sender] = block.timestamp;
lastHatch[msg.sender] = block.timestamp;


//send referral eggs
//send referral eggs
claimedEggs[referrals[msg.sender]] += eggsUsed / 10;
claimedEggs[referrals[msg.sender]] += eggsUsed / 10;


//boost market to nerf miners hoarding
//boost market to nerf miners hoarding
marketMEOW += eggsUsed / 2;
marketCoq += eggsUsed / 2;
}
}


function withdraw() external {
function withdraw() external {
require(initialized);
require(initialized);
uint256 hasEggs = getMyEggs();
uint256 hasEggs = getMyEggs();


require(hasEggs > 0, "no eggs");
require(hasEggs > 0, "no eggs");
uint256 eggValue = calculateEggSell(hasEggs);
uint256 eggValue = calculateEggSell(hasEggs);
uint256 fee = devFee(eggValue);
uint256 fee = devFee(eggValue);


claimedEggs[msg.sender] = 0;
claimedEggs[msg.sender] = 0;
lastHatch[msg.sender] = block.timestamp;
lastHatch[msg.sender] = block.timestamp;
lastWithdraw[msg.sender] = block.timestamp;
lastWithdraw[msg.sender] = block.timestamp;


// boost market to nerf miners hoarding
// boost market to nerf miners hoarding
marketMEOW += hasEggs;
marketCoq += hasEggs;


MEOW.safeTransfer(treasuryAddress, fee);
COQ.safeTransfer(treasuryAddress, fee);
MEOW.safeTransfer(msg.sender, eggValue - fee);
COQ.safeTransfer(msg.sender, eggValue - fee);
}
}


function depositAvax(uint minAmount, address ref) external payable {
function depositAvax(uint minAmount, address ref) external payable {
require(initialized, "not initialized");
require(initialized, "not initialized");
require(msg.value > 0, "invalid amount");
require(msg.value > 0, "invalid amount");


uint amount = _swap(minAmount);
uint amount = _swap(minAmount);
_deposit(amount, ref, false);
_deposit(amount, ref, false);
}
}


function depositMEOW(uint amount, address ref) external {
function depositCoq(uint amount, address ref) external {
require(initialized, "not initialized");
require(initialized, "not initialized");
require(amount > 0, "invalid amount");
require(amount > 0, "invalid amount");


MEOW.safeTransferFrom(msg.sender, address(this), amount);
COQ.safeTransferFrom(msg.sender, address(this), amount);
_deposit(amount, ref, false);
_deposit(amount, ref, false);
}
}


function depositMEOWWithProof(
function depositCoqWithProof(
uint amount,
uint amount,
address ref,
address ref,
bytes32[] memory proof
bytes32[] memory proof
) external {
) external {
require(initialized, "not initialized");
require(initialized, "not initialized");
require(amount > 0, "invalid amount");
require(amount > 0, "invalid amount");


bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
require(MerkleProof.verify(proof, merkleRoot, leaf), "invalid proof");
require(MerkleProof.verify(proof, merkleRoot, leaf), "invalid proof");


MEOW.safeTransferFrom(msg.sender, address(this), amount);
COQ.safeTransferFrom(msg.sender, address(this), amount);
_deposit(amount, ref, true); // is an holder
_deposit(amount, ref, true); // is an holder
}
}


function _deposit(uint amount, address ref, bool holder) internal {
function _deposit(uint amount, address ref, bool holder) internal {
uint256 eggsBought = calculateEggBuy(amount, getBalance() - amount);
uint256 eggsBought = calculateEggBuy(amount, getBalance() - amount);


if (holder) {
if (holder) {
eggsBought += (eggsBought * 2) / 100; // 2% boost reward
eggsBought += (eggsBought * 2) / 100; // 2% boost reward
}
}


eggsBought -= devFee(eggsBought);
eggsBought -= devFee(eggsBought);
uint256 fee = devFee(amount);
uint256 fee = devFee(amount);


MEOW.safeTransfer(treasuryAddress, fee);
COQ.safeTransfer(treasuryAddress, fee);


claimedEggs[msg.sender] += eggsBought;
claimedEggs[msg.sender] += eggsBought;
compound(ref);
compound(ref);
}
}


function _swap(uint minTokenOut) internal returns (uint) {
function _swap(uint minTokenOut) internal returns (uint) {
uint initialBalance = getBalance();
uint initialBalance = getBalance();


address[] memory path = new address[](2);
address[] memory path = new address[](2);
path[0] = ROUTER.WAVAX();
path[0] = ROUTER.WAVAX();
path[1] = address(MEOW);
path[1] = address(COQ);


ROUTER.swapExactAVAXForTokens{value: msg.value}(
ROUTER.swapExactAVAXForTokens{value: msg.value}(
minTokenOut,
minTokenOut,
path,
path,
address(this),
address(this),
block.timestamp
block.timestamp
);
);


return getBalance() - initialBalance;
return getBalance() - initialBalance;
}
}


//magic trade balancing algorithm
//magic trade balancing algorithm
function calculateTrade(
function calculateTrade(
uint256 rt,
uint256 rt,
uint256 rs,
uint256 rs,
uint256 bs
uint256 bs
) public view returns (uint256) {
) public view returns (uint256) {
return (PSN * bs) / (PSNH + ((PSN * rs + PSNH * rt) / rt));
return (PSN * bs) / (PSNH + ((PSN * rs + PSNH * rt) / rt));
}
}


function calculateEggSell(uint256 eggs) public view returns (uint256) {
function calculateEggSell(uint256 eggs) public view returns (uint256) {
if (eggs == 0) return 0;
if (eggs == 0) return 0;
return calculateTrade(eggs, marketMEOW, getBalance());
return calculateTrade(eggs, marketCoq, getBalance());
}
}


function calculateEggBuy(
function calculateEggBuy(
uint256 eth,
uint256 eth,
uint256 contractBalance
uint256 contractBalance
) public view returns (uint256) {
) public view returns (uint256) {
return calculateTrade(eth, contractBalance, marketMEOW);
return calculateTrade(eth, contractBalance, marketCoq);
}
}


function calculateEggBuySimple(uint256 eth) public view returns (uint256) {
function calculateEggBuySimple(uint256 eth) public view returns (uint256) {
return calculateEggBuy(eth, getBalance());
return calculateEggBuy(eth, getBalance());
}
}


function devFee(uint256 amount) public pure returns (uint256) {
function devFee(uint256 amount) public pure returns (uint256) {
return (amount * 5) / 100;
return (amount * 5) / 100;
}
}


function seedMarket() public payable onlyOwner {
function seedMarket() public payable onlyOwner {
require(marketMEOW == 0);
require(marketCoq == 0);
initialized = true;
initialized = true;
marketMEOW = 86400000000;
marketCoq = 86400000000;
}
}


function getBalance() public view returns (uint256) {
function getBalance() public view returns (uint256) {
return MEOW.balanceOf(address(this));
return COQ.balanceOf(address(this));
}
}


function getMyMiners() public view returns (uint256) {
function getMyMiners() public view returns (uint256) {
return hatcheryMiners[msg.sender];
return hatcheryMiners[msg.sender];
}
}


function getMyEggs() public view returns (uint256) {
function getMyEggs() public view returns (uint256) {
return claimedEggs[msg.sender] + getEggsSinceLastHatch(msg.sender);
return claimedEggs[msg.sender] + getEggsSinceLastHatch(msg.sender);
}
}


function getEggsSinceLastHatch(address adr) public view returns (uint256) {
function getEggsSinceLastHatch(address adr) public view returns (uint256) {
uint256 steps = (block.timestamp - lastWithdraw[msg.sender]) /
uint256 steps = (block.timestamp - lastWithdraw[msg.sender]) /
HATCH_STEP;
HATCH_STEP;


// the percentage is capped at 100%
// the percentage is capped at 100%
// it takes 1 day to reach 100% after a withdrawal
// it takes 1 day to reach 100% after a withdrawal
uint256 percentage = min(
uint256 percentage = min(
1e18,
1e18,
BASE_PERCENTAGE + steps * HATCH_STEP_MODIFIER
BASE_PERCENTAGE + steps * HATCH_STEP_MODIFIER
);
);


uint256 secondsPassed = min(
uint256 secondsPassed = min(
EGGS_TO_HATCH_1MINERS,
EGGS_TO_HATCH_1MINERS,
block.timestamp - lastHatch[adr]
block.timestamp - lastHatch[adr]
);
);
return ((secondsPassed * hatcheryMiners[adr]) * percentage) / 1e18;
return ((secondsPassed * hatcheryMiners[adr]) * percentage) / 1e18;
}
}


function getHalvingPercentage() public view returns (uint256) {
function getHalvingPercentage() public view returns (uint256) {
uint256 steps = (block.timestamp - lastWithdraw[msg.sender]) /
uint256 steps = (block.timestamp - lastWithdraw[msg.sender]) /
HATCH_STEP;
HATCH_STEP;


return min(1e18, BASE_PERCENTAGE + steps * HATCH_STEP_MODIFIER);
return min(1e18, BASE_PERCENTAGE + steps * HATCH_STEP_MODIFIER);
}
}


function min(uint256 a, uint256 b) private pure returns (uint256) {
function min(uint256 a, uint256 b) private pure returns (uint256) {
return a < b ? a : b;
return a < b ? a : b;
}
}
}
}