// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "../reserve/IReserveSystem.sol"; /** * @title DODO PMM Pool Interface * @notice Simplified interface for DODO Proactive Market Maker pools * @dev Actual DODO interfaces may vary - this is a simplified version */ interface IDODOPMMPool { function _BASE_TOKEN_() external view returns (address); function _QUOTE_TOKEN_() external view returns (address); function querySellBase(address trader, uint256 payBaseAmount) external view returns (uint256 receiveQuoteAmount, uint256 mtFee); function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount, uint256 mtFee); /// @notice Official DODO DVM: excess base in pool vs reserve is sold; `to` receives quote. function sellBase(address to) external returns (uint256 receiveQuoteAmount); /// @notice Official DODO DVM: excess quote in pool vs reserve is sold; `to` receives base. function sellQuote(address to) external returns (uint256 receiveBaseAmount); function buyShares(address to) external returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare); function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve); function getMidPrice() external view returns (uint256); function _QUOTE_RESERVE_() external view returns (uint256); function _BASE_RESERVE_() external view returns (uint256); } /** * @title DODO Vending Machine Interface * @notice Interface for creating DODO Vending Machine (DVM) pools */ interface IDODOVendingMachine { function createDVM( address baseToken, address quoteToken, uint256 lpFeeRate, uint256 i, uint256 k, bool isOpenTWAP ) external returns (address dvm); } /** * @title DODOPMMIntegration * @notice Integration contract for DODO PMM pools with CompliantUSDT/USDC * @dev Manages liquidity pools on DODO and provides swap functionality between * compliant tokens (cUSDT/cUSDC) and official tokens (USDT/USDC) * * This contract facilitates exchangeability between compliant and official tokens * through DODO's Proactive Market Maker algorithm, which maintains price stability * and provides efficient liquidity. */ contract DODOPMMIntegration is AccessControl, ReentrancyGuard { using SafeERC20 for IERC20; bytes32 public constant POOL_MANAGER_ROLE = keccak256("POOL_MANAGER_ROLE"); bytes32 public constant SWAP_OPERATOR_ROLE = keccak256("SWAP_OPERATOR_ROLE"); uint256 private constant POOL_SURFACE_SAMPLE_AMOUNT = 1; // DODO contracts address public immutable dodoVendingMachine; address public immutable dodoApprove; // DODO's approval contract for gas optimization // Token addresses address public immutable officialUSDT; // Official USDT on destination chain address public immutable officialUSDC; // Official USDC on destination chain address public immutable compliantUSDT; // cUSDT on Chain 138 address public immutable compliantUSDC; // cUSDC on Chain 138 // Pool mappings mapping(address => mapping(address => address)) public pools; // token0 => token1 => pool mapping(address => bool) public isRegisteredPool; mapping(address => bool) public hasStandardPoolSurface; // Pool configuration struct PoolConfig { address pool; address baseToken; address quoteToken; uint256 lpFeeRate; // Basis points (100 = 1%) uint256 i; // Initial price (1e18 = $1 for stablecoins) uint256 k; // Slippage factor (0.5 = 500000000000000000, lower = less slippage) bool isOpenTWAP; // Enable TWAP oracle for price discovery uint256 createdAt; } mapping(address => PoolConfig) public poolConfigs; address[] public allPools; /// @notice Optional ReserveSystem for oracle-backed mid price (base/quote in reserve system) IReserveSystem public reserveSystem; event PoolCreated( address indexed pool, address indexed baseToken, address indexed quoteToken, address creator ); event LiquidityAdded( address indexed pool, address indexed provider, uint256 baseAmount, uint256 quoteAmount, uint256 lpShares ); event SwapExecuted( address indexed pool, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, address trader ); event PoolRemoved(address indexed pool); event ReserveSystemSet(address indexed reserveSystem); event PoolImported( address indexed pool, address indexed baseToken, address indexed quoteToken, address importer ); event PoolSurfaceValidated(address indexed pool, bool standardSurface); constructor( address admin, address dodoVendingMachine_, address dodoApprove_, address officialUSDT_, address officialUSDC_, address compliantUSDT_, address compliantUSDC_ ) { require(admin != address(0), "DODOPMMIntegration: zero admin"); require(dodoVendingMachine_ != address(0), "DODOPMMIntegration: zero DVM"); require(officialUSDT_ != address(0), "DODOPMMIntegration: zero USDT"); require(officialUSDC_ != address(0), "DODOPMMIntegration: zero USDC"); require(compliantUSDT_ != address(0), "DODOPMMIntegration: zero cUSDT"); require(compliantUSDC_ != address(0), "DODOPMMIntegration: zero cUSDC"); _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(POOL_MANAGER_ROLE, admin); _grantRole(SWAP_OPERATOR_ROLE, admin); dodoVendingMachine = dodoVendingMachine_; dodoApprove = dodoApprove_; officialUSDT = officialUSDT_; officialUSDC = officialUSDC_; compliantUSDT = compliantUSDT_; compliantUSDC = compliantUSDC_; } /** * @notice Create DODO PMM pool for cUSDT/USDT pair * @param lpFeeRate Liquidity provider fee rate (basis points, 3 = 0.03%) * @param initialPrice Initial price (1e18 = $1 for stablecoin pairs) * @param k Slippage factor (0.5e18 = 50%, lower = less slippage, higher = more slippage) * @param isOpenTWAP Enable TWAP oracle for price discovery */ function createCUSDTUSDTPool( uint256 lpFeeRate, uint256 initialPrice, uint256 k, bool isOpenTWAP ) external onlyRole(POOL_MANAGER_ROLE) returns (address pool) { require(pools[compliantUSDT][officialUSDT] == address(0), "DODOPMMIntegration: pool exists"); // Create DVM pool using DODO Vending Machine pool = IDODOVendingMachine(dodoVendingMachine).createDVM( compliantUSDT, // baseToken (cUSDT) officialUSDT, // quoteToken (USDT) lpFeeRate, // LP fee rate initialPrice, // Initial price k, // Slippage factor isOpenTWAP // Enable TWAP ); _requireBasicPoolSurface(pool, compliantUSDT, officialUSDT); _recordPool(pool, compliantUSDT, officialUSDT, lpFeeRate, initialPrice, k, isOpenTWAP); emit PoolCreated(pool, compliantUSDT, officialUSDT, msg.sender); } /** * @notice Create DODO PMM pool for cUSDC/USDC pair * @param lpFeeRate Liquidity provider fee rate (basis points) * @param initialPrice Initial price (1e18 = $1) * @param k Slippage factor * @param isOpenTWAP Enable TWAP oracle */ function createCUSDCUSDCPool( uint256 lpFeeRate, uint256 initialPrice, uint256 k, bool isOpenTWAP ) external onlyRole(POOL_MANAGER_ROLE) returns (address pool) { require(pools[compliantUSDC][officialUSDC] == address(0), "DODOPMMIntegration: pool exists"); pool = IDODOVendingMachine(dodoVendingMachine).createDVM( compliantUSDC, officialUSDC, lpFeeRate, initialPrice, k, isOpenTWAP ); _requireBasicPoolSurface(pool, compliantUSDC, officialUSDC); _recordPool(pool, compliantUSDC, officialUSDC, lpFeeRate, initialPrice, k, isOpenTWAP); emit PoolCreated(pool, compliantUSDC, officialUSDC, msg.sender); } /** * @notice Create DODO PMM pool for cUSDT/cUSDC pair (public liquidity per VAULT_SYSTEM_MASTER_TECHNICAL_PLAN §4) * @param lpFeeRate Liquidity provider fee rate (basis points, 3 = 0.03%) * @param initialPrice Initial price (1e18 = $1 for stablecoin pairs) * @param k Slippage factor (0.5e18 = 50%, lower = less slippage) * @param isOpenTWAP Enable TWAP oracle for price discovery */ function createCUSDTCUSDCPool( uint256 lpFeeRate, uint256 initialPrice, uint256 k, bool isOpenTWAP ) external onlyRole(POOL_MANAGER_ROLE) returns (address pool) { require(pools[compliantUSDT][compliantUSDC] == address(0), "DODOPMMIntegration: pool exists"); pool = IDODOVendingMachine(dodoVendingMachine).createDVM( compliantUSDT, // baseToken (cUSDT) compliantUSDC, // quoteToken (cUSDC) lpFeeRate, initialPrice, k, isOpenTWAP ); _requireBasicPoolSurface(pool, compliantUSDT, compliantUSDC); _recordPool(pool, compliantUSDT, compliantUSDC, lpFeeRate, initialPrice, k, isOpenTWAP); emit PoolCreated(pool, compliantUSDT, compliantUSDC, msg.sender); } /** * @notice Create DODO PMM pool for any base/quote token pair (generic) * @param baseToken Base token address * @param quoteToken Quote token address * @param lpFeeRate Liquidity provider fee rate (basis points, 3 = 0.03%) * @param initialPrice Initial price (1e18 = $1 for stablecoins) * @param k Slippage factor (0.5e18 = 50%, lower = less slippage) * @param isOpenTWAP Enable TWAP oracle for price discovery */ function createPool( address baseToken, address quoteToken, uint256 lpFeeRate, uint256 initialPrice, uint256 k, bool isOpenTWAP ) external onlyRole(POOL_MANAGER_ROLE) returns (address pool) { require(baseToken != address(0), "DODOPMMIntegration: zero base"); require(quoteToken != address(0), "DODOPMMIntegration: zero quote"); require(baseToken != quoteToken, "DODOPMMIntegration: same token"); require(pools[baseToken][quoteToken] == address(0), "DODOPMMIntegration: pool exists"); pool = IDODOVendingMachine(dodoVendingMachine).createDVM( baseToken, quoteToken, lpFeeRate, initialPrice, k, isOpenTWAP ); _requireBasicPoolSurface(pool, baseToken, quoteToken); _recordPool(pool, baseToken, quoteToken, lpFeeRate, initialPrice, k, isOpenTWAP); emit PoolCreated(pool, baseToken, quoteToken, msg.sender); } /** * @notice Import an already-deployed DODO PMM pool into integration state. * @dev Use this when the pool exists at the DODO/provider layer but was not * recorded in the integration mappings or allPools inventory. */ function importExistingPool( address pool, address baseToken, address quoteToken, uint256 lpFeeRate, uint256 initialPrice, uint256 k, bool isOpenTWAP ) external onlyRole(POOL_MANAGER_ROLE) { require(pool != address(0), "DODOPMMIntegration: zero pool"); require(baseToken != address(0), "DODOPMMIntegration: zero base"); require(quoteToken != address(0), "DODOPMMIntegration: zero quote"); require(baseToken != quoteToken, "DODOPMMIntegration: same token"); require(pools[baseToken][quoteToken] == address(0), "DODOPMMIntegration: pair already recorded"); require(!isRegisteredPool[pool], "DODOPMMIntegration: pool already registered"); address actualBase = IDODOPMMPool(pool)._BASE_TOKEN_(); address actualQuote = IDODOPMMPool(pool)._QUOTE_TOKEN_(); bool matchesForward = actualBase == baseToken && actualQuote == quoteToken; bool matchesReverse = actualBase == quoteToken && actualQuote == baseToken; require(matchesForward || matchesReverse, "DODOPMMIntegration: pool token mismatch"); if (matchesReverse) { (baseToken, quoteToken) = (quoteToken, baseToken); } _requireBasicPoolSurface(pool, baseToken, quoteToken); _recordPool(pool, baseToken, quoteToken, lpFeeRate, initialPrice, k, isOpenTWAP); emit PoolImported(pool, baseToken, quoteToken, msg.sender); } /** * @notice Add liquidity to a DODO PMM pool * @param pool Pool address * @param baseAmount Amount of base token to deposit * @param quoteAmount Amount of quote token to deposit */ function addLiquidity( address pool, uint256 baseAmount, uint256 quoteAmount ) external nonReentrant returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(baseAmount > 0 && quoteAmount > 0, "DODOPMMIntegration: zero amount"); PoolConfig memory config = poolConfigs[pool]; // Transfer tokens to pool (DODO pools handle their own token management) IERC20(config.baseToken).safeTransferFrom(msg.sender, pool, baseAmount); IERC20(config.quoteToken).safeTransferFrom(msg.sender, pool, quoteAmount); // Call buyShares on DODO pool to add liquidity (baseShare, quoteShare, lpShare) = IDODOPMMPool(pool).buyShares(msg.sender); _setStandardPoolSurface(pool, config.baseToken, config.quoteToken); emit LiquidityAdded(pool, msg.sender, baseAmount, quoteAmount, lpShare); } /** * @notice Re-run full standard-surface validation for an already-registered pool. * @dev Useful during migrations when a replacement pool has been seeded and should * now qualify as a standard DODO venue for routers and indexers. */ function refreshPoolSurface(address pool) external onlyRole(POOL_MANAGER_ROLE) returns (bool standardSurface) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); PoolConfig memory config = poolConfigs[pool]; standardSurface = _setStandardPoolSurface(pool, config.baseToken, config.quoteToken); } /** * @notice Swap cUSDT for official USDT via DODO PMM * @param pool Pool address * @param amountIn Amount of cUSDT to sell * @param minAmountOut Minimum amount of USDT to receive (slippage protection) */ function swapCUSDTForUSDT( address pool, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(poolConfigs[pool].baseToken == compliantUSDT, "DODOPMMIntegration: invalid pool"); require(amountIn > 0, "DODOPMMIntegration: zero amount"); // Transfer cUSDT to pool IERC20(compliantUSDT).safeTransferFrom(msg.sender, pool, amountIn); // Execute swap (sell base token) — DVM sends quote to msg.sender amountOut = IDODOPMMPool(pool).sellBase(msg.sender); require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, compliantUSDT, officialUSDT, amountIn, amountOut, msg.sender); } /** * @notice Swap official USDT for cUSDT via DODO PMM * @param pool Pool address * @param amountIn Amount of USDT to sell * @param minAmountOut Minimum amount of cUSDT to receive */ function swapUSDTForCUSDT( address pool, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(poolConfigs[pool].quoteToken == officialUSDT, "DODOPMMIntegration: invalid pool"); require(amountIn > 0, "DODOPMMIntegration: zero amount"); // Transfer USDT to pool IERC20(officialUSDT).safeTransferFrom(msg.sender, pool, amountIn); // Execute swap (sell quote token) — DVM sends base to msg.sender amountOut = IDODOPMMPool(pool).sellQuote(msg.sender); require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, officialUSDT, compliantUSDT, amountIn, amountOut, msg.sender); } /** * @notice Swap cUSDC for official USDC via DODO PMM * @param pool Pool address * @param amountIn Amount of cUSDC to sell * @param minAmountOut Minimum amount of USDC to receive */ function swapCUSDCForUSDC( address pool, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(poolConfigs[pool].baseToken == compliantUSDC, "DODOPMMIntegration: invalid pool"); require(amountIn > 0, "DODOPMMIntegration: zero amount"); IERC20(compliantUSDC).safeTransferFrom(msg.sender, pool, amountIn); amountOut = IDODOPMMPool(pool).sellBase(msg.sender); require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, compliantUSDC, officialUSDC, amountIn, amountOut, msg.sender); } /** * @notice Swap official USDC for cUSDC via DODO PMM * @param pool Pool address * @param amountIn Amount of USDC to sell * @param minAmountOut Minimum amount of cUSDC to receive */ function swapUSDCForCUSDC( address pool, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(poolConfigs[pool].quoteToken == officialUSDC, "DODOPMMIntegration: invalid pool"); require(amountIn > 0, "DODOPMMIntegration: zero amount"); IERC20(officialUSDC).safeTransferFrom(msg.sender, pool, amountIn); amountOut = IDODOPMMPool(pool).sellQuote(msg.sender); require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, officialUSDC, compliantUSDC, amountIn, amountOut, msg.sender); } /** * @notice Swap cUSDT for cUSDC via cUSDT/cUSDC DODO PMM pool (public liquidity pair per Master Plan §4) */ function swapCUSDTForUSDC( address pool, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(poolConfigs[pool].baseToken == compliantUSDT && poolConfigs[pool].quoteToken == compliantUSDC, "DODOPMMIntegration: invalid pool"); require(amountIn > 0, "DODOPMMIntegration: zero amount"); IERC20(compliantUSDT).safeTransferFrom(msg.sender, pool, amountIn); amountOut = IDODOPMMPool(pool).sellBase(msg.sender); require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, compliantUSDT, compliantUSDC, amountIn, amountOut, msg.sender); } /** * @notice Swap cUSDC for cUSDT via cUSDT/cUSDC DODO PMM pool */ function swapUSDCForCUSDT( address pool, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); require(poolConfigs[pool].baseToken == compliantUSDT && poolConfigs[pool].quoteToken == compliantUSDC, "DODOPMMIntegration: invalid pool"); require(amountIn > 0, "DODOPMMIntegration: zero amount"); IERC20(compliantUSDC).safeTransferFrom(msg.sender, pool, amountIn); amountOut = IDODOPMMPool(pool).sellQuote(msg.sender); require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, compliantUSDC, compliantUSDT, amountIn, amountOut, msg.sender); } /** * @notice Generic swap for any registered pool (full mesh routing). * @param pool Pool address * @param tokenIn Token to sell * @param amountIn Amount of tokenIn * @param minAmountOut Minimum amount of tokenOut to receive * @return amountOut Amount of quote/base token received (sent to msg.sender) */ function swapExactIn( address pool, address tokenIn, uint256 amountIn, uint256 minAmountOut ) external nonReentrant returns (uint256 amountOut) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); PoolConfig memory config = poolConfigs[pool]; address tokenOut; if (tokenIn == config.baseToken) { tokenOut = config.quoteToken; IERC20(tokenIn).safeTransferFrom(msg.sender, pool, amountIn); amountOut = IDODOPMMPool(pool).sellBase(msg.sender); } else if (tokenIn == config.quoteToken) { tokenOut = config.baseToken; IERC20(tokenIn).safeTransferFrom(msg.sender, pool, amountIn); amountOut = IDODOPMMPool(pool).sellQuote(msg.sender); } else { revert("DODOPMMIntegration: token not in pool"); } require(amountOut >= minAmountOut, "DODOPMMIntegration: insufficient output"); emit SwapExecuted(pool, tokenIn, tokenOut, amountIn, amountOut, msg.sender); } /** * @notice Set optional ReserveSystem for oracle-backed mid price * @param reserveSystem_ ReserveSystem address (address(0) to disable) */ function setReserveSystem(address reserveSystem_) external onlyRole(DEFAULT_ADMIN_ROLE) { reserveSystem = IReserveSystem(reserveSystem_); emit ReserveSystemSet(reserveSystem_); } /** * @notice Get pool price: oracle (ReserveSystem) if configured and available, else pool getMidPrice() * @param pool Pool address * @return price Price in 18 decimals (quote per base; 1e18 = $1 for stablecoins) */ function getPoolPriceOrOracle(address pool) public view returns (uint256 price) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); if (address(reserveSystem) != address(0)) { PoolConfig memory config = poolConfigs[pool]; try reserveSystem.getConversionPrice(config.baseToken, config.quoteToken) returns (uint256 oraclePrice) { if (oraclePrice > 0) return oraclePrice; } catch { } } return IDODOPMMPool(pool).getMidPrice(); } /** * @notice Get current pool price (pool mid only; use getPoolPriceOrOracle for oracle-backed price) * @param pool Pool address * @return price Current mid price (1e18 = $1 for stablecoins) */ function getPoolPrice(address pool) external view returns (uint256 price) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); price = IDODOPMMPool(pool).getMidPrice(); } /** * @notice Get pool reserves * @param pool Pool address * @return baseReserve Base token reserve * @return quoteReserve Quote token reserve */ function getPoolReserves(address pool) external view returns (uint256 baseReserve, uint256 quoteReserve) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); (baseReserve, quoteReserve) = IDODOPMMPool(pool).getVaultReserve(); } /** * @notice Get pool configuration * @param pool Pool address * @return config Pool configuration struct */ function getPoolConfig(address pool) external view returns (PoolConfig memory config) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); config = poolConfigs[pool]; } /** * @notice Get all registered pools * @return List of all pool addresses */ function getAllPools() external view returns (address[] memory) { return allPools; } /** * @notice Remove pool (emergency only) * @param pool Pool address to remove */ function removePool(address pool) external onlyRole(DEFAULT_ADMIN_ROLE) { require(isRegisteredPool[pool], "DODOPMMIntegration: pool not registered"); PoolConfig memory config = poolConfigs[pool]; pools[config.baseToken][config.quoteToken] = address(0); pools[config.quoteToken][config.baseToken] = address(0); isRegisteredPool[pool] = false; hasStandardPoolSurface[pool] = false; delete poolConfigs[pool]; emit PoolRemoved(pool); } function _recordPool( address pool, address baseToken, address quoteToken, uint256 lpFeeRate, uint256 initialPrice, uint256 k, bool isOpenTWAP ) internal { pools[baseToken][quoteToken] = pool; pools[quoteToken][baseToken] = pool; isRegisteredPool[pool] = true; allPools.push(pool); poolConfigs[pool] = PoolConfig({ pool: pool, baseToken: baseToken, quoteToken: quoteToken, lpFeeRate: lpFeeRate, i: initialPrice, k: k, isOpenTWAP: isOpenTWAP, createdAt: block.timestamp }); } function _requireBasicPoolSurface( address pool, address expectedBaseToken, address expectedQuoteToken ) internal view { require(pool != address(0), "DODOPMMIntegration: zero pool"); require(IDODOPMMPool(pool)._BASE_TOKEN_() == expectedBaseToken, "DODOPMMIntegration: unexpected base token"); require(IDODOPMMPool(pool)._QUOTE_TOKEN_() == expectedQuoteToken, "DODOPMMIntegration: unexpected quote token"); IDODOPMMPool(pool).getVaultReserve(); IDODOPMMPool(pool).getMidPrice(); IDODOPMMPool(pool)._BASE_RESERVE_(); IDODOPMMPool(pool)._QUOTE_RESERVE_(); } function _setStandardPoolSurface( address pool, address expectedBaseToken, address expectedQuoteToken ) internal returns (bool standardSurface) { standardSurface = _hasStandardPoolSurface(pool, expectedBaseToken, expectedQuoteToken); require(standardSurface, "DODOPMMIntegration: pool missing standard DODO surface"); hasStandardPoolSurface[pool] = true; emit PoolSurfaceValidated(pool, true); } function _hasStandardPoolSurface( address pool, address expectedBaseToken, address expectedQuoteToken ) internal view returns (bool) { _requireBasicPoolSurface(pool, expectedBaseToken, expectedQuoteToken); (uint256 baseReserve, uint256 quoteReserve) = IDODOPMMPool(pool).getVaultReserve(); if (baseReserve == 0 || quoteReserve == 0) { return false; } try IDODOPMMPool(pool).querySellBase(address(this), POOL_SURFACE_SAMPLE_AMOUNT) returns (uint256, uint256) { } catch { return false; } try IDODOPMMPool(pool).querySellQuote(address(this), POOL_SURFACE_SAMPLE_AMOUNT) returns (uint256, uint256) { } catch { return false; } return true; } }