Address
0x01db2c1924f1f62a3431be71a9fd263da307abe6Current Holdings
$0.00
TXs sent
not counted
First Active
2026-01-02
block 25,422,568
Last Active
257 days ago
block 25,426,629
Funded By
not identified
Net worth historyi
4 snapshots · to block 27,455,299coverage 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 REMIX - Deflationary Arb Bot Fuel Station
* @notice Generates HEX and AER by selling minted RMX, then burns more than minted
* @dev Each operation: Mint X, Burn 1.1X = Net 10% deflationary
* @custom:security Fully audited with adjustable thresholds and edge case handling
* @custom:version 1.0.2 - Stack depth and warnings resolved
*/
interface IERC20Extended {
function balanceOf(address) external view returns (uint256);
function transfer(address, uint256) external returns (bool);
function approve(address, uint256) external returns (bool);
}
interface IAerPool {
function STAKE_IS_ACTIVE() external view returns (bool);
function HEX_REDEMPTION_RATE() external view returns (uint256);
function CURRENT_STAKE_PRINCIPAL() external view returns (uint256);
function totalSupply() external view returns (uint256);
}
interface IDexRouter {
function factory() external view returns (address);
function WPLS() external view returns (address);
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 token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function totalSupply() external view returns (uint256);
function sync() external;
}
contract REMIX is ERC20, Ownable, ReentrancyGuard {
// ========== CONSTANTS ==========
uint256 private constant MAX_BPS = 10000;
uint256 private constant MIN_REFILL_BPS = 1000;
uint256 private constant MAX_REFILL_BPS = 9000;
uint256 private constant MIN_COOLDOWN = 1 minutes;
uint256 private constant MAX_COOLDOWN = 1 hours;
uint256 private constant MAX_SLIPPAGE_BPS = 1000;
uint256 private constant MAX_SUPPLY_CAP = 1_000_000 * 10**8;
uint256 private constant MAX_MINT_PER_EXECUTION = 1000 * 10**8;
uint256 private constant MAX_OPTIMAL_BALANCE = 100_000 * 10**8;
// ========== IMMUTABLES ==========
IDexRouter public immutable router;
address public constant HEX = 0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39;
address public constant AER = 0x92337f43FB462163869342E72538744E030EAF55;
address public immutable WPLS;
IAerPool public immutable aerPool;
address public immutable pairRMXHEX;
address public immutable pairRMXAER;
// ========== ARB BOT CONFIG ==========
address public arbBot1;
address public arbBot2;
uint256 public bot1OptimalHex = 100 * 10**8;
uint256 public bot1OptimalAer = 20 * 10**8;
uint256 public bot2OptimalHex = 200 * 10**8;
uint256 public bot2OptimalAer = 40 * 10**8;
uint256 public refillThresholdBps = 5000;
// ========== DEFLATION CONFIG ==========
uint256 public burnMultiplierBps = 11000;
// ========== OPERATION CONFIG ==========
uint256 public cooldownPeriod = 5 minutes;
uint256 public slippageBps = 300;
uint256 public minLPThreshold = 100 * 10**8;
uint256 public maxSupplyCap = MAX_SUPPLY_CAP;
uint256 public minOperationValue = 10 * 10**8;
uint256 public reservedForRewards = 1000 * 10**8;
uint256 public maxAmountSanity = 1_000_000 * 10**8;
uint256 public minGenerationThresholdBps = 8000;
uint256 public lpSafetyMultiplier = 2;
// ========== STATE ==========
uint256 public lastExecutionTime;
uint256 public totalExecutions;
uint256 public totalRMXMinted;
uint256 public totalRMXBurned;
uint256 public totalHexFunded;
uint256 public totalAerFunded;
uint256 public failedRecycleHex;
uint256 public failedRecycleAer;
bool public paused;
// ========== EVENTS ==========
event Executed(
address indexed caller,
uint256 rewardMinted,
uint256 netBurned,
uint256 supplyChange
);
event BotFunded(address indexed bot, uint256 hexAmount, uint256 aerAmount);
event RMXMinted(uint256 amount, string reason);
event RMXBurned(uint256 amount, string reason);
event CallerRewarded(address indexed caller, uint256 amount);
event Deflation(uint256 minted, uint256 burned, uint256 netDeflation);
event EmergencyAction(string action, address indexed token, uint256 amount);
event RecycleFailed(address indexed pair, address indexed token, uint256 amount);
event StuckTokensRecovered(address indexed token, uint256 amount);
event ThresholdUpdated(string parameter, uint256 oldValue, uint256 newValue);
// ========== ERRORS ==========
error Paused();
error NotPaused();
error CooldownActive();
error ZeroAddress();
error InvalidAddress();
error InvalidParameter(string param);
error SupplyCapExceeded();
error TransferFailed();
error PairCreationFailed();
error InsufficientGeneration();
// ========== CONSTRUCTOR ==========
constructor() ERC20("Remix", "RMX") Ownable(msg.sender) {
router = IDexRouter(0x165C3410fC91EF562C50559f7d2289fEbed552d9);
WPLS = router.WPLS();
aerPool = IAerPool(AER);
IDexFactory factory = IDexFactory(router.factory());
pairRMXHEX = _getOrCreatePair(factory, address(this), HEX);
pairRMXAER = _getOrCreatePair(factory, address(this), AER);
if (pairRMXHEX == address(0)) revert PairCreationFailed();
if (pairRMXAER == address(0)) revert PairCreationFailed();
_mint(owner(), 2000 * 10**8);
}
function _getOrCreatePair(IDexFactory factory, address tokenA, address tokenB) private returns (address) {
address pair = factory.getPair(tokenA, tokenB);
if (pair == address(0)) {
pair = factory.createPair(tokenA, tokenB);
}
return pair;
}
function decimals() public pure override returns (uint8) {
return 8;
}
// ========== MAIN EXECUTION ==========
function execute() external nonReentrant returns (uint256 rewardMinted) {
if (paused) revert Paused();
if (block.timestamp < lastExecutionTime + cooldownPeriod) revert CooldownActive();
uint256 supplyBefore = totalSupply();
uint256 totalNetBurned;
// Fuel bots
{
(, , uint256 burned1) = _fuelBot(arbBot1, bot1OptimalHex, bot1OptimalAer);
(, , uint256 burned2) = _fuelBot(arbBot2, bot2OptimalHex, bot2OptimalAer);
totalNetBurned = burned1 + burned2;
}
// Caller reward
if (totalSupply() + 1 * 10**8 <= maxSupplyCap) {
rewardMinted = 1 * 10**8;
_mint(msg.sender, rewardMinted);
totalRMXMinted += rewardMinted;
emit CallerRewarded(msg.sender, rewardMinted);
emit RMXMinted(rewardMinted, "Caller reward");
}
// Update state
lastExecutionTime = block.timestamp;
totalExecutions++;
// Burn excess
uint256 excess = balanceOf(address(this));
if (excess > 0) {
_burn(address(this), excess);
totalRMXBurned += excess;
totalNetBurned += excess;
emit RMXBurned(excess, "Excess cleanup");
}
uint256 supplyAfter = totalSupply();
uint256 supplyChange = supplyBefore > supplyAfter ? supplyBefore - supplyAfter : 0;
emit Executed(msg.sender, rewardMinted, totalNetBurned, supplyChange);
return rewardMinted;
}
// ========== BOT FUELING ==========
function _fuelBot(
address bot,
uint256 optimalHex,
uint256 optimalAer
) private returns (uint256 hexSent, uint256 aerSent, uint256 netBurned) {
if (bot == address(0)) return (0, 0, 0);
if (bot == address(this)) return (0, 0, 0);
if (optimalHex == 0 && optimalAer == 0) return (0, 0, 0);
uint256 botHex = IERC20Extended(HEX).balanceOf(bot);
uint256 botAer = IERC20Extended(AER).balanceOf(bot);
uint256 hexThreshold = (optimalHex * refillThresholdBps) / MAX_BPS;
uint256 aerThreshold = (optimalAer * refillThresholdBps) / MAX_BPS;
// Generate HEX
if (optimalHex > 0 && botHex < hexThreshold) {
uint256 hexNeeded = optimalHex - botHex;
if (hexNeeded >= minOperationValue) {
(uint256 hexGenerated, uint256 burned) = _generateHex(hexNeeded);
if (hexGenerated > 0) {
if (!IERC20Extended(HEX).transfer(bot, hexGenerated)) {
revert TransferFailed();
}
hexSent = hexGenerated;
totalHexFunded += hexGenerated;
netBurned += burned;
}
}
}
// Generate AER
if (optimalAer > 0 && botAer < aerThreshold) {
uint256 aerNeeded = optimalAer - botAer;
if (aerNeeded >= minOperationValue) {
(uint256 aerGenerated, uint256 burned) = _generateAer(aerNeeded);
if (aerGenerated > 0) {
if (!IERC20Extended(AER).transfer(bot, aerGenerated)) {
revert TransferFailed();
}
aerSent = aerGenerated;
totalAerFunded += aerGenerated;
netBurned += burned;
}
}
}
if (hexSent > 0 || aerSent > 0) {
emit BotFunded(bot, hexSent, aerSent);
}
}
// ========== RATE CALCULATION ==========
function getTargetRate() public view returns (uint256 rate) {
bool isStake = aerPool.STAKE_IS_ACTIVE();
if (isStake) {
uint256 treasury = IERC20Extended(HEX).balanceOf(AER);
uint256 principal = aerPool.CURRENT_STAKE_PRINCIPAL();
uint256 supply = aerPool.totalSupply();
if (supply == 0) return 0;
uint256 backing = treasury + principal;
if (backing == 0) return 0;
return (backing * 10**8) / supply;
} else {
uint256 redemptionRate = aerPool.HEX_REDEMPTION_RATE();
if (redemptionRate == 0) return 0;
return redemptionRate;
}
}
// ========== CAPITAL GENERATION ==========
function _generateHex(uint256 hexNeeded) private returns (uint256 hexGenerated, uint256 netBurned) {
if (hexNeeded == 0) return (0, 0);
uint256 hexBal = IERC20Extended(HEX).balanceOf(address(this));
if (hexBal >= hexNeeded) {
return (hexNeeded, 0);
}
uint256 stillNeeded = hexNeeded - hexBal;
uint256 targetRate = getTargetRate();
if (targetRate == 0) return (0, 0);
(, uint256 burned) = _mintSellBurnLP(pairRMXHEX, HEX, stillNeeded, targetRate);
uint256 finalBalance = IERC20Extended(HEX).balanceOf(address(this));
uint256 minRequired = (hexNeeded * minGenerationThresholdBps) / MAX_BPS;
if (finalBalance < minRequired) {
return (0, burned);
}
hexGenerated = finalBalance >= hexNeeded ? hexNeeded : finalBalance;
netBurned = burned;
}
function _generateAer(uint256 aerNeeded) private returns (uint256 aerGenerated, uint256 netBurned) {
if (aerNeeded == 0) return (0, 0);
uint256 aerBal = IERC20Extended(AER).balanceOf(address(this));
if (aerBal >= aerNeeded) {
return (aerNeeded, 0);
}
uint256 stillNeeded = aerNeeded - aerBal;
uint256 targetRate = getTargetRate();
if (targetRate == 0) return (0, 0);
(, uint256 burned) = _mintSellBurnLP(pairRMXAER, AER, stillNeeded, targetRate);
uint256 finalBalance = IERC20Extended(AER).balanceOf(address(this));
uint256 minRequired = (aerNeeded * minGenerationThresholdBps) / MAX_BPS;
if (finalBalance < minRequired) {
return (0, burned);
}
aerGenerated = finalBalance >= aerNeeded ? aerNeeded : finalBalance;
netBurned = burned;
}
// ========== MINT/SELL/BURN ==========
function _mintSellBurnLP(
address pair,
address token,
uint256 amountNeeded,
uint256 targetRate
) private returns (uint256 generated, uint256 netBurned) {
if (pair == address(0) || amountNeeded == 0) return (0, 0);
if (!_pairHasLiquidity(pair)) return (0, 0);
uint256 rmxToMint = _calculateMintAmount(amountNeeded, targetRate, pair);
if (rmxToMint == 0) return (0, 0);
return _executeMintBurnCycle(pair, token, rmxToMint);
}
function _calculateMintAmount(
uint256 amountNeeded,
uint256 targetRate,
address pair
) private view returns (uint256) {
if (targetRate == 0) return 0;
// Sanity check
if (amountNeeded > maxAmountSanity) {
amountNeeded = maxAmountSanity;
}
// Check pool health
(uint256 rmxReserve, ) = _getLPReserves(pair);
if (rmxReserve <= minLPThreshold * lpSafetyMultiplier) return 0;
// Calculate mint amount
uint256 rmxToMint = (amountNeeded * 10**8 * 120) / (targetRate * 100);
// Apply minimum
if (rmxToMint < 1 * 10**8) rmxToMint = 1 * 10**8;
// Check burn feasibility
return _validateMintAmount(rmxToMint, rmxReserve);
}
function _validateMintAmount(
uint256 rmxToMint,
uint256 rmxReserve
) private view returns (uint256) {
uint256 rmxToBurn = (rmxToMint * burnMultiplierBps) / MAX_BPS;
uint256 maxRemovable = rmxReserve > minLPThreshold ? rmxReserve - minLPThreshold : 0;
if (rmxToBurn > maxRemovable) {
rmxToMint = (maxRemovable * MAX_BPS) / burnMultiplierBps;
}
if (rmxToMint < 1 * 10**8) return 0;
// Check supply cap
if (rmxToMint > MAX_MINT_PER_EXECUTION) rmxToMint = MAX_MINT_PER_EXECUTION;
uint256 effectiveCap = maxSupplyCap > reservedForRewards
? maxSupplyCap - reservedForRewards
: maxSupplyCap;
if (totalSupply() + rmxToMint > effectiveCap) {
if (totalSupply() >= effectiveCap) return 0;
rmxToMint = effectiveCap - totalSupply();
}
return rmxToMint;
}
function _executeMintBurnCycle(
address pair,
address token,
uint256 rmxToMint
) private returns (uint256 generated, uint256 netBurned) {
_mint(address(this), rmxToMint);
totalRMXMinted += rmxToMint;
emit RMXMinted(rmxToMint, "Deflationary cycle");
uint256 tokenFromSale = _sellRMX(token, rmxToMint);
uint256 burned = _removeLPAndBurn(pair, token, rmxToMint);
if (burned > rmxToMint) {
netBurned = burned - rmxToMint;
emit Deflation(rmxToMint, burned, netBurned);
}
return (tokenFromSale, netBurned);
}
function _removeLPAndBurn(
address pair,
address token,
uint256 minted
) private returns (uint256 burned) {
uint256 rmxToBurn = (minted * burnMultiplierBps) / MAX_BPS;
(uint256 rmxReceived, uint256 tokenFromLP) = _removeLPExactRMX(pair, token, rmxToBurn);
if (rmxReceived > 0) {
_burn(address(this), rmxReceived);
totalRMXBurned += rmxReceived;
emit RMXBurned(rmxReceived, "Deflationary burn");
burned = rmxReceived;
}
if (tokenFromLP > 0) {
_addSingleSided(pair, token, tokenFromLP);
}
return burned;
}
// ========== SWAP & LP HELPERS ==========
function _sellRMX(address token, uint256 rmxAmount) private returns (uint256) {
if (rmxAmount == 0) return 0;
address[] memory path = new address[](2);
path[0] = address(this);
path[1] = token;
uint256 expectedOut = _getExpectedOutput(rmxAmount, path);
if (expectedOut == 0) return 0;
uint256 minOut = (expectedOut * (MAX_BPS - slippageBps)) / MAX_BPS;
_forceApprove(address(this), address(router), rmxAmount);
uint256 received = _executeSwap(token, rmxAmount, minOut, path);
if (received < minOut) {
return 0;
}
return received;
}
function _getExpectedOutput(
uint256 amountIn,
address[] memory path
) private view returns (uint256) {
try router.getAmountsOut(amountIn, path) returns (uint256[] memory amounts) {
if (amounts.length < 2) return 0;
return amounts[1];
} catch {
return 0;
}
}
function _executeSwap(
address token,
uint256 rmxAmount,
uint256 minOut,
address[] memory path
) private returns (uint256) {
uint256 balanceBefore = IERC20Extended(token).balanceOf(address(this));
try router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
rmxAmount,
minOut,
path,
address(this),
block.timestamp + 300
) {
uint256 balanceAfter = IERC20Extended(token).balanceOf(address(this));
return balanceAfter > balanceBefore ? balanceAfter - balanceBefore : 0;
} catch {
return 0;
}
}
function _removeLPExactRMX(
address pair,
address token,
uint256 exactRMXWanted
) private returns (uint256 rmxReceived, uint256 tokenReceived) {
(uint256 rmxReserve, uint256 totalLP) = _getLPReserves(pair);
if (rmxReserve == 0 || totalLP == 0) return (0, 0);
if (rmxReserve <= minLPThreshold) return (0, 0);
uint256 maxRemovable = rmxReserve - minLPThreshold;
if (exactRMXWanted > maxRemovable) exactRMXWanted = maxRemovable;
uint256 lpNeeded = (exactRMXWanted * totalLP) / rmxReserve;
lpNeeded = _validateLPAmount(pair, lpNeeded);
if (lpNeeded == 0) return (0, 0);
return _executeRemoveLiquidity(pair, token, lpNeeded);
}
function _getLPReserves(address pair) private view returns (uint256 rmxReserve, uint256 totalLP) {
(uint112 r0, uint112 r1, ) = IDexPair(pair).getReserves();
if (r0 == 0 || r1 == 0) return (0, 0);
address token0 = IDexPair(pair).token0();
rmxReserve = token0 == address(this) ? uint256(r0) : uint256(r1);
totalLP = IDexPair(pair).totalSupply();
}
function _validateLPAmount(
address pair,
uint256 lpNeeded
) private view returns (uint256) {
uint256 lpBalance = IERC20Extended(pair).balanceOf(address(this));
if (lpNeeded > lpBalance) {
lpNeeded = lpBalance;
}
return lpNeeded;
}
function _executeRemoveLiquidity(
address pair,
address token,
uint256 lpAmount
) private returns (uint256 rmxReceived, uint256 tokenReceived) {
_forceApprove(pair, address(router), lpAmount);
uint256 rmxBefore = balanceOf(address(this));
uint256 tokenBefore = IERC20Extended(token).balanceOf(address(this));
try router.removeLiquidity(
address(this),
token,
lpAmount,
0,
0,
address(this),
block.timestamp + 300
) returns (uint256, uint256) {
rmxReceived = balanceOf(address(this)) - rmxBefore;
tokenReceived = IERC20Extended(token).balanceOf(address(this)) - tokenBefore;
return (rmxReceived, tokenReceived);
} catch {
return (0, 0);
}
}
function _addSingleSided(address pair, address token, uint256 amount) private {
if (amount == 0) return;
if (!IERC20Extended(token).transfer(pair, amount)) {
if (token == HEX) {
failedRecycleHex += amount;
} else if (token == AER) {
failedRecycleAer += amount;
}
emit RecycleFailed(pair, token, amount);
return;
}
try IDexPair(pair).sync() {} catch {}
}
function _forceApprove(address token, address spender, uint256 amount) private {
IERC20Extended(token).approve(spender, 0);
IERC20Extended(token).approve(spender, amount);
}
function _pairHasLiquidity(address pair) private view returns (bool) {
try IDexPair(pair).getReserves() returns (uint112 r0, uint112 r1, uint32) {
return r0 > 0 && r1 > 0;
} catch {
return false;
}
}
// ========== VIEW FUNCTIONS ==========
function canExecute() external view returns (bool) {
if (paused) return false;
if (block.timestamp < lastExecutionTime + cooldownPeriod) return false;
return true;
}
function getBotStatus(address bot) external view returns (
uint256 hexBalance,
uint256 aerBalance,
uint256 hexOptimal,
uint256 aerOptimal,
uint256 hexThreshold,
uint256 aerThreshold,
bool needsHex,
bool needsAer,
bool contractPaused
) {
hexBalance = IERC20Extended(HEX).balanceOf(bot);
aerBalance = IERC20Extended(AER).balanceOf(bot);
if (bot == arbBot1) {
hexOptimal = bot1OptimalHex;
aerOptimal = bot1OptimalAer;
} else if (bot == arbBot2) {
hexOptimal = bot2OptimalHex;
aerOptimal = bot2OptimalAer;
}
hexThreshold = (hexOptimal * refillThresholdBps) / MAX_BPS;
aerThreshold = (aerOptimal * refillThresholdBps) / MAX_BPS;
needsHex = hexBalance < hexThreshold;
needsAer = aerBalance < aerThreshold;
contractPaused = paused;
}
function getStats() external view returns (
uint256 executions,
uint256 rmxMinted,
uint256 rmxBurned,
uint256 netDeflation,
uint256 hexFunded,
uint256 aerFunded,
uint256 currentSupply,
uint256 nextExecutionTime
) {
netDeflation = totalRMXBurned > totalRMXMinted
? totalRMXBurned - totalRMXMinted
: 0;
return (
totalExecutions,
totalRMXMinted,
totalRMXBurned,
netDeflation,
totalHexFunded,
totalAerFunded,
totalSupply(),
lastExecutionTime + cooldownPeriod
);
}
function getLPInfo(address pair) external view returns (
uint256 rmxReserve,
uint256 tokenReserve,
uint256 lpOwnedByContract,
uint256 totalLPSupply,
address tokenAddress,
bool hasLiquidity,
uint256 rmxPrice
) {
try IDexPair(pair).getReserves() returns (uint112 r0, uint112 r1, uint32) {
address token0 = IDexPair(pair).token0();
rmxReserve = token0 == address(this) ? uint256(r0) : uint256(r1);
tokenReserve = token0 == address(this) ? uint256(r1) : uint256(r0);
tokenAddress = token0 == address(this) ? IDexPair(pair).token1() : token0;
hasLiquidity = r0 > 0 && r1 > 0;
lpOwnedByContract = IERC20Extended(pair).balanceOf(address(this));
totalLPSupply = IDexPair(pair).totalSupply();
if (rmxReserve > 0) {
rmxPrice = (tokenReserve * 10**8) / rmxReserve;
}
} catch {
hasLiquidity = false;
}
}
function getFailedRecycleAmounts() external view returns (
uint256 hexAmount,
uint256 aerAmount
) {
return (failedRecycleHex, failedRecycleAer);
}
function getThresholds() external view returns (
uint256 reservedRewards,
uint256 maxSanity,
uint256 minGenerationBps,
uint256 lpSafety,
uint256 minOpValue,
uint256 minLPThresh
) {
return (
reservedForRewards,
maxAmountSanity,
minGenerationThresholdBps,
lpSafetyMultiplier,
minOperationValue,
minLPThreshold
);
}
// ========== ADMIN FUNCTIONS ==========
function setArbBots(address _bot1, address _bot2) external onlyOwner {
if (_bot1 == address(0) && _bot2 == address(0)) revert ZeroAddress();
if (_bot1 == address(this) || _bot2 == address(this)) revert InvalidAddress();
if (_bot1 != address(0) && _bot1 == _bot2) revert InvalidAddress();
arbBot1 = _bot1;
arbBot2 = _bot2;
}
function setBotOptimalBalances(
uint256 _bot1Hex,
uint256 _bot1Aer,
uint256 _bot2Hex,
uint256 _bot2Aer
) external onlyOwner {
if (_bot1Hex > MAX_OPTIMAL_BALANCE) revert InvalidParameter("bot1Hex");
if (_bot1Aer > MAX_OPTIMAL_BALANCE) revert InvalidParameter("bot1Aer");
if (_bot2Hex > MAX_OPTIMAL_BALANCE) revert InvalidParameter("bot2Hex");
if (_bot2Aer > MAX_OPTIMAL_BALANCE) revert InvalidParameter("bot2Aer");
bot1OptimalHex = _bot1Hex;
bot1OptimalAer = _bot1Aer;
bot2OptimalHex = _bot2Hex;
bot2OptimalAer = _bot2Aer;
}
function setRefillThreshold(uint256 _bps) external onlyOwner {
if (_bps < MIN_REFILL_BPS || _bps > MAX_REFILL_BPS) {
revert InvalidParameter("refillThreshold");
}
uint256 oldValue = refillThresholdBps;
refillThresholdBps = _bps;
emit ThresholdUpdated("refillThreshold", oldValue, _bps);
}
function setBurnMultiplier(uint256 _bps) external onlyOwner {
if (_bps < 10000 || _bps > 20000) revert InvalidParameter("burnMultiplier");
uint256 oldValue = burnMultiplierBps;
burnMultiplierBps = _bps;
emit ThresholdUpdated("burnMultiplier", oldValue, _bps);
}
function setCooldown(uint256 _cooldown) external onlyOwner {
if (_cooldown < MIN_COOLDOWN || _cooldown > MAX_COOLDOWN) {
revert InvalidParameter("cooldown");
}
uint256 oldValue = cooldownPeriod;
cooldownPeriod = _cooldown;
emit ThresholdUpdated("cooldown", oldValue, _cooldown);
}
function setSlippage(uint256 _bps) external onlyOwner {
if (_bps > MAX_SLIPPAGE_BPS) revert InvalidParameter("slippage");
uint256 oldValue = slippageBps;
slippageBps = _bps;
emit ThresholdUpdated("slippage", oldValue, _bps);
}
function setMinLPThreshold(uint256 _threshold) external onlyOwner {
if (_threshold > 10000 * 10**8) revert InvalidParameter("minLPThreshold");
uint256 oldValue = minLPThreshold;
minLPThreshold = _threshold;
emit ThresholdUpdated("minLPThreshold", oldValue, _threshold);
}
function setMinOperationValue(uint256 _value) external onlyOwner {
if (_value > 1000 * 10**8) revert InvalidParameter("minOperationValue");
uint256 oldValue = minOperationValue;
minOperationValue = _value;
emit ThresholdUpdated("minOperationValue", oldValue, _value);
}
function setReservedForRewards(uint256 _amount) external onlyOwner {
if (_amount > maxSupplyCap / 10) revert InvalidParameter("reservedForRewards");
uint256 oldValue = reservedForRewards;
reservedForRewards = _amount;
emit ThresholdUpdated("reservedForRewards", oldValue, _amount);
}
function setMaxAmountSanity(uint256 _amount) external onlyOwner {
if (_amount < 1000 * 10**8) revert InvalidParameter("maxAmountSanity");
if (_amount > maxSupplyCap) revert InvalidParameter("maxAmountSanity");
uint256 oldValue = maxAmountSanity;
maxAmountSanity = _amount;
emit ThresholdUpdated("maxAmountSanity", oldValue, _amount);
}
function setMinGenerationThreshold(uint256 _bps) external onlyOwner {
if (_bps < 5000 || _bps > 9500) revert InvalidParameter("minGenerationThreshold");
uint256 oldValue = minGenerationThresholdBps;
minGenerationThresholdBps = _bps;
emit ThresholdUpdated("minGenerationThreshold", oldValue, _bps);
}
function setLPSafetyMultiplier(uint256 _multiplier) external onlyOwner {
if (_multiplier < 1 || _multiplier > 5) revert InvalidParameter("lpSafetyMultiplier");
uint256 oldValue = lpSafetyMultiplier;
lpSafetyMultiplier = _multiplier;
emit ThresholdUpdated("lpSafetyMultiplier", oldValue, _multiplier);
}
function pause() external onlyOwner {
paused = true;
}
function unpause() external onlyOwner {
paused = false;
}
function recoverStuckTokens() external onlyOwner {
if (failedRecycleHex > 0) {
uint256 amount = failedRecycleHex;
failedRecycleHex = 0;
_addSingleSided(pairRMXHEX, HEX, amount);
emit StuckTokensRecovered(HEX, amount);
}
if (failedRecycleAer > 0) {
uint256 amount = failedRecycleAer;
failedRecycleAer = 0;
_addSingleSided(pairRMXAER, AER, amount);
emit StuckTokensRecovered(AER, amount);
}
}
function emergencyWithdraw(address token, uint256 amount, address recipient) external onlyOwner {
if (!paused) revert NotPaused();
if (recipient == address(0)) revert ZeroAddress();
if (recipient == address(this)) revert InvalidAddress();
if (!IERC20Extended(token).transfer(recipient, amount)) {
revert TransferFailed();
}
emit EmergencyAction("Withdraw", token, amount);
}
receive() external payable {}
}