// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "./NTAKE.sol"; import "@openzeppelin/contracts/math/SafeMath.sol"; //StakingContract is named NTAKE contract NLiquidity is Ownable, ReentrancyGuard { using SafeMath for uint256; IERC20 public navisToken; IERC20 public otherToken; // Replace with the actual ERC20 token interface for the other token NTAKE public stakingContract; // Replace with the actual EnhancedStakingContract interface uint256 public totalNavisSupply; uint256 public totalOtherTokenSupply; mapping(address => uint256) public navisBalances; mapping(address => uint256) public otherTokenBalances; uint256 public constant FEE_PERCENTAGE = 1; // 1% transaction fee uint256 public constant STAKED_NAVIS_MULTIPLIER = 2; // Multiplier for staked NAVIS providers event LiquidityProvided(address indexed provider, uint256 navisAmount, uint256 otherTokenAmount); event LiquidityRemoved(address indexed provider, uint256 navisAmount, uint256 otherTokenAmount); constructor( address _navisToken, address _otherToken, address _stakingContract ) { navisToken = IERC20(_navisToken); otherToken = IERC20(_otherToken); stakingContract = NTAKE(_stakingContract); } // Function to provide liquidity to the pool using staked NAVIS function provideLiquidityWithStake(uint256 otherTokenAmount) external { require(otherTokenAmount > 0, "Other token amount must be greater than zero"); // Use staked NAVIS for liquidity uint256 stakedNavisAmount = stakingContract.getStakedBalance(msg.sender); require(stakedNavisAmount > 0, "No staked NAVIS available"); // Calculate NAVIS amount to use based on staking multiplier uint256 stakedNavisToUse = stakedNavisAmount.mul(STAKED_NAVIS_MULTIPLIER); require(navisToken.balanceOf(msg.sender) >= stakedNavisToUse, "Insufficient staked NAVIS balance"); // Transfer staked NAVIS from the user to the contract stakingContract.withdraw(stakedNavisToUse); require(navisToken.transferFrom(msg.sender, address(this), stakedNavisToUse), "Navis transfer failed"); // Transfer other token from the user to the contract require(otherToken.transferFrom(msg.sender, address(this), otherTokenAmount), "Other token transfer failed"); // Update liquidity pool balances navisBalances[msg.sender] = navisBalances[msg.sender].add(stakedNavisToUse); otherTokenBalances[msg.sender] = otherTokenBalances[msg.sender].add(otherTokenAmount); totalNavisSupply = totalNavisSupply.add(stakedNavisToUse); totalOtherTokenSupply = totalOtherTokenSupply.add(otherTokenAmount); emit LiquidityProvided(msg.sender, stakedNavisToUse, otherTokenAmount); } // Function to remove liquidity from the pool function removeLiquidity(uint256 navisAmount, uint256 otherTokenAmount) external { require(navisAmount > 0, "Navis amount must be greater than zero"); require(otherTokenAmount > 0, "Other token amount must be greater than zero"); require(navisAmount <= navisBalances[msg.sender], "Insufficient NAVIS balance"); require(otherTokenAmount <= otherTokenBalances[msg.sender], "Insufficient other token balance"); // Calculate proportional share of total supply uint256 navisShare = navisAmount.mul(totalNavisSupply).div(totalNavisSupply); uint256 otherTokenShare = otherTokenAmount.mul(totalOtherTokenSupply).div(totalOtherTokenSupply); // Update liquidity pool balances navisBalances[msg.sender] = navisBalances[msg.sender].sub(navisAmount); otherTokenBalances[msg.sender] = otherTokenBalances[msg.sender].sub(otherTokenAmount); totalNavisSupply = totalNavisSupply.sub(navisShare); totalOtherTokenSupply = totalOtherTokenSupply.sub(otherTokenShare); // Transfer NAVIS and other token back to the user require(navisToken.transfer(msg.sender, navisAmount), "Navis transfer failed"); require(otherToken.transfer(msg.sender, otherTokenAmount), "Other token transfer failed"); emit LiquidityRemoved(msg.sender, navisAmount, otherTokenAmount); } // Implement automated market-making algorithms here // Add incentive mechanisms for liquidity providers, including fee distribution function trade(uint256 navisSold, uint256 minOtherTokenBought) external { uint256 navisReserve = navisToken.balanceOf(address(this)); uint256 otherTokenReserve = otherToken.balanceOf(address(this)); require(navisSold > 0 && navisSold <= navisReserve, "Invalid NAVIS amount"); uint256 otherTokenBought = calculateTradeAmount(navisSold, navisReserve, otherTokenReserve); require(otherTokenBought >= minOtherTokenBought, "Slippage limit exceeded"); // Transfer NAVIS from the trader to the contract require(navisToken.transferFrom(msg.sender, address(this), navisSold), "Navis transfer failed"); // Transfer other token to the trader require(otherToken.transfer(msg.sender, otherTokenBought), "Other token transfer failed"); // Distribute transaction fee to liquidity providers uint256 fee = otherTokenBought.mul(FEE_PERCENTAGE).div(100); // Calculate 1% fee uint256 stakedNavisProvidersReward = fee.mul(STAKED_NAVIS_MULTIPLIER); uint256 nonStakedNavisProvidersReward = fee.sub(stakedNavisProvidersReward); // Distribute fees to liquidity providers distributeFees(stakedNavisProvidersReward, nonStakedNavisProvidersReward); // Emit trade event emit LiquidityProvided(msg.sender, navisSold, otherTokenBought); } // Automated market-making algorithm (AMM) - Placeholder, replace with actual algorithm function calculateTradeAmount(uint256 navisSold, uint256 navisReserve, uint256 otherTokenReserve) internal pure returns (uint256) { // Replace with an actual AMM algorithm return navisSold.mul(otherTokenReserve).div(navisReserve); } // Fee distribution to liquidity providers function distributeFees(uint256 stakedNavisProvidersReward, uint256 nonStakedNavisProvidersReward) internal { // Distribute fees to staked NAVIS providers stakingContract.distributeRewards(stakedNavisProvidersReward); // Distribute fees to non-staked NAVIS providers for (uint256 i = 0; i < stakingContract.getTotalStakers(); i++) { address nonStakedProvider = stakingContract.getStakerAt(i); if (nonStakedProvider != address(0) && nonStakedProvider != msg.sender) { uint256 nonStakedProviderReward = nonStakedNavisProvidersReward.mul(stakingContract.getStakedBalance(nonStakedProvider)).div(totalNavisSupply); require(navisToken.transfer(nonStakedProvider, nonStakedProviderReward), "Navis transfer failed"); } } } }