From 82ba6f152cfc316626f1c1e529d8f6e7226ee6a3 Mon Sep 17 00:00:00 2001 From: Terry Pawn Date: Thu, 18 Apr 2024 18:05:11 +0800 Subject: [PATCH 1/2] Add FlashSwapRouterV3Helper --- contracts/swap/FlashSwapRouterV3Helper.sol | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 contracts/swap/FlashSwapRouterV3Helper.sol diff --git a/contracts/swap/FlashSwapRouterV3Helper.sol b/contracts/swap/FlashSwapRouterV3Helper.sol new file mode 100644 index 00000000..540cc85a --- /dev/null +++ b/contracts/swap/FlashSwapRouterV3Helper.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.6.10 <0.8.0; + +import "./FlashSwapRouterV3.sol"; + +contract FlashSwapRouterV3Helper { + FlashSwapRouterV3 public immutable flashSwapRouter; + + constructor(address flashSwapRouter_) public { + flashSwapRouter = FlashSwapRouterV3(flashSwapRouter_); + } + + /// @dev Only meant for an off-chain client to call with eth_call. + /// When inQuote does not increase monotonically with outR, + /// this function does not guarantee to return the optimal solution. + function getBuyRFromQuote( + IFundV5 fund, + bool needWrap, + address queenSwapOrPrimaryMarketRouter, + address tokenQuote, + uint256 minOutR, + uint256 maxOutR, + uint256 inQuote + ) external returns (uint256 outR) { + while (minOutR < maxOutR - 1) { + uint256 midOutR = minOutR / 2 + maxOutR / 2; + (bool success, bytes memory data) = address(flashSwapRouter).call( + abi.encodeWithSelector( + FlashSwapRouterV3.getBuyR.selector, + fund, + needWrap, + queenSwapOrPrimaryMarketRouter, + tokenQuote, + midOutR + ) + ); + if (success) { + (uint256 quoteDelta, ) = abi.decode(data, (uint256, uint256)); + if (quoteDelta <= inQuote) { + minOutR = midOutR; + continue; + } + } + maxOutR = midOutR; + } + return minOutR; + } +} From d526d04beab3dce2d63a7a35cdaa1986c4832bc8 Mon Sep 17 00:00:00 2001 From: Terry Pawn Date: Fri, 19 Apr 2024 13:27:10 +0800 Subject: [PATCH 2/2] Update comments --- contracts/swap/FlashSwapRouterV3Helper.sol | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/contracts/swap/FlashSwapRouterV3Helper.sol b/contracts/swap/FlashSwapRouterV3Helper.sol index 540cc85a..10497cb8 100644 --- a/contracts/swap/FlashSwapRouterV3Helper.sol +++ b/contracts/swap/FlashSwapRouterV3Helper.sol @@ -11,8 +11,12 @@ contract FlashSwapRouterV3Helper { } /// @dev Only meant for an off-chain client to call with eth_call. - /// When inQuote does not increase monotonically with outR, - /// this function does not guarantee to return the optimal solution. + /// This function uses binary search to find the maximum `outR` in the range `[minOutR, maxOutR)` + /// such that `getBuyR(outR).quoteDelta <= inQuote`. When `inQuote` does not increase monotonically + /// with `outR`, this function does not guarantee to return the optimal solution. + /// + /// Although `FlashSwapRouterV3.getBuyR` is not a view function, it typically does not alter any + /// contract state. However, this function fails when `FlashSwapRouterV3.getBuyR` does modify some state. function getBuyRFromQuote( IFundV5 fund, bool needWrap,