Skip to content

Commit 4c8b54a

Browse files
committedFeb 8, 2025
feat: hybrid exchange helper v2
1 parent 7ed41cc commit 4c8b54a

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
6+
7+
interface IExchangeHelpersV2 {
8+
function getDy(uint256 _dx, bool _collToBold, IERC20 _collToken) external returns (uint256 dy);
9+
function getDx(uint256 _dy, bool _collToBold, IERC20 _collToken) external returns (uint256 dx);
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.18;
4+
5+
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
6+
import {IWETH} from "../../../Interfaces/IWETH.sol";
7+
import {ICurveStableswapNGPool} from "./Curve/ICurveStableswapNGPool.sol";
8+
import {IQuoterV2} from "./UniswapV3/IQuoterV2.sol";
9+
import {IExchangeHelpersV2} from "../../Interfaces/IExchangeHelpersV2.sol";
10+
11+
contract HybridCurveUniV3ExchangeHelpersV2 is IExchangeHelpersV2 {
12+
IERC20 public immutable USDC;
13+
IWETH public immutable WETH;
14+
15+
// Curve
16+
ICurveStableswapNGPool public immutable curvePool;
17+
uint128 public immutable USDC_INDEX;
18+
uint128 public immutable BOLD_TOKEN_INDEX;
19+
20+
// Uniswap
21+
uint24 public immutable feeUsdcWeth;
22+
uint24 public immutable feeWethColl;
23+
IQuoterV2 public immutable uniV3Quoter;
24+
25+
constructor(
26+
IERC20 _usdc,
27+
IWETH _weth,
28+
// Curve
29+
ICurveStableswapNGPool _curvePool,
30+
uint128 _usdcIndex,
31+
uint128 _boldIndex,
32+
// UniV3
33+
uint24 _feeUsdcWeth,
34+
uint24 _feeWethColl,
35+
IQuoterV2 _uniV3Quoter
36+
) {
37+
USDC = _usdc;
38+
WETH = _weth;
39+
40+
// Curve
41+
curvePool = _curvePool;
42+
USDC_INDEX = _usdcIndex;
43+
BOLD_TOKEN_INDEX = _boldIndex;
44+
45+
// Uniswap
46+
feeUsdcWeth = _feeUsdcWeth;
47+
feeWethColl = _feeWethColl;
48+
uniV3Quoter = _uniV3Quoter;
49+
}
50+
51+
function getDy(uint256 _dx, bool _collToBold, IERC20 _collToken) external returns (uint256 dy) {
52+
if (_collToBold) {
53+
// (Coll ->) WETH -> USDC?
54+
bytes memory path;
55+
if (address(WETH) == address(_collToken)) {
56+
path = abi.encodePacked(WETH, feeUsdcWeth, USDC);
57+
} else {
58+
path = abi.encodePacked(_collToken, feeWethColl, WETH, feeUsdcWeth, USDC);
59+
}
60+
61+
(uint256 uniDy,,,) = uniV3Quoter.quoteExactInput(path, _dx);
62+
63+
// USDC -> BOLD?
64+
dy = curvePool.get_dy(int128(USDC_INDEX), int128(BOLD_TOKEN_INDEX), uniDy);
65+
} else {
66+
// BOLD -> USDC?
67+
uint256 curveDy = curvePool.get_dy(int128(BOLD_TOKEN_INDEX), int128(USDC_INDEX), _dx);
68+
69+
// USDC -> WETH (-> Coll)?
70+
bytes memory path;
71+
if (address(WETH) == address(_collToken)) {
72+
path = abi.encodePacked(USDC, feeUsdcWeth, WETH);
73+
} else {
74+
path = abi.encodePacked(USDC, feeUsdcWeth, WETH, feeWethColl, _collToken);
75+
}
76+
77+
(dy,,,) = uniV3Quoter.quoteExactInput(path, curveDy);
78+
}
79+
}
80+
81+
function getDx(uint256 _dy, bool _collToBold, IERC20 _collToken) external returns (uint256 dx) {
82+
if (_collToBold) {
83+
// USDC? -> BOLD
84+
uint256 curveDx = curvePool.get_dx(int128(USDC_INDEX), int128(BOLD_TOKEN_INDEX), _dy);
85+
86+
// Uniswap expects path to be reversed when quoting exact output
87+
// USDC <- WETH (<- Coll)?
88+
bytes memory path;
89+
if (address(WETH) == address(_collToken)) {
90+
path = abi.encodePacked(USDC, feeUsdcWeth, WETH);
91+
} else {
92+
path = abi.encodePacked(USDC, feeUsdcWeth, WETH, feeWethColl, _collToken);
93+
}
94+
95+
(dx,,,) = uniV3Quoter.quoteExactOutput(path, curveDx);
96+
} else {
97+
// Uniswap expects path to be reversed when quoting exact output
98+
// (Coll <-) WETH <- USDC?
99+
bytes memory path;
100+
if (address(WETH) == address(_collToken)) {
101+
path = abi.encodePacked(WETH, feeUsdcWeth, USDC);
102+
} else {
103+
path = abi.encodePacked(_collToken, feeWethColl, WETH, feeUsdcWeth, USDC);
104+
}
105+
106+
(uint256 uniDx,,,) = uniV3Quoter.quoteExactOutput(path, _dy);
107+
108+
// BOLD? -> USDC
109+
dx = curvePool.get_dx(int128(BOLD_TOKEN_INDEX), int128(USDC_INDEX), uniDx);
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)