// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Script, console} from "forge-std/Script.sol"; import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFlashReceiver.sol"; import {QuotePushTreasuryManager} from "../../contracts/flash/QuotePushTreasuryManager.sol"; interface IDODOPMMPoolQuoteManagedUsdt { function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount, uint256 mtFee); } /// @notice USDT rail mirror of RunManagedMainnetAaveCwusdcUsdcQuotePushCycle. contract RunManagedMainnetAaveCwusdtUsdtQuotePushCycle is Script { address internal constant DEFAULT_POOL = 0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC; address internal constant DEFAULT_CWUSDT = 0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE; address internal constant DEFAULT_USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; uint256 internal constant DEFENDED_SAFE_CAP_RAW = 2_964_298; function run() external { uint256 pk = vm.envUint("PRIVATE_KEY"); address receiver = vm.envAddress("AAVE_QUOTE_PUSH_RECEIVER_MAINNET"); address managerAddr = vm.envAddress("QUOTE_PUSH_TREASURY_MANAGER_MAINNET"); address pool = vm.envOr("POOL_CWUSDT_USDT_MAINNET", DEFAULT_POOL); address integration = vm.envAddress("DODO_PMM_INTEGRATION_MAINNET"); address baseToken = vm.envOr("CWUSDT_MAINNET", DEFAULT_CWUSDT); address usdt = vm.envOr("USDT_MAINNET", DEFAULT_USDT); address unwinder = vm.envAddress("QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET"); uint256 amount = vm.envUint("FLASH_QUOTE_AMOUNT_RAW"); uint256 localCap = vm.envOr("MAX_FLASH_QUOTE_AMOUNT_RAW", DEFENDED_SAFE_CAP_RAW); bool harvest = vm.envOr("QUOTE_PUSH_TREASURY_HARVEST", uint256(1)) == 1; uint256 gasHoldbackTargetRaw = vm.envOr("QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW", uint256(0)); require(pool == DEFAULT_POOL, "defended pool only"); require(localCap <= DEFENDED_SAFE_CAP_RAW, "local cap exceeds defended safe cap"); require(amount <= localCap, "flash amount exceeds cap"); QuotePushTreasuryManager manager = QuotePushTreasuryManager(managerAddr); AaveQuotePushFlashReceiver.QuotePushParams memory p = _loadQuotePushParams(receiver, pool, integration, baseToken, unwinder, amount); vm.startBroadcast(pk); (uint256 harvested, uint256 gasAmount, uint256 recycleAmount) = manager.runManagedCycle(usdt, amount, p, harvest, gasHoldbackTargetRaw); vm.stopBroadcast(); console.log("managedCycleHarvestedRaw", harvested); console.log("managedCycleGasDistributionRaw", gasAmount); console.log("managedCycleRecycleDistributionRaw", recycleAmount); } function _loadQuotePushParams( address receiver, address pool, address integration, address baseToken, address unwinder, uint256 amount ) internal view returns (AaveQuotePushFlashReceiver.QuotePushParams memory p) { uint256 minPmmNum = vm.envOr("MIN_OUT_PMM_NUM", uint256(985)); uint256 minPmmDen = vm.envOr("MIN_OUT_PMM_DEN", uint256(1000)); uint256 minOutPmm = vm.envOr("MIN_OUT_PMM", uint256(0)); if (minOutPmm == 0) { (uint256 baseOut,) = IDODOPMMPoolQuoteManagedUsdt(pool).querySellQuote(receiver, amount); minOutPmm = (baseOut * minPmmNum) / minPmmDen; } uint256 premiumBps = vm.envOr("AAVE_FLASH_PREMIUM_BPS", uint256(5)); uint256 buf = vm.envOr("MIN_OUT_UNWIND_BUFFER_RAW", uint256(5000)); uint256 premium = (amount * premiumBps) / 10000; uint256 minOutUnwind = vm.envOr("MIN_OUT_UNWIND", amount + premium + buf); uint256 unwindMode = vm.envOr("UNWIND_MODE", uint256(1)); bytes memory unwindData; if (unwindMode == 1) { address dodoPool = vm.envOr("UNWIND_DODO_POOL", pool); unwindData = abi.encode(dodoPool); } else { revert("USDT rail: UNWIND_MODE=1 (DODO) required for now"); } p = AaveQuotePushFlashReceiver.QuotePushParams({ integration: integration, pmmPool: pool, baseToken: baseToken, externalUnwinder: unwinder, minOutPmm: minOutPmm, minOutUnwind: minOutUnwind, unwindData: unwindData, atomicBridge: AaveQuotePushFlashReceiver.AtomicBridgeParams({ coordinator: address(0), sourceChain: 0, destinationChain: 0, destinationAsset: address(0), bridgeAmount: 0, minDestinationAmount: 0, destinationRecipient: address(0), destinationDeadline: 0, routeId: bytes32(0), settlementMode: bytes32(0), submitCommitment: false }) }); } }