// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {IAtomicQuoteEngine} from "./interfaces/IAtomicQuoteEngine.sol"; import {IAtomicBridgeCoordinator} from "./interfaces/IAtomicBridgeCoordinator.sol"; import {IAtomicLiquidityVault} from "./interfaces/IAtomicLiquidityVault.sol"; import {IAtomicFulfillerRegistry} from "./interfaces/IAtomicFulfillerRegistry.sol"; import {AtomicFeePolicy} from "./AtomicFeePolicy.sol"; import {AtomicTypes} from "./AtomicTypes.sol"; contract AtomicQuoteEngine is IAtomicQuoteEngine { IAtomicBridgeCoordinator public immutable coordinator; IAtomicLiquidityVault public immutable vault; IAtomicFulfillerRegistry public immutable fulfillerRegistry; AtomicFeePolicy public immutable feePolicy; constructor( address coordinator_, address vault_, address fulfillerRegistry_, address feePolicy_ ) { coordinator = IAtomicBridgeCoordinator(coordinator_); vault = IAtomicLiquidityVault(vault_); fulfillerRegistry = IAtomicFulfillerRegistry(fulfillerRegistry_); feePolicy = AtomicFeePolicy(feePolicy_); } function quote( bytes32 corridorId, uint256 amountIn, uint256 minAmountOut, address fulfiller ) external view returns (AtomicTypes.AtomicQuote memory q) { AtomicTypes.CorridorConfig memory cfg = coordinator.getCorridorConfig(corridorId); AtomicTypes.CorridorLiquidityState memory state = vault.getCorridorLiquidityState(corridorId, cfg.assetOut); (uint256 fulfillerFee, uint256 protocolFee) = feePolicy.quoteFees(corridorId, amountIn); uint256 requiredBond = feePolicy.requiredBond(corridorId, minAmountOut); bool authorized = fulfillerRegistry.isFulfillerAuthorized(fulfiller, corridorId); bool bondSufficient = fulfillerRegistry.canCover(fulfiller, requiredBond); q = AtomicTypes.AtomicQuote({ routeClass: _routeClass(cfg, state, amountIn, minAmountOut, authorized, bondSufficient), availableLiquidity: state.freeLiquidity > state.targetBuffer ? state.freeLiquidity - state.targetBuffer : 0, freeLiquidity: state.freeLiquidity, fulfillerFee: fulfillerFee, protocolFee: protocolFee, requiredBond: requiredBond, settlementBacklog: state.settlementBacklog, deadlineWindow: cfg.fulfilmentTimeout, corridorEnabled: cfg.enabled, corridorDegraded: cfg.degraded, fulfillerAuthorized: authorized, fulfillerBondSufficient: bondSufficient }); } function _routeClass( AtomicTypes.CorridorConfig memory cfg, AtomicTypes.CorridorLiquidityState memory state, uint256 amountIn, uint256 minAmountOut, bool authorized, bool bondSufficient ) internal pure returns (AtomicTypes.RouteClass) { if (!cfg.enabled || cfg.degraded) { return AtomicTypes.RouteClass.Blocked; } if ( amountIn > cfg.maxNotional || minAmountOut > state.freeLiquidity || state.settlementBacklog > cfg.maxSettlementBacklog ) { return AtomicTypes.RouteClass.Blocked; } if (!authorized || !bondSufficient) { return AtomicTypes.RouteClass.Planning; } return AtomicTypes.RouteClass.ExecutionReady; } }