SecurityLib

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "SecurityLib.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./Constants.sol";

library SecurityLib {

    error SlippageTooHigh(uint256 expected, uint256 actual);
    error FlashLoanDetected();
    error RateLimitExceeded(address user, uint256 lastCall);
    error InvalidTokenPair(address token0, address token1);
    error InsufficientLiquidity(uint256 available, uint256 required);
    error PriceManipulationDetected(uint256 oldPrice, uint256 newPrice);
    error FakeTokenDetected(address token);
    error MEVAttackDetected();
    error PoolDrainAttempt(uint256 remainingLiquidity);

    struct SlippageParams {
        uint256 amountIn;
        uint256 amountOutMin;
        uint256 amountOutMax;
        uint256 maxSlippageBps;
    }

    struct RateLimit {
        uint256 lastCallTime;
        uint256 callCount;
        uint256 windowStart;
    }

    struct PriceValidation {
        uint256 lastPrice;
        uint256 lastUpdateTime;
        uint256 maxDeviationBps;
        bool isValid;
    }

    struct FlashLoanGuard {
        uint256 balanceBefore;
        uint256 balanceAfter;
        bool isFlashLoan;
    }

    function validateSlippage(
        SlippageParams memory params,
        uint256 actualAmountOut
    ) internal pure {

        if (actualAmountOut < params.amountOutMin) {
            revert SlippageTooHigh(params.amountOutMin, actualAmountOut);
        }

        if (actualAmountOut > params.amountOutMax) {
            revert SlippageTooHigh(params.amountOutMax, actualAmountOut);
        }

        uint256 expectedAmount = (params.amountOutMin + params.amountOutMax) / 2;
        if (expectedAmount > 0) {
            uint256 slippageBps;
            if (actualAmountOut < expectedAmount) {
                slippageBps = ((expectedAmount - actualAmountOut) * Constants.BASIS_POINTS) / expectedAmount;
            } else {
                slippageBps = ((actualAmountOut - expectedAmount) * Constants.BASIS_POINTS) / expectedAmount;
            }

            if (slippageBps > params.maxSlippageBps) {
                revert SlippageTooHigh(expectedAmount, actualAmountOut);
            }
        }
    }

    function detectFlashLoan(
        address /* token */,
        uint256 balanceBefore,
        uint256 balanceAfter
    ) internal pure returns (bool) {

        if (balanceAfter > balanceBefore) {
            uint256 increase = balanceAfter - balanceBefore;
            uint256 increasePercentage = (increase * 100) / balanceBefore;

            if (increasePercentage > 1000) {
                return true;
            }
        }

        return false;
    }

    function requireNoFlashLoan(
        address token,
        uint256 balanceBefore
    ) internal view {

        uint256 currentBalance = getTokenBalance(token, address(this));
        if (detectFlashLoan(token, balanceBefore, currentBalance)) {
            revert FlashLoanDetected();
        }
    }

    function checkRateLimit(
        mapping(address => RateLimit) storage rateLimits,
        address user,
        uint256 maxCallsPerWindow,
        uint256 windowDuration
    ) internal {
        RateLimit storage limit = rateLimits[user];
        uint256 currentTime = block.timestamp;

        if (currentTime >= limit.windowStart + windowDuration) {
            limit.windowStart = currentTime;
            limit.callCount = 0;
        }

        if (limit.callCount >= maxCallsPerWindow) {
            revert RateLimitExceeded(user, limit.lastCallTime);
        }

        limit.callCount++;
        limit.lastCallTime = currentTime;
    }

    function validateSwapParams(
        address tokenIn,
        address tokenOut,
        uint256 amountIn,
        uint256 amountOutMin,
        address to
    ) internal pure {
        require(tokenIn != address(0), "Invalid tokenIn");
        require(tokenOut != address(0), "Invalid tokenOut");
        require(to != address(0), "Invalid recipient");
        require(amountIn > 0, "Invalid amount");
        require(amountOutMin > 0, "Invalid min amount");
        require(tokenIn != tokenOut, "Identical tokens");
    }

    function validateToken(address token) internal view returns (bool) {
        if (token == address(0)) return false;

        uint256 size;
        assembly {
            size := extcodesize(token)
        }

        if (size == 0) return false;

        try IERC20(token).totalSupply() returns (uint256) {
            return true;
        } catch {
            return false;
        }
    }

    function validatePriceChange(
        PriceValidation storage priceData,
        uint256 newPrice,
        uint256 maxDeviationBps
    ) internal {
        if (priceData.lastPrice > 0 && priceData.isValid) {
            uint256 priceChange;

            if (newPrice > priceData.lastPrice) {
                priceChange = ((newPrice - priceData.lastPrice) * Constants.BASIS_POINTS) / priceData.lastPrice;
            } else {
                priceChange = ((priceData.lastPrice - newPrice) * Constants.BASIS_POINTS) / priceData.lastPrice;
            }

            if (priceChange > maxDeviationBps) {
                revert PriceManipulationDetected(priceData.lastPrice, newPrice);
            }
        }

        priceData.lastPrice = newPrice;
        priceData.lastUpdateTime = block.timestamp;
        priceData.isValid = true;
    }

    function detectSandwichAttack(
        address user,
        uint256 amountIn,
        uint256 /* amountOut */,
        mapping(address => uint256) storage lastTxAmounts,
        mapping(address => uint256) storage lastTxBlocks
    ) internal view {

        if (lastTxBlocks[user] == block.number - 1) {
            uint256 lastAmount = lastTxAmounts[user];

            if (amountIn > lastAmount * 10 || lastAmount > amountIn * 10) {
                revert MEVAttackDetected();
            }
        }
    }

    function validatePoolHealth(
        uint256 reserve0,
        uint256 reserve1,
        uint256 withdrawAmount0,
        uint256 withdrawAmount1,
        uint256 minLiquidity
    ) internal pure {
        uint256 remainingReserve0 = reserve0 - withdrawAmount0;
        uint256 remainingReserve1 = reserve1 - withdrawAmount1;

        if (remainingReserve0 < minLiquidity || remainingReserve1 < minLiquidity) {
            revert PoolDrainAttempt(remainingReserve0 + remainingReserve1);
        }

        uint256 kBefore = reserve0 * reserve1;
        uint256 kAfter = remainingReserve0 * remainingReserve1;

        if (kAfter < (kBefore * 95) / 100) {
            revert PoolDrainAttempt(kAfter);
        }
    }

    function getTokenBalance(address token, address account) internal view returns (uint256) {
        try IERC20(token).balanceOf(account) returns (uint256 balance) {
            return balance;
        } catch {
            return 0;
        }
    }

    function calculatePercentageChange(
        uint256 oldValue,
        uint256 newValue
    ) internal pure returns (uint256) {
        if (oldValue == 0) return 0;

        if (newValue > oldValue) {
            return ((newValue - oldValue) * Constants.BASIS_POINTS) / oldValue;
        } else {
            return ((oldValue - newValue) * Constants.BASIS_POINTS) / oldValue;
        }
    }

    function validateDeadline(uint256 deadline) internal view {
        require(block.timestamp <= deadline, "Transaction expired");
    }

    function safeTokenTransfer(
        address token,
        address to,
        uint256 amount
    ) internal {
        require(validateToken(token), "Invalid token");
        require(to != address(0), "Zero address");
        require(amount > 0, "Zero amount");

        (bool success, bytes memory data) = token.call(
            abi.encodeWithSelector(IERC20.transfer.selector, to, amount)
        );

        require(success && (data.length == 0 || abi.decode(data, (bool))), "Transfer failed");
    }
}

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}"
    },
    "Constants.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

