// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract DBKExchangeVault is ReentrancyGuard {
address public immutable dbkToken; // DBK ERC-20 address
address public immutable usdcToken; // Example input: USDC
AggregatorV3Interface public immutable usdOracle; // Chainlink USD/USD feed (for peg check)
AggregatorV3Interface public immutable usdcUsdOracle; // USDC/USD oracle (should be ~1)
uint256 public constant PEG_PRICE = 1e18; // 1.00 USD in 18 decimals
uint256 public constant MAX_DRIFT = 1e16; // 0.01 USD tolerance (1e16 / 1e18 = 0.01)
uint256 public feeBasisPoints = 100; // 1% fee (100 / 10000)
event SwapExecuted(address indexed user, uint256 inputAmount, uint256 dbkReceived, uint256 fee);
event SwapFailed(address indexed user, uint256 inputAmount, string reason);
constructor(
address _dbkToken,
address _usdcToken,
address _usdOracle,
address _usdcUsdOracle
) {
dbkToken = _dbkToken;
usdcToken = _usdcToken;
usdOracle = AggregatorV3Interface(_usdOracle);
usdcUsdOracle = AggregatorV3Interface(_usdcUsdOracle);
}
// Swap USDC (or similar) for DBK at 1:1 USD peg
function swapForDBK(uint256 inputAmount) external nonReentrant {
require(inputAmount > 0, "Input must be positive");
// Transfer input tokens from user
IERC20(usdcToken).transferFrom(msg.sender, address(this), inputAmount);
// Get USD value of input (for volatile assets, use asset-specific oracle)
(, int256 usdcUsdPrice, , , ) = usdcUsdOracle.latestRoundData();
require(usdcUsdPrice > 0, "Invalid oracle price");
uint256 inputUsdValue = (inputAmount * uint256(usdcUsdPrice)) / 1e18; // Adjust decimals as needed
// Validate peg: Expected DBK = inputUsdValue; check against DBK USD price (should be 1)
(, int256 dbkUsdPrice, , , ) = usdOracle.latestRoundData(); // Assume DBK oracle feed at 1 USD
require(dbkUsdPrice > 0, "Invalid DBK oracle");
uint256 expectedDbkUsd = (inputUsdValue * uint256(dbkUsdPrice)) / 1e18;
uint256 pegCheck = uint256(dbkUsdPrice) * 1e18; // DBK should be 1e18 USD
require(pegCheck >= PEG_PRICE - MAX_DRIFT && pegCheck <= PEG_PRICE + MAX_DRIFT, "Peg deviation: Transaction invalid");
// Calculate fee on input USD value
uint256 feeUsd = (inputUsdValue * feeBasisPoints) / 10000;
uint256 dbkAmount = inputUsdValue - feeUsd; // Fee deducted from input; output at 1:1
// Transfer DBK to user (assume vault holds DBK liquidity)
require(IERC20(dbkToken).transfer(msg.sender, dbkAmount), "DBK transfer failed");
// Burn/hold fee or send to treasury (example: hold in contract)
// IERC20(usdcToken).transfer(treasury, feeUsd); // Uncomment for treasury
emit SwapExecuted(msg.sender, inputAmount, dbkAmount, feeUsd);
}
// Admin: Set fee (for exchange profit config)
function setFee(uint256 _feeBasisPoints) external {
// Add onlyOwner modifier in production
require(_feeBasisPoints <= 500, "Fee too high"); // Max 5%
feeBasisPoints = _feeBasisPoints;
}
// Fallback: Reject direct ETH/unsupported
receive() external payable {
revert("Unsupported: Use swapForDBK for pegged pairs only");
}
}