Address
0x364d45abbbd4fbb015fb32d18a2c3d20b5a7bb70Current Holdings
$0.00
TXs sent
not counted
First Active
2026-01-06
block 25,457,439
Last Active
256 days ago
block 25,457,672
Funded By
not identified
Net worth historyi
2 snapshots · to block 27,488,952coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
exact matchREMIXsolc 0.8.33+commit.64118f21runtime exact · creation exact
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
/**
* @title SwapHelper - Intermediary for swaps to avoid INVALID_TO error
*/
contract SwapHelper {
address public immutable parent;
constructor() {
parent = msg.sender;
}
function forward(address token, address to) external {
require(msg.sender == parent, "Only parent");
uint256 balance = IERC20(token).balanceOf(address(this));
if (balance > 0) {
require(IERC20(token).transfer(to, balance), "Forward failed");
}
}
}
/**
* @title REMIX - Autonomous Bot Funding
*/
interface IERC20Extended {
function balanceOf(address) external view returns (uint256);
function transfer(address, uint256) external returns (bool);
function approve(address, uint256) external returns (bool);
function transferFrom(address, address, uint256) external returns (bool);
}
interface IDexRouter {
function factory() external view returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
}
interface IDexFactory {
function getPair(address, address) external view returns (address);
function createPair(address, address) external returns (address);
}
interface IDexPair {
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function token0() external view returns (address);
function token1() external view returns (address);
function totalSupply() external view returns (uint256);
function sync() external;
}
contract REMIX is ERC20, Ownable, ReentrancyGuard {
// ========== CONSTANTS ==========
IDexRouter public immutable router;
SwapHelper public immutable swapHelper;
address public constant HEX = 0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39;
address public constant AER = 0x92337f43FB462163869342E72538744E030EAF55;
address public immutable pairRMXHEX;
address public immutable pairRMXAER;
uint256 private constant MIN_LIQUIDITY = 1000000;
uint256 private constant MAX_SLIPPAGE = 2000;
uint256 private constant POOL_DEPLETION_LIMIT = 9000;
uint256 private constant FAILED_CALL_REDUCTION = 80;
uint256 private constant SAME_BLOCK_REDUCTION = 90;
uint256 private constant JACKPOT_IMMEDIATE = 50;
uint256 private constant BURN_IMMEDIATE = 1000;
uint256 private constant POOL_CONTRIBUTION = 100;
// ========== CONFIG ==========
address public bot1 = 0x5839F1728ccd1cA6013F1858C4400b58B0173eb9;
address public bot2 = 0x26a5ca8735e04df70a3F4219fA091E730c51a7ED;
uint256 public bot1HEX = 200000000000;
uint256 public bot1AER = 40000000000;
uint256 public bot2HEX = 200000000000;
uint256 public bot2AER = 40000000000;
uint256 public targetSupply = 150000000000000000;
uint8 public burnPercentage = 5;
uint8 public maxLPBurnPercentage = 5;
uint16 public mintBuffer = 200;
bool public paused;
bool public mintingPaused;
bool public burningPaused;
bool public rewardsPaused;
uint256 public minHexReserve = 50000000000;
uint256 public minAerReserve = 10000000000;
uint256 public rewardPool;
uint256 public minMaintenanceReward = 500000000;
uint256 public poolRefillThreshold = 5000000000;
uint256 public poolRefillAmount = 10000000000;
bool public autoRefillEnabled = true;
mapping(address => uint256) public lastCallTime;
uint32 public callerCooldown = 5 minutes;
uint256 public lastWorkBlock;
uint256 public cooldownChangeTime;
uint32 public oldCooldownValue;
mapping(address => bool) public hasEverCalled;
mapping(address => uint256) public callCount;
mapping(address => uint256) public totalEarnedByAddress;
uint256 public totalMinted;
uint256 public totalBurned;
uint256 public totalHexSent;
uint256 public totalAerSent;
uint256 public totalRewardsPaid;
uint256 public totalPoolRefills;
// ========== EVENTS ==========
event BotRefilled(address indexed bot, uint256 hexAmount, uint256 aerAmount);
event LPBurned(uint256 amount);
event CallerRewarded(address indexed caller, uint256 reward, string rewardType);
event LiquidityAdded(address indexed pair, uint256 amountRMX, uint256 amountToken, uint256 liquidity);
event EmergencyLPWithdraw(address indexed pair, uint256 amount);
event ConfigUpdated(string param, uint256 value);
event PoolAutoRefilled(uint256 amount);
event PauseToggled(string pauseType, bool state);
// ========== CONSTRUCTOR ==========
constructor() ERC20("Remix", "RMX") Ownable(msg.sender) {
router = IDexRouter(0x165C3410fC91EF562C50559f7d2289fEbed552d9);
swapHelper = new SwapHelper();
IDexFactory factory = IDexFactory(router.factory());
pairRMXHEX = _getOrCreatePair(factory, address(this), HEX);
pairRMXAER = _getOrCreatePair(factory, address(this), AER);
_mint(msg.sender, 200000000000000000);
}
function _getOrCreatePair(IDexFactory factory, address tokenA, address tokenB) private returns (address pair) {
pair = factory.getPair(tokenA, tokenB);
if (pair == address(0)) {
pair = factory.createPair(tokenA, tokenB);
}
}
function decimals() public pure override returns (uint8) {
return 8;
}
// ========== ADD LIQUIDITY ==========
function addInitialLiquidity(
uint256 hexAmount,
uint256 aerAmount,
uint256 rmxForHexPool,
uint256 rmxForAerPool
) external onlyOwner {
require(hexAmount > 0 && rmxForHexPool > 0, "Invalid HEX");
require(aerAmount > 0 && rmxForAerPool > 0, "Invalid AER");
require(rmxForHexPool >= MIN_LIQUIDITY && rmxForAerPool >= MIN_LIQUIDITY, "Below min");
_transfer(msg.sender, address(this), rmxForHexPool + rmxForAerPool);
_addLiquidity(HEX, hexAmount, rmxForHexPool, pairRMXHEX);
_addLiquidity(AER, aerAmount, rmxForAerPool, pairRMXAER);
}
function _addLiquidity(address token, uint256 tokenAmount, uint256 rmxAmount, address pair) private {
require(IERC20Extended(token).transferFrom(msg.sender, address(this), tokenAmount), "Transfer fail");
_approve(address(this), address(router), rmxAmount);
IERC20Extended(token).approve(address(router), tokenAmount);
(uint256 amountA, uint256 amountB, uint256 liquidity) = router.addLiquidity(
address(this), token, rmxAmount, tokenAmount, 0, 0, address(this), block.timestamp + 300
);
require(liquidity > 0, "No liquidity");
emit LiquidityAdded(pair, amountA, amountB, liquidity);
}
// ========== REGULATION ==========
function regulate() external nonReentrant {
require(!paused, "Paused");
require(gasleft() >= 500000, "Low gas");
if (lastWorkBlock == block.number) {
lastCallTime[msg.sender] = block.timestamp - (uint256(callerCooldown) * SAME_BLOCK_REDUCTION / 100);
return;
}
bool isFirstCall = lastCallTime[msg.sender] == 0 && !hasEverCalled[msg.sender];
if (msg.sender != owner() && !isFirstCall) {
uint256 effectiveCooldown = _getEffectiveCooldown(msg.sender);
require(block.timestamp >= lastCallTime[msg.sender] + effectiveCooldown, "Cooldown");
}
uint256 mintedBefore = totalMinted;
uint256 burnedBefore = totalBurned;
bool workDone = false;
bool needsRefill = false;
if (bot1 != address(0) && !mintingPaused) {
(bool hexLow, bool aerLow) = _checkBot(bot1, bot1HEX, bot1AER);
if (hexLow || aerLow) {
needsRefill = true;
workDone = true;
_refillBot(bot1, bot1HEX, bot1AER, hexLow, aerLow);
}
}
if (bot2 != address(0) && !mintingPaused) {
(bool hexLow, bool aerLow) = _checkBot(bot2, bot2HEX, bot2AER);
if (hexLow || aerLow) {
needsRefill = true;
workDone = true;
_refillBot(bot2, bot2HEX, bot2AER, hexLow, aerLow);
}
}
if (!needsRefill && !burningPaused && totalSupply() > targetSupply) {
uint256 burned = _burnLP();
if (burned > 0) workDone = true;
}
if (autoRefillEnabled && rewardPool < poolRefillThreshold && !mintingPaused) {
_refillRewardPool();
}
if (workDone) {
hasEverCalled[msg.sender] = true;
lastWorkBlock = block.number;
lastCallTime[msg.sender] = block.timestamp;
callCount[msg.sender]++;
if (!rewardsPaused) {
_rewardCaller(msg.sender, mintedBefore, burnedBefore);
}
} else {
if (!isFirstCall) {
lastCallTime[msg.sender] = block.timestamp - (uint256(callerCooldown) * FAILED_CALL_REDUCTION / 100);
}
}
}
function _refillRewardPool() private {
_mint(address(this), poolRefillAmount);
rewardPool += poolRefillAmount;
totalMinted += poolRefillAmount;
totalPoolRefills++;
emit PoolAutoRefilled(poolRefillAmount);
}
function _getEffectiveCooldown(address caller) private view returns (uint256) {
uint256 lastCall = lastCallTime[caller];
if (cooldownChangeTime > 0 && lastCall > 0 && lastCall < cooldownChangeTime) {
return uint256(oldCooldownValue);
}
return uint256(callerCooldown);
}
function _rewardCaller(address caller, uint256 mintedBefore, uint256 burnedBefore) private {
uint256 mintedAmount = totalMinted - mintedBefore;
uint256 burnedAmount = totalBurned - burnedBefore;
uint256 rewardToPay = 0;
string memory rewardType = "";
if (mintedAmount > 0) {
uint256 poolContribution = mintedAmount / POOL_CONTRIBUTION;
rewardPool += poolContribution;
rewardToPay = mintedAmount / JACKPOT_IMMEDIATE;
if (rewardPool >= poolContribution * 2) {
uint256 bonus = poolContribution / 2;
rewardToPay += bonus;
rewardPool -= bonus;
}
rewardType = "jackpot";
} else if (burnedAmount > 0) {
uint256 poolContribution = burnedAmount / POOL_CONTRIBUTION;
rewardPool += poolContribution;
rewardToPay = (burnedAmount * 15) / BURN_IMMEDIATE;
rewardType = "burn";
} else {
if (rewardPool >= 10000000000) {
rewardToPay = 2000000000;
} else if (rewardPool >= 5000000000) {
rewardToPay = 1000000000;
} else if (rewardPool >= minMaintenanceReward) {
rewardToPay = minMaintenanceReward;
}
if (rewardToPay > rewardPool) rewardToPay = rewardPool;
if (rewardToPay > 0) rewardPool -= rewardToPay;
rewardType = "maintenance";
}
if (rewardToPay > 0) {
totalEarnedByAddress[caller] += rewardToPay;
_mint(caller, rewardToPay);
totalRewardsPaid += rewardToPay;
emit CallerRewarded(caller, rewardToPay, rewardType);
}
}
// ========== BOT MANAGEMENT ==========
function _checkBot(address bot, uint256 optimalHex, uint256 optimalAer) private view returns (bool needsHex, bool needsAer) {
uint256 botHex = IERC20Extended(HEX).balanceOf(bot);
uint256 botAer = IERC20Extended(AER).balanceOf(bot);
needsHex = optimalHex > 0 && botHex < optimalHex;
needsAer = optimalAer > 0 && botAer < optimalAer;
}
function _refillBot(address bot, uint256 optimalHex, uint256 optimalAer, bool needsHex, bool needsAer) private {
uint256 hexSent = 0;
uint256 aerSent = 0;
if (needsHex) {
uint256 botHex = IERC20Extended(HEX).balanceOf(bot);
if (botHex < optimalHex) {
uint256 needed = optimalHex - botHex;
hexSent = _getTokenAndSend(HEX, needed, bot);
totalHexSent += hexSent;
}
}
if (needsAer) {
uint256 botAer = IERC20Extended(AER).balanceOf(bot);
if (botAer < optimalAer) {
uint256 needed = optimalAer - botAer;
aerSent = _getTokenAndSend(AER, needed, bot);
totalAerSent += aerSent;
}
}
emit BotRefilled(bot, hexSent, aerSent);
}
function _getTokenAndSend(address token, uint256 amount, address recipient) private returns (uint256 sent) {
require(amount > 0, "Zero amount");
uint256 balance = IERC20Extended(token).balanceOf(address(this));
uint256 minReserve = token == HEX ? minHexReserve : minAerReserve;
uint256 available = balance > minReserve ? balance - minReserve : 0;
if (available < amount) {
uint256 needed = amount - available;
uint256 rmxNeeded = _calculateRMXNeeded(token, needed);
if (rmxNeeded == 0) {
if (available > 0) {
require(IERC20Extended(token).transfer(recipient, available), "Transfer fail");
return available;
}
return 0;
}
uint256 toMint = (rmxNeeded * uint256(mintBuffer)) / 100;
_mint(address(this), toMint);
totalMinted += toMint;
uint256 swapped = _swap(token, toMint);
available += swapped;
}
sent = available >= amount ? amount : available;
if (sent > 0) {
require(IERC20Extended(token).transfer(recipient, sent), "Transfer fail");
}
return sent;
}
function _calculateRMXNeeded(address token, uint256 tokenAmount) private view returns (uint256) {
if (tokenAmount == 0) return 0;
address pair = token == HEX ? pairRMXHEX : pairRMXAER;
(uint112 r0, uint112 r1,) = IDexPair(pair).getReserves();
address token0 = IDexPair(pair).token0();
uint256 rmxReserve = token0 == address(this) ? uint256(r0) : uint256(r1);
uint256 tokenReserve = token0 == address(this) ? uint256(r1) : uint256(r0);
if (rmxReserve == 0 || tokenReserve == 0) return 0;
uint256 maxPurchase = (tokenReserve * POOL_DEPLETION_LIMIT) / 10000;
if (tokenAmount >= maxPurchase) tokenAmount = maxPurchase;
if (tokenAmount >= tokenReserve) return 0;
uint256 numerator = rmxReserve * tokenAmount;
if (numerator / rmxReserve != tokenAmount) return 0;
numerator = numerator * 1000;
uint256 denominator = (tokenReserve - tokenAmount) * 997;
if (denominator == 0) return 0;
uint256 rmxNeeded = numerator / denominator;
rmxNeeded = (rmxNeeded * 102) / 100;
if (rmxNeeded > rmxReserve * 10) return 0;
return rmxNeeded;
}
function _swap(address tokenOut, uint256 rmxIn) private returns (uint256 received) {
if (rmxIn == 0) return 0;
_approve(address(this), address(router), rmxIn);
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = tokenOut;
uint256 expected = 0;
try router.getAmountsOut(rmxIn, path) returns (uint[] memory amounts) {
expected = amounts.length >= 2 ? amounts[1] : 0;
} catch {
return 0;
}
if (expected == 0) return 0;
uint256 slippage = 1000;
if (slippage > MAX_SLIPPAGE) slippage = MAX_SLIPPAGE;
uint256 minOut = (expected * (10000 - slippage)) / 10000;
uint256 balanceBefore = IERC20Extended(tokenOut).balanceOf(address(this));
try router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
rmxIn, minOut, path, address(swapHelper), block.timestamp + 300
) {
swapHelper.forward(tokenOut, address(this));
} catch {
return 0;
}
uint256 balanceAfter = IERC20Extended(tokenOut).balanceOf(address(this));
received = balanceAfter > balanceBefore ? balanceAfter - balanceBefore : 0;
return received;
}
// ========== LP BURNING ==========
function _burnLP() private returns (uint256 totalBurnedNow) {
if (totalSupply() <= targetSupply) return 0;
uint256 excess = totalSupply() - targetSupply;
uint256 toBurn = (excess * uint256(burnPercentage)) / 100;
if (toBurn > excess) toBurn = excess;
if (toBurn == 0) return 0;
uint256 burned1 = _burnFromPool(pairRMXHEX, HEX, toBurn / 2);
uint256 burned2 = _burnFromPool(pairRMXAER, AER, toBurn / 2);
totalBurnedNow = burned1 + burned2;
if (totalBurnedNow > 0) {
totalBurned += totalBurnedNow;
emit LPBurned(totalBurnedNow);
}
return totalBurnedNow;
}
function _burnFromPool(address pair, address token, uint256 targetBurn) private returns (uint256 burned) {
if (targetBurn == 0) return 0;
uint256 lpToRemove;
{
(uint112 r0, uint112 r1,) = IDexPair(pair).getReserves();
if (r0 == 0 || r1 == 0) return 0;
address token0 = IDexPair(pair).token0();
uint256 rmxReserve = token0 == address(this) ? uint256(r0) : uint256(r1);
uint256 totalLP = IDexPair(pair).totalSupply();
uint256 ourLP = IERC20Extended(pair).balanceOf(address(this));
if (ourLP == 0 || totalLP == 0 || rmxReserve == 0) return 0;
lpToRemove = (targetBurn * totalLP) / rmxReserve;
if (lpToRemove > ourLP) lpToRemove = ourLP;
uint256 maxLP = (totalLP * uint256(maxLPBurnPercentage)) / 100;
if (lpToRemove > maxLP) lpToRemove = maxLP;
if (lpToRemove < 100) return 0;
}
IERC20Extended(pair).approve(address(router), lpToRemove);
uint256 rmxBefore = balanceOf(address(this));
uint256 tokenBefore = IERC20Extended(token).balanceOf(address(this));
try router.removeLiquidity(address(this), token, lpToRemove, 0, 0, address(this), block.timestamp + 300)
returns (uint256, uint256) {} catch {
return 0;
}
uint256 rmxGot = balanceOf(address(this));
rmxGot = rmxGot > rmxBefore ? rmxGot - rmxBefore : 0;
uint256 tokenGot = IERC20Extended(token).balanceOf(address(this));
tokenGot = tokenGot > tokenBefore ? tokenGot - tokenBefore : 0;
if (rmxGot > 0) {
_burn(address(this), rmxGot);
burned = rmxGot;
}
if (tokenGot > 0) {
IERC20Extended(token).transfer(pair, tokenGot);
IDexPair(pair).sync();
}
return burned;
}
// ========== ADMIN ==========
function setBots(address _bot1, address _bot2) external onlyOwner {
require(_bot1 != address(this) && _bot2 != address(this), "Invalid bot");
bot1 = _bot1;
bot2 = _bot2;
}
function setBot1Levels(uint256 hexAmount, uint256 aerAmount) external onlyOwner {
require(hexAmount <= 10000000000000 && aerAmount <= 10000000000000, "Too high");
bot1HEX = hexAmount;
bot1AER = aerAmount;
}
function setBot2Levels(uint256 hexAmount, uint256 aerAmount) external onlyOwner {
require(hexAmount <= 10000000000000 && aerAmount <= 10000000000000, "Too high");
bot2HEX = hexAmount;
bot2AER = aerAmount;
}
function setTargetSupply(uint256 target) external onlyOwner {
require(target > 0, "Invalid");
targetSupply = target;
}
function setBurnPercentage(uint8 percentage) external onlyOwner {
require(percentage > 0 && percentage <= 100, "Invalid");
burnPercentage = percentage;
emit ConfigUpdated("burnPercentage", percentage);
}
function setMaxLPBurnPercentage(uint8 percentage) external onlyOwner {
require(percentage > 0 && percentage <= 100, "Invalid");
maxLPBurnPercentage = percentage;
emit ConfigUpdated("maxLPBurnPercentage", percentage);
}
function setMintBuffer(uint16 bufferPercent) external onlyOwner {
require(bufferPercent >= 100 && bufferPercent <= 500, "Invalid");
mintBuffer = bufferPercent;
emit ConfigUpdated("mintBuffer", bufferPercent);
}
function setMinReserves(uint256 hexReserve, uint256 aerReserve) external onlyOwner {
require(hexReserve <= 10000000000000 && aerReserve <= 10000000000000, "Too high");
minHexReserve = hexReserve;
minAerReserve = aerReserve;
emit ConfigUpdated("minReserves", hexReserve);
}
function setMinMaintenanceReward(uint256 amount) external onlyOwner {
require(amount > 0 && amount <= 10000000000, "Invalid");
minMaintenanceReward = amount;
emit ConfigUpdated("minMaintenanceReward", amount);
}
function setCallerCooldown(uint32 cooldownSeconds) external onlyOwner {
require(cooldownSeconds >= 60 && cooldownSeconds <= 1 days, "Invalid");
uint32 oldCooldown = callerCooldown;
if (cooldownSeconds > oldCooldown) {
cooldownChangeTime = block.timestamp;
oldCooldownValue = oldCooldown;
}
callerCooldown = cooldownSeconds;
emit ConfigUpdated("callerCooldown", cooldownSeconds);
}
function setAutoRefillConfig(uint256 threshold, uint256 amount, bool enabled) external onlyOwner {
require(threshold <= 100000000000 && amount <= 1000000000000, "Invalid");
poolRefillThreshold = threshold;
poolRefillAmount = amount;
autoRefillEnabled = enabled;
emit ConfigUpdated("autoRefill", enabled ? 1 : 0);
}
function manualRefillRewardPool(uint256 amount) external onlyOwner {
require(amount > 0 && amount <= 10000000000000, "Invalid");
_mint(address(this), amount);
rewardPool += amount;
totalMinted += amount;
totalPoolRefills++;
emit PoolAutoRefilled(amount);
}
function pause() external onlyOwner {
paused = true;
emit PauseToggled("main", true);
}
function unpause() external onlyOwner {
paused = false;
emit PauseToggled("main", false);
}
function toggleMintingPause() external onlyOwner {
mintingPaused = !mintingPaused;
emit PauseToggled("minting", mintingPaused);
}
function toggleBurningPause() external onlyOwner {
burningPaused = !burningPaused;
emit PauseToggled("burning", burningPaused);
}
function toggleRewardsPause() external onlyOwner {
rewardsPaused = !rewardsPaused;
emit PauseToggled("rewards", rewardsPaused);
}
function withdraw(address token, uint256 amount) external onlyOwner {
require(paused && token != address(this), "Invalid");
require(IERC20Extended(token).transfer(owner(), amount), "Fail");
}
function emergencyWithdrawLP(address pair, uint256 amount) external onlyOwner {
require(paused && (pair == pairRMXHEX || pair == pairRMXAER), "Invalid");
require(amount <= IERC20Extended(pair).balanceOf(address(this)), "Insufficient");
require(IERC20Extended(pair).transfer(owner(), amount), "Fail");
emit EmergencyLPWithdraw(pair, amount);
}
function emergencyWithdrawAllLP() external onlyOwner {
require(paused, "Not paused");
uint256 hexLP = IERC20Extended(pairRMXHEX).balanceOf(address(this));
if (hexLP > 0) {
require(IERC20Extended(pairRMXHEX).transfer(owner(), hexLP), "Fail");
emit EmergencyLPWithdraw(pairRMXHEX, hexLP);
}
uint256 aerLP = IERC20Extended(pairRMXAER).balanceOf(address(this));
if (aerLP > 0) {
require(IERC20Extended(pairRMXAER).transfer(owner(), aerLP), "Fail");
emit EmergencyLPWithdraw(pairRMXAER, aerLP);
}
}
// ========== ESSENTIAL VIEWS ==========
function getCooldownRemaining() external view returns (uint256) {
uint256 effectiveCooldown = _getEffectiveCooldown(msg.sender);
if (block.timestamp >= lastCallTime[msg.sender] + effectiveCooldown) return 0;
return (lastCallTime[msg.sender] + effectiveCooldown) - block.timestamp;
}
function getCooldownRemainingFor(address caller) external view returns (uint256) {
uint256 effectiveCooldown = _getEffectiveCooldown(caller);
if (block.timestamp >= lastCallTime[caller] + effectiveCooldown) return 0;
return (lastCallTime[caller] + effectiveCooldown) - block.timestamp;
}
function checkBots() external view returns (bool, bool, bool, bool) {
bool bot1NeedsHex;
bool bot1NeedsAer;
bool bot2NeedsHex;
bool bot2NeedsAer;
if (bot1 != address(0)) {
(bot1NeedsHex, bot1NeedsAer) = _checkBot(bot1, bot1HEX, bot1AER);
}
if (bot2 != address(0)) {
(bot2NeedsHex, bot2NeedsAer) = _checkBot(bot2, bot2HEX, bot2AER);
}
return (bot1NeedsHex, bot1NeedsAer, bot2NeedsHex, bot2NeedsAer);
}
function getStats() external view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
return (totalMinted, totalBurned, totalHexSent, totalAerSent, totalSupply(), totalRewardsPaid);
}
function getPoolInfo() external view returns (uint256, uint256, uint256, bool, uint256) {
return (rewardPool, poolRefillThreshold, poolRefillAmount, autoRefillEnabled, totalPoolRefills);
}
function getCallerStats(address caller) external view returns (uint256, uint256, uint256) {
return (callCount[caller], totalEarnedByAddress[caller], this.getCooldownRemainingFor(caller));
}
receive() external payable {
revert("No ETH");
}
}