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": []
}
}}
Submitted on: 2025-11-05 17:42:33
Comments
Log in to comment.
No comments yet.