// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/access/Ownable.sol"; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import "@TheNavisAPP/contracts/token/NAVISToken.sol"; import "@TheNavisAPP/contracts/token/NFUEL.sol"; contract NDEX is Ownable { NAVISToken public navisToken; AggregatorV3Interface internal priceFeed; // Chainlink BTC/USD price feed NFUEL public gasToken; // Gas token contract uint256 public constant MINIMUM_NAVIS_AMOUNT = 1; // Minimum NAVIS amount for swapping uint256 public makerFeePercentage = 75; // 0.075% Maker fee uint256 public takerFeePercentage = 25; // 0.025% Taker fee uint256 public fiatSpreadPercentage = 50; // 0.50% Spread for fiat uint256 public cryptoSpreadPercentage = 100; // 1.00% Spread for crypto uint256 public rewardPercentage = 100; // 1:1 reward for users who swap tokens mapping(address => uint256) public userRewards; // Accumulated rewards for each user struct Swap { address user; uint256 navisAmount; uint256 btcAmount; uint256 fee; uint256 spread; uint256 reward; uint256 gasRefund; // Gas refund in NFUEL uint256 timestamp; } Swap[] public swapHistory; uint256 public totalSwappedBTC; event TokensSwapped( address indexed user, uint256 navisAmount, uint256 btcAmount, uint256 fee, uint256 spread, uint256 reward, uint256 gasRefund ); event TradingFeeChanged(uint256 newMakerFeePercentage, uint256 newTakerFeePercentage, uint256 newFiatSpread, uint256 newCryptoSpread); event RewardPercentageChanged(uint256 newRewardPercentage); event RewardWithdrawn(address indexed user, uint256 amount); constructor(address _navisToken, address _priceFeed, address _gasToken) { navisToken = NAVISToken(_navisToken); priceFeed = AggregatorV3Interface(_priceFeed); gasToken = NFUEL(_gasToken); } function swapTokens(uint256 navisAmount) external { require(navisAmount >= MINIMUM_NAVIS_AMOUNT, "NAVIS amount must be greater than or equal to the minimum amount"); require(navisAmount > 0, "NAVIS amount must be greater than zero"); // Calculate BTC amount based on the Chainlink BTC/USD price feed uint256 btcAmount = navisToken.convertNAVIStoBTC(navisAmount); // Calculate fees and spreads uint256 fee = calculateFee(btcAmount); uint256 spread = calculateSpread(btcAmount); uint256 reward = (navisAmount * rewardPercentage) / 100; // Calculate reward for the user // Calculate the gas refund in NFUEL uint256 gasRefund = calculateGasRefund(btcAmount); // Calculate the total amount to be deducted from the user's NAVIS tokens uint256 totalDeduction = navisAmount + fee + spread; // Transfer NAVIS tokens from the user require(navisToken.safeTransferFrom(msg.sender, address(this), totalDeduction), "NAVIS token transfer failed"); // Transfer BTC to the user // In a real-world scenario, you would interact with a decentralized exchange for the actual swap. // Here, we simulate the transfer of BTC to the user. // Ensure the contract has sufficient BTC balance for this operation. (bool success, ) = msg.sender.call{value: btcAmount - fee}(""); require(success, "BTC transfer failed"); // Save swap details to the history swapHistory.push(Swap({ user: msg.sender, navisAmount: navisAmount, btcAmount: btcAmount - fee, fee: fee, spread: spread, reward: reward, gasRefund: gasRefund, timestamp: block.timestamp })); // Update total swapped BTC amount totalSwappedBTC += btcAmount - fee; // Update user's accumulated rewards userRewards[msg.sender] += reward; // Transfer gas refund in NFUEL to the user if (gasRefund > 0) { require(gasToken.transfer(msg.sender, gasRefund), "Gas refund transfer failed"); } // Emit event emit TokensSwapped(msg.sender, navisAmount, btcAmount - fee, fee, spread, reward, gasRefund); } // Function to calculate trading fee based on Maker or Taker function calculateFee(uint256 btcAmount) internal view returns (uint256) { if (gasToken.isGasToken(msg.sender)) { // If user is using the gas token, set fee to zero return 0; } if (btcAmount > 0) { return (btcAmount * (msg.sender == tx.origin ? takerFeePercentage : makerFeePercentage)) / 10000; } return 0; } // Function to calculate spread based on fiat or crypto function calculateSpread(uint256 btcAmount) internal view returns (uint256) { return (btcAmount * (msg.sender == tx.origin ? cryptoSpreadPercentage : fiatSpreadPercentage)) / 10000; } // Function to calculate gas refund in NFUEL function calculateGasRefund(uint256 btcAmount) internal view returns (uint256) { // Implement the logic to calculate gas refund using NFUEL with the actual logic you plan to use for gas refund in NFUEL. // Example: Calculate gas refund based on a fixed rate and gas used in the transaction uint256 gasUsed = gasleft(); // Get the gas used in the transaction uint256 gasRefund = (gasUsed * 1 gwei) / 1e9; // Gas refund at a fixed rate (1 gwei per gas) return gasRefund; } // Function to withdraw gas tokens function withdrawGasTokens(uint256 amount) external onlyOwner { gasToken.withdraw(msg.sender, amount); } // Function to update trading fees and spreads function updateTradingFees(uint256 newMakerFeePercentage, uint256 newTakerFeePercentage, uint256 newFiatSpread, uint256 newCryptoSpread) external onlyOwner { require(newMakerFeePercentage <= 10000 && newTakerFeePercentage <= 10000, "Invalid fee percentage"); require(newFiatSpread <= 10000 && newCryptoSpread <= 10000, "Invalid spread percentage"); makerFeePercentage = newMakerFeePercentage; takerFeePercentage = newTakerFeePercentage; fiatSpreadPercentage = newFiatSpread; cryptoSpreadPercentage = newCryptoSpread; emit TradingFeeChanged(newMakerFeePercentage, newTakerFeePercentage, newFiatSpread, newCryptoSpread); } // Function to update reward percentage function updateRewardPercentage(uint256 newRewardPercentage) external onlyOwner { require(newRewardPercentage <= 100, "Invalid reward percentage"); rewardPercentage = newRewardPercentage; emit RewardPercentageChanged(newRewardPercentage); } // Function to withdraw accumulated rewards function withdrawRewards() external { uint256 userReward = userRewards[msg.sender]; require(userReward > 0, "No rewards to withdraw"); userRewards[msg.sender] = 0; // Reset user's accumulated rewards require(navisToken.transfer(msg.sender, userReward), "Reward withdrawal failed"); emit RewardWithdrawn(msg.sender, userReward); } }