- Updated DBIS_ConversionRouter and DBIS_SettlementRouter to utilize IDBIS_EIP712Helper for EIP-712 hashing and signature recovery, improving stack depth management. - Refactored minting logic in DBIS_GRU_MintController to streamline recipient processing. - Enhanced BUILD_NOTES.md with updated build instructions and test coverage details. - Added new functions in DBIS_SignerRegistry for duplicate signer checks and active signer validation. - Introduced a new submodule, DBIS_EIP712Helper, to encapsulate EIP-712 related functionalities. Made-with: Cursor
204 lines
7.7 KiB
Solidity
204 lines
7.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";
|
|
import "../../dex/DODOPMMIntegration.sol";
|
|
|
|
/**
|
|
* @title DODOPMMProvider
|
|
* @notice Wrapper for DODO PMM with extended functionality
|
|
* @dev Implements ILiquidityProvider for multi-provider liquidity system
|
|
*/
|
|
contract DODOPMMProvider is ILiquidityProvider, AccessControl {
|
|
using SafeERC20 for IERC20;
|
|
|
|
bytes32 public constant POOL_MANAGER_ROLE = keccak256("POOL_MANAGER_ROLE");
|
|
|
|
DODOPMMIntegration public dodoIntegration;
|
|
|
|
// Pool tracking
|
|
mapping(address => mapping(address => address)) public pools; // tokenIn => tokenOut => pool
|
|
mapping(address => bool) public isKnownPool;
|
|
|
|
event PoolCreated(address indexed tokenIn, address indexed tokenOut, address pool);
|
|
event PoolOptimized(address indexed pool, uint256 newK, uint256 newI);
|
|
|
|
constructor(address _dodoIntegration, address admin) {
|
|
require(_dodoIntegration != address(0), "Zero address");
|
|
|
|
dodoIntegration = DODOPMMIntegration(_dodoIntegration);
|
|
|
|
_grantRole(DEFAULT_ADMIN_ROLE, admin);
|
|
_grantRole(POOL_MANAGER_ROLE, admin);
|
|
}
|
|
|
|
/**
|
|
* @notice Get quote from DODO PMM
|
|
*/
|
|
function getQuote(
|
|
address tokenIn,
|
|
address tokenOut,
|
|
uint256 amountIn
|
|
) external view override returns (uint256 amountOut, uint256 slippageBps) {
|
|
address pool = pools[tokenIn][tokenOut];
|
|
|
|
if (pool == address(0)) {
|
|
return (0, 10000); // No pool, 100% slippage
|
|
}
|
|
|
|
try dodoIntegration.getPoolPriceOrOracle(pool) returns (uint256 price) {
|
|
// Simple calculation (in production, would use actual DODO math)
|
|
amountOut = (amountIn * price) / 1e18;
|
|
slippageBps = 30; // 0.3% typical for stablecoin pools
|
|
return (amountOut, slippageBps);
|
|
} catch {
|
|
return (0, 10000);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @notice Execute swap via DODO PMM
|
|
*/
|
|
function executeSwap(
|
|
address tokenIn,
|
|
address tokenOut,
|
|
uint256 amountIn,
|
|
uint256 minAmountOut
|
|
) external override returns (uint256 amountOut) {
|
|
// Get pool for token pair
|
|
address pool = pools[tokenIn][tokenOut];
|
|
require(pool != address(0), "Pool not found");
|
|
|
|
// Transfer tokens from caller
|
|
IERC20(tokenIn).safeTransferFrom(msg.sender, address(this), amountIn);
|
|
|
|
// Route to appropriate swap method: use dedicated methods for the 6 legacy pairs,
|
|
// otherwise use generic swapExactIn for full-mesh routing (any registered pool).
|
|
if (tokenIn == dodoIntegration.compliantUSDT() && tokenOut == dodoIntegration.officialUSDT()) {
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapCUSDTForUSDT(pool, amountIn, minAmountOut);
|
|
} else if (tokenIn == dodoIntegration.officialUSDT() && tokenOut == dodoIntegration.compliantUSDT()) {
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapUSDTForCUSDT(pool, amountIn, minAmountOut);
|
|
} else if (tokenIn == dodoIntegration.compliantUSDC() && tokenOut == dodoIntegration.officialUSDC()) {
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapCUSDCForUSDC(pool, amountIn, minAmountOut);
|
|
} else if (tokenIn == dodoIntegration.officialUSDC() && tokenOut == dodoIntegration.compliantUSDC()) {
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapUSDCForCUSDC(pool, amountIn, minAmountOut);
|
|
} else if (tokenIn == dodoIntegration.compliantUSDT() && tokenOut == dodoIntegration.compliantUSDC()) {
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapCUSDTForUSDC(pool, amountIn, minAmountOut);
|
|
} else if (tokenIn == dodoIntegration.compliantUSDC() && tokenOut == dodoIntegration.compliantUSDT()) {
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapUSDCForCUSDT(pool, amountIn, minAmountOut);
|
|
} else {
|
|
// Full mesh: any registered pool (c* vs c*, c* vs official, etc.)
|
|
IERC20(tokenIn).approve(address(dodoIntegration), amountIn);
|
|
amountOut = dodoIntegration.swapExactIn(pool, tokenIn, amountIn, minAmountOut);
|
|
}
|
|
|
|
// Transfer output tokens to caller
|
|
IERC20(tokenOut).safeTransfer(msg.sender, amountOut);
|
|
|
|
return amountOut;
|
|
}
|
|
|
|
/**
|
|
* @notice Check if provider supports token pair
|
|
*/
|
|
function supportsTokenPair(
|
|
address tokenIn,
|
|
address tokenOut
|
|
) external view override returns (bool) {
|
|
return pools[tokenIn][tokenOut] != address(0);
|
|
}
|
|
|
|
/**
|
|
* @notice Get provider name
|
|
*/
|
|
function providerName() external pure override returns (string memory) {
|
|
return "DODO PMM";
|
|
}
|
|
|
|
/**
|
|
* @notice Estimate gas for swap
|
|
*/
|
|
function estimateGas(
|
|
address,
|
|
address,
|
|
uint256
|
|
) external pure override returns (uint256) {
|
|
return 150000; // Typical gas for DODO swap
|
|
}
|
|
|
|
/**
|
|
* @notice Ensure pool exists for token pair
|
|
*/
|
|
function ensurePoolExists(address tokenIn, address tokenOut) external onlyRole(POOL_MANAGER_ROLE) {
|
|
if (pools[tokenIn][tokenOut] == address(0)) {
|
|
_createOptimalPool(tokenIn, tokenOut);
|
|
}
|
|
}
|
|
|
|
/// @dev Default params for stablecoin pairs: 0.03% fee, 1:1 price, k=0.5e18
|
|
uint256 private constant DEFAULT_LP_FEE = 3;
|
|
uint256 private constant DEFAULT_I = 1e18;
|
|
uint256 private constant DEFAULT_K = 0.5e18;
|
|
|
|
/**
|
|
* @notice Create optimal DODO pool via DODOPMMIntegration
|
|
* @dev Requires DODOPMMIntegration to grant POOL_MANAGER_ROLE to this contract
|
|
*/
|
|
function _createOptimalPool(address tokenIn, address tokenOut) internal {
|
|
address pool = dodoIntegration.createPool(
|
|
tokenIn,
|
|
tokenOut,
|
|
DEFAULT_LP_FEE,
|
|
DEFAULT_I,
|
|
DEFAULT_K,
|
|
false // isOpenTWAP - disable for stablecoins
|
|
);
|
|
pools[tokenIn][tokenOut] = pool;
|
|
pools[tokenOut][tokenIn] = pool;
|
|
isKnownPool[pool] = true;
|
|
emit PoolCreated(tokenIn, tokenOut, pool);
|
|
}
|
|
|
|
/**
|
|
* @notice Register existing pool
|
|
*/
|
|
function registerPool(
|
|
address tokenIn,
|
|
address tokenOut,
|
|
address pool
|
|
) external onlyRole(POOL_MANAGER_ROLE) {
|
|
require(pool != address(0), "Zero address");
|
|
|
|
pools[tokenIn][tokenOut] = pool;
|
|
isKnownPool[pool] = true;
|
|
|
|
emit PoolCreated(tokenIn, tokenOut, pool);
|
|
}
|
|
|
|
/**
|
|
* @notice Optimize pool parameters (K, I)
|
|
* @dev DODO PMM parameters are typically oracle-driven; DVM pools may expose
|
|
* setK/setI. Emits for off-chain monitoring. If the pool supports
|
|
* parameter updates, extend this to call the pool's update functions.
|
|
*/
|
|
function optimizePoolParameters(
|
|
address pool,
|
|
uint256 newK,
|
|
uint256 newI
|
|
) external onlyRole(POOL_MANAGER_ROLE) {
|
|
require(isKnownPool[pool], "Unknown pool");
|
|
// DODO DVM/PMM: parameters set at creation; oracle-driven rebalancing.
|
|
// Emit for observability; integrate pool.setK/setI when supported.
|
|
emit PoolOptimized(pool, newK, newI);
|
|
}
|
|
}
|