204 lines
7.6 KiB
Solidity
204 lines
7.6 KiB
Solidity
pragma solidity >=0.6.5;
|
|
|
|
import "forge-std/Test.sol";
|
|
import "../src/TraderJoeV2MultiQuoter.sol";
|
|
import "../src/TraderJoeV2Common.sol";
|
|
import "@traderjoe-xyz/joe-v2/src/LBQuoterV2.sol";
|
|
|
|
interface ILBQuoter {
|
|
function findBestPathFromAmountIn(
|
|
address[] calldata _route,
|
|
uint256 _amountIn
|
|
) external view returns (LBQuoterV2.Quote memory quote);
|
|
}
|
|
|
|
contract TestTraderJoeV2MultiQuoter is Test, TraderJoeV2Common {
|
|
/// @dev error threshold for comparison between MultiQuoter and TraderJoe's LBQuoterV2.
|
|
uint256 constant ERROR_THRESHOLD_1_BPS = 0.0001e18;
|
|
|
|
address constant JOE = 0x6e84a6216eA6dACC71eE8E6b0a5B7322EEbC0fDd;
|
|
address constant WAVAX = 0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7;
|
|
address constant WETHe = 0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB;
|
|
|
|
address constant WAVAX_WETHe_POOL = 0x42Be75636374dfA0e57EB96fA7F68fE7FcdAD8a3;
|
|
address constant JOE_WAVAX_POOL = 0xc01961EdE437Bf0cC41D064B1a3F6F0ea6aa2a40;
|
|
|
|
address constant factory = 0x6E77932A92582f504FF6c4BdbCef7Da6c198aEEf;
|
|
address constant router = 0xE3Ffc583dC176575eEA7FD9dF2A7c65F7E23f4C3;
|
|
|
|
TraderJoeV2MultiQuoter multiQuoter;
|
|
LBQuoterV2 quoter;
|
|
uint256[][] testAmounts;
|
|
|
|
function setUp() public {
|
|
multiQuoter = new TraderJoeV2MultiQuoter();
|
|
quoter = new LBQuoterV2(router, factory);
|
|
|
|
testAmounts = new uint256[][](9);
|
|
|
|
testAmounts[0] = new uint256[](1);
|
|
testAmounts[0][0] = 1 ether;
|
|
|
|
testAmounts[1] = new uint256[](1);
|
|
testAmounts[1][0] = 1000 ether;
|
|
|
|
testAmounts[2] = new uint256[](1);
|
|
testAmounts[2][0] = 100000 ether;
|
|
|
|
testAmounts[3] = new uint256[](13);
|
|
testAmounts[4] = new uint256[](13);
|
|
testAmounts[5] = new uint256[](13);
|
|
for (uint256 i = 0; i < 13; ++i) {
|
|
testAmounts[3][i] = (i + 1) * 1000 ether;
|
|
testAmounts[4][i] = (i + 1) * 50000 ether;
|
|
testAmounts[5][i] = (i + 1) * 100000 ether;
|
|
}
|
|
|
|
testAmounts[6] = new uint256[](50);
|
|
testAmounts[7] = new uint256[](50);
|
|
testAmounts[8] = new uint256[](50);
|
|
for (uint256 i = 0; i < 50; ++i) {
|
|
testAmounts[6][i] = (i + 1) * 1000 ether;
|
|
testAmounts[7][i] = (i + 1) * 10000 ether;
|
|
testAmounts[8][i] = (i + 1) * 50000 ether;
|
|
}
|
|
}
|
|
|
|
function testSingleHopQuotes() public {
|
|
address[] memory tokenPath = new address[](2);
|
|
tokenPath[0] = WAVAX;
|
|
tokenPath[1] = WETHe;
|
|
|
|
address[] memory poolPath = new address[](1);
|
|
poolPath[0] = WAVAX_WETHe_POOL;
|
|
|
|
testAllAmountsAndPathsForBuysAndSells(tokenPath, poolPath);
|
|
}
|
|
|
|
function testMultiHopQuotes() public {
|
|
address[] memory tokenPath = new address[](3);
|
|
tokenPath[0] = JOE;
|
|
tokenPath[1] = WAVAX;
|
|
tokenPath[2] = WETHe;
|
|
|
|
address[] memory poolPath = new address[](2);
|
|
poolPath[0] = JOE_WAVAX_POOL;
|
|
poolPath[1] = WAVAX_WETHe_POOL;
|
|
|
|
testAllAmountsAndPathsForBuysAndSells(tokenPath, poolPath);
|
|
}
|
|
|
|
function testAllAmountsAndPathsForBuysAndSells(address[] memory tokenPath, address[] memory poolPath) private {
|
|
uint256 traderJoeQuoterGasUsage;
|
|
uint256 multiQuoterGasUsage;
|
|
|
|
bytes memory path = toTraderJoeV2Path(tokenPath, poolPath);
|
|
address[] memory reverseTokenPath = reverseAddressPath(tokenPath);
|
|
bytes memory reversePath = toTraderJoeV2Path(reverseTokenPath, reverseAddressPath(poolPath));
|
|
|
|
console.log("Quoter Gas Comparison: ");
|
|
console.log("Token Path: ");
|
|
for (uint256 i = 0; i < tokenPath.length; ++i) {
|
|
console.logAddress(tokenPath[i]);
|
|
}
|
|
|
|
for (uint256 i = 0; i < testAmounts.length; ++i) {
|
|
(traderJoeQuoterGasUsage, multiQuoterGasUsage) = compareQuoterSells(path, tokenPath, testAmounts[i]);
|
|
console.log(
|
|
"Normal Path Sell: test=%d, traderJoeQuoterGasUsage=%d, multiQuoterGasUsage=%d",
|
|
i + 1,
|
|
traderJoeQuoterGasUsage,
|
|
multiQuoterGasUsage
|
|
);
|
|
|
|
(traderJoeQuoterGasUsage, multiQuoterGasUsage) = compareQuoterSells(
|
|
reversePath,
|
|
reverseTokenPath,
|
|
testAmounts[i]
|
|
);
|
|
console.log(
|
|
"Reverse Path Sell: test=%d, traderJoeQuoterGasUsage=%d, multiQuoterGasUsage=%d",
|
|
i + 1,
|
|
traderJoeQuoterGasUsage,
|
|
multiQuoterGasUsage
|
|
);
|
|
|
|
(traderJoeQuoterGasUsage, multiQuoterGasUsage) = compareQuoterBuys(reversePath, tokenPath, testAmounts[i]);
|
|
console.log(
|
|
"Normal Path Buy: test=%d, traderJoeQuoterGasUsage=%d, multiQuoterGasUsage=%d",
|
|
i + 1,
|
|
traderJoeQuoterGasUsage,
|
|
multiQuoterGasUsage
|
|
);
|
|
|
|
(traderJoeQuoterGasUsage, multiQuoterGasUsage) = compareQuoterBuys(path, reverseTokenPath, testAmounts[i]);
|
|
console.log(
|
|
"Reverse Path Buy: test=%d, traderJoeQuoterGasUsage=%d, multiQuoterGasUsage=%d",
|
|
i + 1,
|
|
traderJoeQuoterGasUsage,
|
|
multiQuoterGasUsage
|
|
);
|
|
}
|
|
}
|
|
|
|
function compareQuoterSells(
|
|
bytes memory path,
|
|
address[] memory tokenPath,
|
|
uint256[] memory amountsIn
|
|
) private returns (uint256 traderJoeQuoterGasUsage, uint256 multiQuoterGasUsage) {
|
|
uint256 gas0 = gasleft();
|
|
uint256[] memory multiQuoterAmountsOut;
|
|
try multiQuoter.quoteExactMultiInput(factory, path, amountsIn) {} catch (bytes memory reason) {
|
|
bool success;
|
|
(success, multiQuoterAmountsOut, ) = decodeMultiSwapRevert(reason);
|
|
assertTrue(success);
|
|
}
|
|
uint256 gas1 = gasleft();
|
|
|
|
for (uint256 i = 0; i < amountsIn.length; ++i) {
|
|
try quoter.findBestPathFromAmountIn(tokenPath, amountsIn[i]) returns (LBQuoterV2.Quote memory quote) {
|
|
assertApproxEqRel(
|
|
multiQuoterAmountsOut[i],
|
|
quote.amounts[quote.amounts.length - 1],
|
|
ERROR_THRESHOLD_1_BPS
|
|
);
|
|
} catch {
|
|
assertEq(
|
|
multiQuoterAmountsOut[i],
|
|
0,
|
|
"compareQuoterSells: MultiQuoter amount should be 0 when TraderJoeV2 QuoterV2 reverts"
|
|
);
|
|
}
|
|
}
|
|
return (gas1 - gasleft(), gas0 - gas1);
|
|
}
|
|
|
|
function compareQuoterBuys(
|
|
bytes memory path,
|
|
address[] memory tokenPath,
|
|
uint256[] memory amountsOut
|
|
) private returns (uint256 traderJoeQuoterGasUsage, uint256 multiQuoterGasUsage) {
|
|
uint256 gas0 = gasleft();
|
|
uint256[] memory multiQuoterAmountsIn;
|
|
try multiQuoter.quoteExactMultiOutput(factory, path, amountsOut) {} catch (bytes memory reason) {
|
|
bool success;
|
|
(success, multiQuoterAmountsIn, ) = decodeMultiSwapRevert(reason);
|
|
assertTrue(success);
|
|
}
|
|
uint256 gas1 = gasleft();
|
|
|
|
for (uint256 i = 0; i < amountsOut.length; ++i) {
|
|
try quoter.findBestPathFromAmountOut(tokenPath, amountsOut[i]) returns (LBQuoterV2.Quote memory quote) {
|
|
assertApproxEqRel(multiQuoterAmountsIn[i], quote.amounts[0], ERROR_THRESHOLD_1_BPS);
|
|
} catch {
|
|
assertEq(
|
|
multiQuoterAmountsIn[i],
|
|
0,
|
|
"compareQuoterSells: MultiQuoter amount should be 0 when TraderJoeV2 QuoterV2 reverts"
|
|
);
|
|
}
|
|
}
|
|
return (gas1 - gasleft(), gas0 - gas1);
|
|
}
|
|
}
|