// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract DEX is ReentrancyGuard {
struct Pool {
uint256 reserveA;
uint256 reserveB;
}
mapping(address => mapping(address => Pool)) public pools;
event LiquidityAdded(address indexed tokenA, address indexed tokenB, uint256 amountA, uint256 amountB);
event TokensSwapped(address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountA,
uint256 amountB
) external nonReentrant {
require(amountA > 0 && amountB > 0, "Amounts must be greater than zero");
IERC20(tokenA).transferFrom(msg.sender, address(this), amountA);
IERC20(tokenB).transferFrom(msg.sender, address(this), amountB);
pools[tokenA][tokenB].reserveA += amountA;
pools[tokenA][tokenB].reserveB += amountB;
emit LiquidityAdded(tokenA, tokenB, amountA, amountB);
}
function swapTokens(
address tokenIn,
address tokenOut,
uint256 amountIn
) external nonReentrant {
require(amountIn > 0, "Amount must be greater than zero");
Pool storage pool = pools[tokenIn][tokenOut];
require(pool.reserveA > 0 && pool.reserveB > 0, "Liquidity not available");
// Simple swap calculation (could be improved with a more complex formula)
uint256 amountOut = (amountIn * pool.reserveB) / pool.reserveA;
IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
IERC20(tokenOut).transfer(msg.sender, amountOut);
// Update reserves
pool.reserveA += amountIn;
pool.reserveB -= amountOut;
emit TokensSwapped(tokenIn, tokenOut, amountIn, amountOut);
}
}