library Constants {

    string internal constant PROTOCOL_VERSION = "1.0.0";

    string internal constant PROTOCOL_NAME = "DEX Protocol";

    address internal constant ZERO_ADDRESS = address(0);

    uint256 internal constant MAX_UINT256 = type(uint256).max;

    uint128 internal constant MAX_UINT128 = type(uint128).max;

    uint256 internal constant DECIMAL_BASE = 1e18;

    uint256 internal constant MINIMUM_LIQUIDITY = 1000;

    uint256 internal constant MAX_POOLS = 10000;

    uint256 internal constant MIN_SWAP_AMOUNT = 1000;

    uint256 internal constant MAX_SWAP_AMOUNT = 1000000 * DECIMAL_BASE;

    uint256 internal constant K_FACTOR = 1e12;

    uint256 internal constant DEFAULT_SWAP_FEE = 3000;

    uint256 internal constant DEFAULT_WITHDRAW_FEE = 1000;

    uint256 internal constant TOKEN_LISTING_FEE = 1e16;

    uint256 internal constant MAX_FEE_RATE = 5000;

    uint256 internal constant MIN_FEE_RATE = 10;

    uint256 internal constant FEE_BASE = 10000;

    uint256 internal constant BASIS_POINTS = 10000;

    uint256 internal constant PROTOCOL_FEE_SHARE = 2000;

    uint256 internal constant LP_FEE_SHARE = 8000;

    int24 internal constant MIN_TICK_SPACING = 1;

    int24 internal constant MAX_TICK_SPACING = 16384;

    int24 internal constant MIN_TICK = -887272;

    int24 internal constant MAX_TICK = 887272;

    uint256 internal constant PRICE_RATIO_BASE = 1001;

    uint256 internal constant Q96 = 0x1000000000000000000000000;

    uint256 internal constant Q128 = 0x100000000000000000000000000000000;

    uint256 internal constant MIN_VOTING_PERIOD = 3 days;

    uint256 internal constant MAX_VOTING_PERIOD = 30 days;

    uint256 internal constant MIN_TIMELOCK_DELAY = 1 days;

    uint256 internal constant MAX_TIMELOCK_DELAY = 30 days;

    uint256 internal constant MIN_QUORUM = 500;

    uint256 internal constant MAX_QUORUM = 2000;

    uint256 internal constant MIN_PROPOSAL_THRESHOLD = 100;

    uint256 internal constant MAX_SLIPPAGE = 1000;

    uint256 internal constant MIN_SLIPPAGE = 10;

    uint256 internal constant MAX_PRICE_IMPACT = 2000;

    uint256 internal constant WITHDRAW_COOLDOWN = 1 hours;

    uint256 internal constant MAX_TXS_PER_BLOCK = 100;

    uint256 internal constant MAX_GAS_LIMIT = 15000000;

    uint256 internal constant MIN_OBSERVATIONS = 2;

    uint256 internal constant MAX_OBSERVATIONS = 65535;

    uint256 internal constant DEFAULT_CARDINALITY = 100;

    uint256 internal constant MIN_UPDATE_INTERVAL = 1;

    uint256 internal constant MAX_UPDATE_INTERVAL = 3600;

    uint256 internal constant MAX_PRICE_DEVIATION = 500;

    uint256 internal constant MIN_TOKEN_SUPPLY = 1000000 * DECIMAL_BASE;

    uint256 internal constant MAX_TOKEN_SUPPLY = 1000000000 * DECIMAL_BASE;

    uint8 internal constant MAX_DECIMALS = 18;

    uint8 internal constant MIN_DECIMALS = 6;

    uint256 internal constant MAX_TOKEN_NAME_LENGTH = 50;

    uint256 internal constant MAX_TOKEN_SYMBOL_LENGTH = 10;

    uint256 internal constant REWARD_LOCK_PERIOD = 30 days;

    uint256 internal constant MAX_REWARD_APR = 100000;

    uint256 internal constant MIN_REWARD_APR = 100;

    uint256 internal constant TEAM_VESTING_PERIOD = 365 days;

    uint256 internal constant CIRCUIT_BREAKER_THRESHOLD = 5000;

    uint256 internal constant CIRCUIT_BREAKER_COOLDOWN = 2 hours;

    uint256 internal constant MAX_CIRCUIT_BREAKER_TRIGGERS = 3;

    function percentToBasisPoints(uint256 percentage) internal pure returns (uint256) {
        return percentage * 100;
    }

    function basisPointsToPercent(uint256 basisPoints) internal pure returns (uint256) {
        return basisPoints / 100;
    }

    function calculateFee(uint256 amount, uint256 feeRate) internal pure returns (uint256) {
        return (amount * feeRate) / FEE_BASE;
    }

    function isValidFeeRate(uint256 feeRate) internal pure returns (bool) {
        return feeRate >= MIN_FEE_RATE && feeRate <= MAX_FEE_RATE;
    }

    function isValidTick(int24 tick) internal pure returns (bool) {
        return tick >= MIN_TICK && tick <= MAX_TICK;
    }

    function isValidTickSpacing(int24 tickSpacing) internal pure returns (bool) {
        return tickSpacing >= MIN_TICK_SPACING && tickSpacing <= MAX_TICK_SPACING;
    }
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
Factory|addr:0x11a31df5b1cb2afab32f29f6bd845463a1770bc9|verified:true|block:23526099|tx:0x758ca8bd791a27cf7a88b35c692fe7b502ad20a9bd648a5fa04f035617ead6e9|first_check:1759846372

Submitted on: 2025-10-07 16:12:53

Comments

Log in to comment.

No comments yet.