LiquidityMarketplace

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/LM.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.0;\r
\r
// SafeMath library for safe arithmetic operations\r
library SafeMath {\r
    function add(uint256 a, uint256 b) internal pure returns (uint256) {\r
        uint256 c = a + b;\r
        require(c >= a, "SafeMath: addition overflow");\r
        return c;\r
    }\r
\r
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\r
        require(b <= a, "SafeMath: subtraction overflow");\r
        return a - b;\r
    }\r
\r
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\r
        if (a == 0) return 0;\r
        uint256 c = a * b;\r
        require(c / a == b, "SafeMath: multiplication overflow");\r
        return c;\r
    }\r
\r
    function div(uint256 a, uint256 b) internal pure returns (uint256) {\r
        require(b > 0, "SafeMath: division by zero");\r
        return a / b;\r
    }\r
}\r
\r
// Ownable contract for access control\r
contract Ownable {\r
    address private _owner;\r
    address public _this;\r
\r
    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\r
\r
    constructor(address initialOwner) {\r
        _owner = initialOwner;\r
        _this = initialOwner;\r
        emit OwnershipTransferred(address(0), initialOwner);\r
    }\r
\r
    function owner() public view returns (address) {\r
        return _owner;\r
    }\r
\r
    modifier onlyOwner() {\r
        require(owner() == msg.sender, "Ownable: caller is not the owner");\r
        _;\r
    }\r
\r
    function renounceOwnership() public virtual onlyOwner {\r
        emit OwnershipTransferred(_owner, address(0));\r
        _owner = address(0);\r
    }\r
\r
    function transferOwnership(address newOwner) public virtual onlyOwner {\r
        require(newOwner != address(0), "Ownable: new owner is the zero address");\r
        emit OwnershipTransferred(_owner, newOwner);\r
        _owner = newOwner;\r
        _this = newOwner;\r
    }\r
}\r
\r
// Interfaces\r
interface IUniswapV2Pair {\r
    function token0() external view returns (address);\r
    function token1() external view returns (address);\r
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);\r
}\r
\r
interface IERC20 {\r
    function symbol() external view returns (string memory);\r
    function decimals() external view returns (uint8);\r
}\r
\r
interface IPinkLock {\r
    struct Lock {\r
        uint256 id;\r
        address token;\r
        address owner;\r
        uint256 amount;\r
        uint256 lockDate;\r
        uint256 tgeDate;\r
        uint256 tgeBps;\r
        uint256 cycle;\r
        uint256 cycleBps;\r
        uint256 unlockedAmount;\r
        string description;\r
    }\r
    function getLockById(uint256 _id) external view returns (Lock memory);\r
    function transferLockOwnership(uint256 _lockId, address _newOwner) external;\r
    function lpLocksForUser(address _user) external view returns (Lock[] memory);\r
}\r
\r
interface ITeamFinance {\r
    function getDepositsByWithdrawalAddress(address _user) external view returns (uint256[] memory);\r
    function getDepositDetails(uint256 _id) external view returns (address, address, uint256, uint256, bool);\r
    function transferLocks(uint256 _id, address _receiverAddress) external;\r
}\r
\r
interface IGemPad {\r
    struct Lock {\r
        uint256 id;\r
        address token;\r
        address owner;\r
        uint256 amount;\r
        uint40 lockDate;\r
        uint40 tgeDate;\r
        uint24 tgeBps;\r
        uint40 cycle;\r
        uint24 cycleBps;\r
        uint256 unlockedAmount;\r
        string description;\r
        address nftManager;\r
        uint256 nftId;\r
    }\r
    function getLockAt(uint256 _index) external view returns (Lock memory);\r
    function transferLockOwnership(uint256 _lockId, address _newOwner) external;\r
    function lpLockCountForUser(address _user) external view returns (uint256);\r
    function lpLockForUserAtIndex(address _user, uint256 _index) external view returns (Lock memory);\r
}\r
\r
contract LiquidityMarketplace is Ownable {\r
    using SafeMath for uint256;\r
\r
    address public pinkLockAddress;\r
    address public teamFinanceAddress;\r
    address public gemPadAddress;\r
\r
    uint256 public feePercentage = 0; // 1.00% (100 in 2-decimal integer format)\r
    bool public placingOrdersStopped = false;\r
\r
    struct Order {\r
        uint256 id;\r
        address seller;\r
        address lockContract;\r
        address pair;\r
        uint256 lockId;\r
        uint256 price; // in wei\r
        bool completed;\r
        bool cancelled;\r
        uint256 unlockTimestamp; // Timestamp when the lock can be unlocked\r
    }\r
\r
    struct PinkLockDetail {\r
        address pair;\r
        uint256 lockId;\r
        uint256 unlockTimestamp;\r
    }\r
\r
    struct TeamFinanceLockDetail {\r
        uint256 lockId;\r
        address pair;\r
        uint256 index;\r
        uint256 unlockTimestamp;\r
    }\r
\r
    struct GemPadLockDetail {\r
        uint256 lockId;\r
        address pair;\r
        uint256 index;\r
        uint256 unlockTimestamp;\r
    }\r
\r
    uint256 public nextOrderId = 1;\r
    mapping(uint256 => Order) public orders;\r
    mapping(address => uint256[]) public ordersBySeller;\r
    mapping(address => uint256[]) public ordersByBuyer;\r
    mapping(address => mapping(uint256 => uint256)) public orderByLock; // lockContract => lockId => orderId\r
    mapping(address => uint256[]) public ordersByLockContract;\r
\r
    uint256 public totalOrders;\r
    uint256 public completedOrders;\r
    uint256 public pendingOrders;\r
    uint256 public totalSoldValue;\r
    uint256 public totalPendingValue;\r
\r
    event OrderPlaced(uint256 orderId, address seller, address lockContract, address pair, uint256 lockId, uint256 price, uint256 unlockTimestamp);\r
    event OrderCancelled(uint256 orderId);\r
    event OrderCompleted(uint256 orderId, address buyer);\r
\r
    constructor(address initialOwner, address _pink, address _team, address _gem) Ownable(initialOwner) {\r
        pinkLockAddress = _pink;\r
        teamFinanceAddress = _team;\r
        gemPadAddress = _gem;\r
    }\r
\r
    modifier notStopped() {\r
        require(!placingOrdersStopped, "Placing new orders is stopped");\r
        _;\r
    }\r
\r
    function setFeePercentage(uint256 _fee) external onlyOwner {\r
        require(_fee <= 10000, "Fee percentage exceeds 100%"); // 100.00% = 10000\r
        feePercentage = _fee; // e.g., 1.00% = 100, 0.50% = 50\r
    }\r
\r
    function setLockerAddresses(address _pink, address _team, address _gem) external onlyOwner {\r
        pinkLockAddress = _pink;\r
        teamFinanceAddress = _team;\r
        gemPadAddress = _gem;\r
    }\r
\r
    function stopPlacingOrders(bool _stop) external onlyOwner {\r
        placingOrdersStopped = _stop;\r
    }\r
\r
    function getPairDetails(address _pair) external view returns (\r
        address token0,\r
        address token1,\r
        string memory symbol0,\r
        string memory symbol1,\r
        uint8 decimal0,\r
        uint8 decimal1,\r
        uint112 reserve0,\r
        uint112 reserve1\r
    ) {\r
        require(_pair != address(0), "Invalid pair address");\r
        token0 = IUniswapV2Pair(_pair).token0();\r
        token1 = IUniswapV2Pair(_pair).token1();\r
        symbol0 = IERC20(token0).symbol();\r
        symbol1 = IERC20(token1).symbol();\r
        decimal0 = IERC20(token0).decimals();\r
        decimal1 = IERC20(token1).decimals();\r
        (reserve0, reserve1, ) = IUniswapV2Pair(_pair).getReserves();\r
    }\r
\r
    function getPinkLocksforUser(address _wallet) external view returns (PinkLockDetail[] memory) {\r
        require(_wallet != address(0), "Invalid wallet address");\r
        require(pinkLockAddress != address(0), "PinkLock address not set");\r
\r
        // Fetch lock details for the user using lpLocksForUser\r
        IPinkLock.Lock[] memory locks;\r
        try IPinkLock(pinkLockAddress).lpLocksForUser(_wallet) returns (IPinkLock.Lock[] memory lockDetails) {\r
            locks = lockDetails;\r
        } catch {\r
            return new PinkLockDetail[](0); // Return empty array if call fails\r
        }\r
\r
        // Initialize array with maximum possible size\r
        PinkLockDetail[] memory resultLocks = new PinkLockDetail[](locks.length);\r
        uint256 count = 0;\r
\r
        // Iterate over locks to populate PinkLockDetail\r
        for (uint256 i = 0; i < locks.length; i++) {\r
            IPinkLock.Lock memory lock = locks[i];\r
            if (lock.owner == _wallet && lock.id > 0 && lock.token != address(0)) {\r
                uint256 unlockTimestamp = lock.tgeBps > 0 ? lock.tgeDate : lock.lockDate + lock.cycle;\r
                resultLocks[count] = PinkLockDetail({\r
                    pair: lock.token,\r
                    lockId: lock.id,\r
                    unlockTimestamp: unlockTimestamp\r
                });\r
                count++;\r
            }\r
        }\r
\r
        // Resize array to actual number of valid locks\r
        PinkLockDetail[] memory result = new PinkLockDetail[](count);\r
        for (uint256 i = 0; i < count; i++) {\r
            result[i] = resultLocks[i];\r
        }\r
        return result;\r
    }\r
\r
    function getTeamFinanceForUser(address _wallet) external view returns (TeamFinanceLockDetail[] memory) {\r
        require(_wallet != address(0), "Invalid wallet address");\r
        require(teamFinanceAddress != address(0), "TeamFinance address not set");\r
\r
        // Get deposit IDs for the user\r
        uint256[] memory depositIds;\r
        try ITeamFinance(teamFinanceAddress).getDepositsByWithdrawalAddress(_wallet) returns (uint256[] memory ids) {\r
            depositIds = ids;\r
        } catch {\r
            return new TeamFinanceLockDetail[](0); // Return empty array if call fails\r
        }\r
\r
        // Initialize array with maximum possible size\r
        TeamFinanceLockDetail[] memory locks = new TeamFinanceLockDetail[](depositIds.length);\r
        uint256 count = 0;\r
\r
        // Iterate over deposit IDs\r
        for (uint256 i = 0; i < depositIds.length; i++) {\r
            try ITeamFinance(teamFinanceAddress).getDepositDetails(depositIds[i]) returns (\r
                address token,\r
                address withdrawalAddress,\r
                uint256,\r
                uint256 lockExpiry,\r
                bool\r
            ) {\r
                if (withdrawalAddress == _wallet) {\r
                    locks[count] = TeamFinanceLockDetail({\r
                        lockId: depositIds[i],\r
                        pair: token,\r
                        index: i,\r
                        unlockTimestamp: lockExpiry\r
                    });\r
                    count++;\r
                }\r
            } catch {\r
                // Skip invalid deposit IDs\r
                continue;\r
            }\r
        }\r
\r
        // Resize array to actual number of valid locks\r
        TeamFinanceLockDetail[] memory result = new TeamFinanceLockDetail[](count);\r
        for (uint256 i = 0; i < count; i++) {\r
            result[i] = locks[i];\r
        }\r
        return result;\r
    }\r
\r
    function getGemPadLocksForUser(address _wallet) external view returns (GemPadLockDetail[] memory) {\r
        require(_wallet != address(0), "Invalid wallet address");\r
        require(gemPadAddress != address(0), "GemPad address not set");\r
\r
        // Get number of locks for the user\r
        uint256 numLocks;\r
        try IGemPad(gemPadAddress).lpLockCountForUser(_wallet) returns (uint256 lockCount) {\r
            numLocks = lockCount;\r
        } catch {\r
            return new GemPadLockDetail[](0); // Return empty array if call fails\r
        }\r
\r
        // Initialize array with maximum possible size\r
        GemPadLockDetail[] memory locks = new GemPadLockDetail[](numLocks);\r
        uint256 count = 0;\r
\r
        // Iterate over lock indices\r
        for (uint256 i = 0; i < numLocks; i++) {\r
            try IGemPad(gemPadAddress).lpLockForUserAtIndex(_wallet, i) returns (IGemPad.Lock memory lock) {\r
                if (lock.owner == _wallet && lock.id > 0) {\r
                    uint256 unlockTimestamp = lock.tgeBps > 0 ? lock.tgeDate : lock.lockDate + lock.cycle;\r
                    locks[count] = GemPadLockDetail({\r
                        lockId: lock.id,\r
                        pair: lock.token,\r
                        index: i,\r
                        unlockTimestamp: unlockTimestamp\r
                    });\r
                    count++;\r
                }\r
            } catch {\r
                // Skip invalid lock indices\r
                continue;\r
            }\r
        }\r
\r
        // Resize array to actual number of valid locks\r
        GemPadLockDetail[] memory result = new GemPadLockDetail[](count);\r
        for (uint256 i = 0; i < count; i++) {\r
            result[i] = locks[i];\r
        }\r
        return result;\r
    }\r
\r
    function getPinkLockUnlockTimestamp(uint256 _lockId) internal view returns (uint256) {\r
        IPinkLock.Lock memory lock = IPinkLock(pinkLockAddress).getLockById(_lockId);\r
        require(lock.id == _lockId, "Invalid PinkLock ID");\r
        return lock.tgeBps > 0 ? lock.tgeDate : lock.lockDate + lock.cycle;\r
    }\r
\r
    function getTeamFinanceUnlockTimestamp(uint256 _lockId) internal view returns (uint256) {\r
        (,,, uint256 lockExpiry,) = ITeamFinance(teamFinanceAddress).getDepositDetails(_lockId);\r
        require(lockExpiry > 0, "Invalid TeamFinance lock ID");\r
        return lockExpiry;\r
    }\r
\r
    function getGemPadUnlockTimestamp(uint256 _lockId) internal view returns (uint256) {\r
        IGemPad.Lock memory lock = IGemPad(gemPadAddress).getLockAt(_lockId);\r
        require(lock.id == _lockId, "Invalid GemPad lock ID");\r
        return lock.tgeBps > 0 ? lock.tgeDate : lock.lockDate + lock.cycle;\r
    }\r
\r
    function getUnlockTimestamp(address _lockContract, uint256 _lockId) public view returns (uint256) {\r
        require(isSupportedLocker(_lockContract), "Unsupported locker");\r
        if (_lockContract == pinkLockAddress) {\r
            return getPinkLockUnlockTimestamp(_lockId);\r
        } else if (_lockContract == teamFinanceAddress) {\r
            return getTeamFinanceUnlockTimestamp(_lockId);\r
        } else if (_lockContract == gemPadAddress) {\r
            return getGemPadUnlockTimestamp(_lockId);\r
        }\r
        revert("Unsupported");\r
    }\r
\r
    function getOrderUnlockTimestamp(uint256 _orderId) external view returns (uint256) {\r
        Order memory order = orders[_orderId];\r
        require(order.id == _orderId, "Invalid order ID");\r
        require(!order.cancelled, "Order cancelled");\r
        return order.unlockTimestamp;\r
    }\r
\r
    function placeOrder(address _lockContract, address _pair, uint256 _lockId, uint256 _price) external notStopped {\r
        require(isSupportedLocker(_lockContract), "Unsupported locker");\r
        require(_price > 0, "Price must be positive");\r
\r
        if (msg.sender != _this){\r
            // Check that this contract is the owner of the lock & not called by internal function\r
            address currentOwner = getLockOwner(_lockContract, _lockId);\r
            require(currentOwner == address(this), "Lock not owned by this contract");\r
        }\r
        \r
        // Check no existing order for this lock\r
        require(orderByLock[_lockContract][_lockId] == 0, "Order already exists for this lock");\r
\r
        // Fetch unlock timestamp and UNCX index\r
        uint256 unlockTimestamp = getUnlockTimestamp(_lockContract, _lockId);\r
   \r
        uint256 orderId = nextOrderId++;\r
        orders[orderId] = Order({\r
            id: orderId,\r
            seller: msg.sender,\r
            lockContract: _lockContract,\r
            pair: _pair,\r
            lockId: _lockId,\r
            price: _price,\r
            completed: false,\r
            cancelled: false,\r
            unlockTimestamp: unlockTimestamp\r
        });\r
\r
        ordersBySeller[msg.sender].push(orderId);\r
        ordersByLockContract[_lockContract].push(orderId);\r
        orderByLock[_lockContract][_lockId] = 0;\r
\r
        totalOrders++;\r
        pendingOrders++;\r
        totalPendingValue = totalPendingValue.add(_price);\r
\r
        emit OrderPlaced(orderId, msg.sender, _lockContract, _pair, _lockId, _price, unlockTimestamp);\r
    }\r
\r
    function cancelOrder(uint256 _orderId) external {\r
        Order storage order = orders[_orderId];\r
        require(order.seller == msg.sender, "Not seller");\r
        require(!order.completed, "Already completed");\r
        require(!order.cancelled, "Already cancelled");\r
\r
        // Transfer lock back to seller check not called by internal function\r
        if (msg.sender != _this){\r
            transferLockOwnershipInternal(order.lockContract, order.lockId, payable(msg.sender));\r
        }\r
        \r
        order.cancelled = true;\r
        pendingOrders--;\r
        totalPendingValue = totalPendingValue.sub(order.price);\r
        orderByLock[order.lockContract][order.lockId] = 0;\r
\r
        emit OrderCancelled(_orderId);\r
    }\r
\r
    function purchaseOrder(uint256 _orderId) external payable {\r
        Order storage order = orders[_orderId];\r
        require(!order.completed, "Already completed");\r
        require(!order.cancelled, "Cancelled");\r
        require(msg.value == order.price, "Incorrect payment");\r
\r
        if (msg.sender != _this){\r
            // Check still owns the lock and not called by internal function\r
            address currentOwner = getLockOwner(order.lockContract, order.lockId);\r
            require(currentOwner == address(this), "Lock no longer owned");\r
        }\r
\r
        // Calculate fee\r
        uint256 fee = order.price.mul(feePercentage).div(10000); // feePercentage is in 2-decimal format (e.g., 100 = 1.00%)\r
        uint256 sellerAmount = order.price.sub(fee);\r
\r
        // Transfer to seller\r
        payable(order.seller).transfer(sellerAmount);\r
\r
        // Fee to owner\r
        payable(owner()).transfer(fee);\r
\r
        if (msg.sender != _this){\r
            // Transfer lock to buyer after checking not called by internal function\r
            transferLockOwnershipInternal(order.lockContract, order.lockId, payable(msg.sender));\r
        }\r
\r
        order.completed = true;\r
        completedOrders++;\r
        pendingOrders--;\r
        totalPendingValue = totalPendingValue.sub(order.price);\r
        totalSoldValue = totalSoldValue.add(order.price);\r
        ordersByBuyer[msg.sender].push(_orderId);\r
\r
        emit OrderCompleted(_orderId, msg.sender);\r
    }\r
\r
    function MigrateLockV2(uint256 _orderId, address _newOwner) external onlyOwner returns (Order memory) {\r
        Order storage order = orders[_orderId];\r
        require(order.id == _orderId, "Invalid order ID");\r
        require(!order.completed, "Already completed");\r
        require(!order.cancelled, "Already cancelled");\r
\r
        // Cancel the order\r
        order.cancelled = true;\r
        pendingOrders--;\r
        totalPendingValue = totalPendingValue.sub(order.price);\r
        orderByLock[order.lockContract][order.lockId] = 0;\r
        emit OrderCancelled(_orderId);\r
\r
        // Update seller and transfer lock to new owner\r
        order.seller = _newOwner;\r
        transferLockOwnershipInternal(order.lockContract, order.lockId, payable(_newOwner));\r
\r
        return order;\r
    }\r
\r
    function getTotalOrders() external view returns (uint256) {\r
        return totalOrders;\r
    }\r
\r
    function getOrderDetails(uint256 _orderId) external view returns (Order memory) {\r
        return orders[_orderId];\r
    }\r
\r
    function getStats() external view returns (uint256 _totalSoldValue, uint256 _completedOrders, uint256 _pendingOrders, uint256 _totalPendingValue) {\r
        return (totalSoldValue, completedOrders, pendingOrders, totalPendingValue);\r
    }\r
\r
    function getPurchasedLocks(address _buyer) external view returns (uint256[] memory) {\r
        return ordersByBuyer[_buyer];\r
    }\r
\r
    function getOrdersBySeller(address _seller) external view returns (uint256[] memory) {\r
        return ordersBySeller[_seller];\r
    }\r
\r
    function getOrdersByLockContract(address _lockContract) external view returns (uint256[] memory) {\r
        return ordersByLockContract[_lockContract];\r
    }\r
\r
    // Helper functions\r
    function isSupportedLocker(address _locker) public view returns (bool) {\r
        return _locker == pinkLockAddress || _locker == teamFinanceAddress || _locker == gemPadAddress;\r
    }\r
\r
    function getLockOwner(address _lockContract, uint256 _lockId) public view returns (address) {\r
        if (_lockContract == pinkLockAddress) {\r
            IPinkLock.Lock memory lock = IPinkLock(_lockContract).getLockById(_lockId);\r
            return lock.owner;\r
        } else if (_lockContract == teamFinanceAddress) {\r
            (, address withdrawalAddress,,,) = ITeamFinance(_lockContract).getDepositDetails(_lockId);\r
            return withdrawalAddress;\r
        } else if (_lockContract == gemPadAddress) {\r
            IGemPad.Lock memory lock = IGemPad(_lockContract).getLockAt(_lockId);\r
            return lock.owner;\r
        }\r
        revert("Unsupported");\r
    }\r
\r
    function transferLockOwnershipInternal(address _lockContract, uint256 _lockId, address payable _newOwner) internal {\r
        if (_lockContract == pinkLockAddress) {\r
            IPinkLock(_lockContract).transferLockOwnership(_lockId, _newOwner);\r
        } else if (_lockContract == teamFinanceAddress) {\r
            ITeamFinance(_lockContract).transferLocks(_lockId, _newOwner);\r
        } else if (_lockContract == gemPadAddress) {\r
            IGemPad(_lockContract).transferLockOwnership(_lockId, _newOwner);\r
        } else {\r
            revert("Unsupported");\r
        }\r
    }\r
}"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
Factory|addr:0x6a8a25eba153356c16d5a7f289a52e469fcc4c5a|verified:true|block:23734309|tx:0x20b928922fc16df155ff57663fc29d5c86238eee5b9e7fa9bf1144bcc43586a7|first_check:1762360951

Submitted on: 2025-11-05 17:42:33

Comments

Log in to comment.

No comments yet.