Files
smom-dbis-138/contracts/liquidity/providers/FixedRateLiquidityProvider.sol

123 lines
4.7 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/ILiquidityProvider.sol";
/**
* @title FixedRateLiquidityProvider
* @notice Narrow Chain 138 prep provider for token pairs that need executable
* router-backed conversion while a DODO pool direction is unhealthy.
*/
contract FixedRateLiquidityProvider is ILiquidityProvider, AccessControl {
using SafeERC20 for IERC20;
bytes32 public constant RATE_MANAGER_ROLE = keccak256("RATE_MANAGER_ROLE");
address public immutable tokenIn;
address public immutable tokenOut;
uint256 public amountOutPerTokenIn;
uint256 public slippageBps;
uint256 public gasEstimate;
bool public enabled = true;
event RateUpdated(uint256 amountOutPerTokenIn, uint256 slippageBps);
event EnabledSet(bool enabled);
event SwapExecuted(address indexed caller, uint256 amountIn, uint256 amountOut);
event Swept(address indexed token, address indexed recipient, uint256 amount);
constructor(
address admin,
address tokenIn_,
address tokenOut_,
uint256 amountOutPerTokenIn_,
uint256 slippageBps_,
uint256 gasEstimate_
) {
require(admin != address(0), "FixedRateLiquidityProvider: zero admin");
require(tokenIn_ != address(0), "FixedRateLiquidityProvider: zero tokenIn");
require(tokenOut_ != address(0), "FixedRateLiquidityProvider: zero tokenOut");
require(tokenIn_ != tokenOut_, "FixedRateLiquidityProvider: same token");
require(amountOutPerTokenIn_ > 0, "FixedRateLiquidityProvider: zero rate");
tokenIn = tokenIn_;
tokenOut = tokenOut_;
amountOutPerTokenIn = amountOutPerTokenIn_;
slippageBps = slippageBps_;
gasEstimate = gasEstimate_;
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(RATE_MANAGER_ROLE, admin);
}
function setRate(uint256 amountOutPerTokenIn_, uint256 slippageBps_) external onlyRole(RATE_MANAGER_ROLE) {
require(amountOutPerTokenIn_ > 0, "FixedRateLiquidityProvider: zero rate");
amountOutPerTokenIn = amountOutPerTokenIn_;
slippageBps = slippageBps_;
emit RateUpdated(amountOutPerTokenIn_, slippageBps_);
}
function setEnabled(bool enabled_) external onlyRole(RATE_MANAGER_ROLE) {
enabled = enabled_;
emit EnabledSet(enabled_);
}
function setGasEstimate(uint256 gasEstimate_) external onlyRole(RATE_MANAGER_ROLE) {
gasEstimate = gasEstimate_;
}
function getQuote(
address tokenIn_,
address tokenOut_,
uint256 amountIn
) external view override returns (uint256 amountOut, uint256 quoteSlippageBps) {
if (!enabled || tokenIn_ != tokenIn || tokenOut_ != tokenOut || amountIn == 0) {
return (0, 10_000);
}
amountOut = (amountIn * amountOutPerTokenIn) / 1e18;
quoteSlippageBps = slippageBps;
}
function executeSwap(
address tokenIn_,
address tokenOut_,
uint256 amountIn,
uint256 minAmountOut
) external override returns (uint256 amountOut) {
require(enabled, "FixedRateLiquidityProvider: disabled");
require(tokenIn_ == tokenIn && tokenOut_ == tokenOut, "FixedRateLiquidityProvider: unsupported pair");
require(amountIn > 0, "FixedRateLiquidityProvider: zero amount");
amountOut = (amountIn * amountOutPerTokenIn) / 1e18;
require(amountOut >= minAmountOut, "FixedRateLiquidityProvider: insufficient output");
require(IERC20(tokenOut).balanceOf(address(this)) >= amountOut, "FixedRateLiquidityProvider: insufficient liquidity");
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
IERC20(tokenOut).safeTransfer(msg.sender, amountOut);
emit SwapExecuted(msg.sender, amountIn, amountOut);
}
function supportsTokenPair(address tokenIn_, address tokenOut_) external view override returns (bool) {
return enabled && tokenIn_ == tokenIn && tokenOut_ == tokenOut;
}
function providerName() external pure override returns (string memory) {
return "Fixed Rate Liquidity Provider";
}
function estimateGas(address, address, uint256) external view override returns (uint256) {
return gasEstimate;
}
function sweep(address token, address recipient, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(recipient != address(0), "FixedRateLiquidityProvider: zero recipient");
IERC20(token).safeTransfer(recipient, amount);
emit Swept(token, recipient, amount);
}
}