Add Trader Joe V2 Mixin to Avalanche BridgeAdapter (#686)

* Add Trader Joe V2 Mixin to Avalanche BridgeAdapter

* Add TraderJoeV2 MixIn tests

* update forked function signatures

* Update Avalanche FQT address to reflect Trader Joe V2 MixIn

* Update CHANGELOG
This commit is contained in:
Savarn Dontamsetti (Sav) 2023-04-20 12:48:21 +09:00 committed by GitHub
parent ff104e7505
commit b483805a22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 307 additions and 55 deletions

View File

@ -1,4 +1,13 @@
[ [
{
"version": "0.42.0",
"changes": [
{
"note": "Add Trader Joe V2 support on Avalanche"
}
],
"timestamp": 1681960738
},
{ {
"version": "0.41.0", "version": "0.41.0",
"changes": [ "changes": [

View File

@ -26,6 +26,7 @@ import "./mixins/MixinKyberElastic.sol";
import "./mixins/MixinAaveV2.sol"; import "./mixins/MixinAaveV2.sol";
import "./mixins/MixinNerve.sol"; import "./mixins/MixinNerve.sol";
import "./mixins/MixinPlatypus.sol"; import "./mixins/MixinPlatypus.sol";
import "./mixins/MixinTraderJoeV2.sol";
import "./mixins/MixinUniswapV2.sol"; import "./mixins/MixinUniswapV2.sol";
import "./mixins/MixinWOOFi.sol"; import "./mixins/MixinWOOFi.sol";
import "./mixins/MixinZeroExBridge.sol"; import "./mixins/MixinZeroExBridge.sol";
@ -41,6 +42,7 @@ contract AvalancheBridgeAdapter is
MixinAaveV2, MixinAaveV2,
MixinNerve, MixinNerve,
MixinPlatypus, MixinPlatypus,
MixinTraderJoeV2,
MixinUniswapV2, MixinUniswapV2,
MixinWOOFi, MixinWOOFi,
MixinZeroExBridge MixinZeroExBridge
@ -100,6 +102,11 @@ contract AvalancheBridgeAdapter is
return (0, true); return (0, true);
} }
boughtAmount = _tradePlatypus(buyToken, sellAmount, order.bridgeData); boughtAmount = _tradePlatypus(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.TRADERJOEV2) {
if (dryRun) {
return (0, true);
}
boughtAmount = _tradeTraderJoeV2(buyToken, sellAmount, order.bridgeData);
} else if (protocolId == BridgeProtocols.WOOFI) { } else if (protocolId == BridgeProtocols.WOOFI) {
if (dryRun) { if (dryRun) {
return (0, true); return (0, true);

View File

@ -56,4 +56,5 @@ library BridgeProtocols {
uint128 internal constant AAVEV3 = 32; uint128 internal constant AAVEV3 = 32;
uint128 internal constant KYBERELASTIC = 33; uint128 internal constant KYBERELASTIC = 33;
uint128 internal constant BARTER = 34; uint128 internal constant BARTER = 34;
uint128 internal constant TRADERJOEV2 = 35;
} }

View File

@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright 2023 ZeroEx Intl.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
pragma solidity ^0.6.5;
pragma experimental ABIEncoderV2;
import "@0x/contracts-erc20/src/v06/LibERC20TokenV06.sol";
import "@0x/contracts-erc20/src/IERC20Token.sol";
import "../IBridgeAdapter.sol";
interface ILBRouter {
/// @notice Swaps exact tokens for tokens while performing safety checks
/// @param amountIn The amount of token to send
/// @param amountOutMin The min amount of token to receive
/// @param pairBinSteps The bin step of the pairs (0: V1, other values will use V2)
/// @param tokenPath The swap path using the binSteps following `_pairBinSteps`
/// @param to The address of the recipient
/// @param deadline The deadline of the tx
/// @return amountOut Output amount of the swap
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
uint256[] memory pairBinSteps,
IERC20Token[] memory tokenPath,
address to,
uint256 deadline
) external returns (uint256 amountOut);
}
contract MixinTraderJoeV2 {
using LibERC20TokenV06 for IERC20Token;
function _tradeTraderJoeV2(
IERC20Token buyToken,
uint256 sellAmount,
bytes memory bridgeData
) internal returns (uint256 boughtAmount) {
ILBRouter router;
IERC20Token[] memory tokenPath;
uint256[] memory pairBinSteps;
{
address[] memory _path;
(router, _path, pairBinSteps) = abi.decode(bridgeData, (ILBRouter, address[], uint256[]));
// To get around `abi.decode()` not supporting interface array types.
assembly {
tokenPath := _path
}
}
require(tokenPath.length >= 2, "MixinTraderJoeV2/PATH_LENGTH_MUST_BE_AT_LEAST_TWO");
require(
tokenPath.length == pairBinSteps.length + 1,
"MixinTraderJoeV2/PAIR_BIN_STEPS_LENGTH_MUST_BE_ONE_LESS_THAN_TOKEN_PATH_LENGTH"
);
require(
tokenPath[tokenPath.length - 1] == buyToken,
"MixinTraderJoeV2/LAST_ELEMENT_OF_PATH_MUST_MATCH_OUTPUT_TOKEN"
);
// Grant the Trader Joe V2 router an allowance to sell the first token.
tokenPath[0].approveIfBelow(address(router), sellAmount);
boughtAmount = router.swapExactTokensForTokens(
sellAmount,
1,
pairBinSteps,
tokenPath,
address(this),
block.timestamp
);
}
}

View File

@ -4,48 +4,62 @@
"UniswapV3Router": "0x0000000000000000000000000000000000000000", "UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x952ffc4c47d66b454a8181f5c68b6248e18b66ec" "KyberElasticPool": "0x952ffc4c47d66b454a8181f5c68b6248e18b66ec",
"TraderJoeV2Pool": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
}, },
"56": { "56": {
"UniswapV2Router": "0x10ed43c718714eb63d5aa57b78b54704e256024e", "UniswapV2Router": "0x10ed43c718714eb63d5aa57b78b54704e256024e",
"UniswapV3Router": "0x0000000000000000000000000000000000000000", "UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0xfbfab68ba077d099cd4b66fa76920572cc0b557c" "KyberElasticPool": "0xfbfab68ba077d099cd4b66fa76920572cc0b557c",
"TraderJoeV2Pool": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
}, },
"137": { "137": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", "UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506",
"UniswapV3Router": "0x0000000000000000000000000000000000000000", "UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0xf9cc934753a127100585812181ac04d07158a4c2" "KyberElasticPool": "0xf9cc934753a127100585812181ac04d07158a4c2",
"TraderJoeV2Pool": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
}, },
"43114": { "43114": {
"UniswapV2Router": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10", "UniswapV2Router": "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10",
"UniswapV3Router": "0x0000000000000000000000000000000000000000", "UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x6038373de7f64da99b2a31951628b7d778b2c3cf" "KyberElasticPool": "0x6038373de7f64da99b2a31951628b7d778b2c3cf",
"TraderJoeV2Pool": "0x1D7A1a79e2b4Ef88D2323f3845246D24a3c20F1d",
"TraderJoeV2Router": "0xE3Ffc583dC176575eEA7FD9dF2A7c65F7E23f4C3"
}, },
"250": { "250": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", "UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506",
"UniswapV3Router": "0x0000000000000000000000000000000000000000", "UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x8dcf5fed6ae6bf0befb5e4f0c9414c2cb9a4ed01" "KyberElasticPool": "0x8dcf5fed6ae6bf0befb5e4f0c9414c2cb9a4ed01",
"TraderJoeV2Pool": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
}, },
"10": { "10": {
"UniswapV2Router": "0x0000000000000000000000000000000000000000", "UniswapV2Router": "0x0000000000000000000000000000000000000000",
"UniswapV3Router": "0x61ffe014ba17989e743c5f6cb21bf9697530b21e", "UniswapV3Router": "0x61ffe014ba17989e743c5f6cb21bf9697530b21e",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x7e29ccaa4bf2894aca02c77e6b99cafc1d24b2f5" "KyberElasticPool": "0x7e29ccaa4bf2894aca02c77e6b99cafc1d24b2f5",
"TraderJoeV2Pool": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
}, },
"42161": { "42161": {
"UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506", "UniswapV2Router": "0x1b02da8cb0d097eb8d57a175b88c7d8b47997506",
"UniswapV3Router": "0x0000000000000000000000000000000000000000", "UniswapV3Router": "0x0000000000000000000000000000000000000000",
"KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f", "KyberElasticQuoter": "0x0d125c15d54ca1f8a813c74a81aee34ebb508c1f",
"KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83", "KyberElasticRouter": "0xc1e7dfe73e1598e3910ef4c7845b68a9ab6f4c83",
"KyberElasticPool": "0x087abaab9cd85025a8b3916948c69fe173c837ea" "KyberElasticPool": "0x087abaab9cd85025a8b3916948c69fe173c837ea",
"TraderJoeV2Pool": "0x0000000000000000000000000000000000000000",
"TraderJoeV2Router": "0x0000000000000000000000000000000000000000"
} }
} }

View File

@ -20,8 +20,8 @@
"43114": { "43114": {
"WrappedNativeToken": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7", "WrappedNativeToken": "0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7",
"DAI": "0xd586e7f844cea2f87f50152665bcbc2c279d8d70", "DAI": "0xd586e7f844cea2f87f50152665bcbc2c279d8d70",
"USDC": "0xa7d7079b0fead91f3e65f86e8915cb59c1a4c664", "USDC": "0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E",
"USDT": "0xc7198437980c041c805A1EDcbA50c1Ce5db95118" "USDT": "0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7"
}, },
"250": { "250": {
"WrappedNativeToken": "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83", "WrappedNativeToken": "0x21be370d5312f44cb42ce377bc9b8a0cef1a4c83",

View File

@ -54,6 +54,75 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
} }
} }
function test_swapERC20ForERC20OnTraderJoeV2() public {
for (uint256 i = 0; i < chains.length; i++) {
// TraderJoeV2 mixin only enabled on Avalanche
if (i != 3) {
continue;
}
vm.selectFork(forkIds[chains[i]]);
labelAddresses(
chains[i],
indexChainsByChain[chains[i]],
getTokens(i),
getContractAddresses(i),
getLiquiditySourceAddresses(i)
);
swapOnTraderJoeV2(getTokens(i), getContractAddresses(i), getLiquiditySourceAddresses(i));
}
}
function swapOnTraderJoeV2(
TokenAddresses memory tokens,
ContractAddresses memory addresses,
LiquiditySources memory sources
) public onlyForked {
if (sources.TraderJoeV2Router == address(0)) {
emit log_string("TraderJoeV2Router not available on this chain");
return;
}
if (sources.TraderJoeV2Pool == address(0)) {
emit log_string("TraderJoeV2Pool not available on this chain");
return;
}
FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell;
fqtData.sellToken = IERC20Token(address(tokens.USDC));
fqtData.buyToken = IERC20Token(address(tokens.USDT));
fqtData.fillSequence = new FillQuoteTransformer.OrderType[](1);
fqtData.fillSequence[0] = FillQuoteTransformer.OrderType.Bridge;
fqtData.fillAmount = 1e6;
(uint256 amountOut, uint256 binStep) = sampleTraderJoeV2(
fqtData.fillAmount,
address(fqtData.sellToken),
address(fqtData.buyToken),
sources.TraderJoeV2Router,
sources.TraderJoeV2Pool
);
log_named_uint("amountOut", amountOut);
IBridgeAdapter.BridgeOrder memory order;
{
address[] memory tokenPath = new address[](2);
tokenPath[0] = address(fqtData.sellToken);
tokenPath[1] = address(fqtData.buyToken);
uint256[] memory binSteps = new uint256[](1);
binSteps[0] = binStep;
order.bridgeData = abi.encode(address(sources.TraderJoeV2Router), tokenPath, binSteps);
}
order.source = bytes32(uint256(BridgeProtocols.TRADERJOEV2) << 128);
order.takerTokenAmount = fqtData.fillAmount;
order.makerTokenAmount = amountOut;
fqtData.bridgeOrders = new IBridgeAdapter.BridgeOrder[](1);
fqtData.bridgeOrders[0] = order;
settleAndLogBalances(fqtData, tokens, addresses);
}
function swapOnKyberElastic( function swapOnKyberElastic(
TokenAddresses memory tokens, TokenAddresses memory tokens,
ContractAddresses memory addresses, ContractAddresses memory addresses,
@ -71,20 +140,6 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
emit log_string("KyberElasticPool not available on this chain"); emit log_string("KyberElasticPool not available on this chain");
return; return;
} }
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](2);
transformations[0].deploymentNonce = _findTransformerNonce(
address(addresses.transformers.wethTransformer),
address(addresses.exchangeProxyTransformerDeployer)
);
emit log_named_uint("WethTransformer nonce", transformations[0].deploymentNonce);
createNewFQT(tokens.WrappedNativeToken, addresses.exchangeProxy, addresses.exchangeProxyTransformerDeployer);
transformations[0].data = abi.encode(LibERC20Transformer.ETH_TOKEN_ADDRESS, 1e18);
transformations[1].deploymentNonce = _findTransformerNonce(
address(fillQuoteTransformer),
address(addresses.exchangeProxyTransformerDeployer)
);
emit log_named_uint("FillQuoteTransformer nonce", transformations[1].deploymentNonce);
FillQuoteTransformer.TransformData memory fqtData; FillQuoteTransformer.TransformData memory fqtData;
fqtData.side = FillQuoteTransformer.Side.Sell; fqtData.side = FillQuoteTransformer.Side.Sell;
@ -111,37 +166,8 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
order.makerTokenAmount = amountOut; order.makerTokenAmount = amountOut;
order.bridgeData = abi.encode(address(sources.KyberElasticRouter), path); order.bridgeData = abi.encode(address(sources.KyberElasticRouter), path);
fqtData.bridgeOrders[0] = order; fqtData.bridgeOrders[0] = order;
transformations[1].data = abi.encode(fqtData);
vm.deal(address(this), 1e18); settleAndLogBalances(fqtData, tokens, addresses);
uint256 balanceETHBefore = address(this).balance;
uint256 balanceERC20Before = IERC20Token(tokens.USDT).balanceOf(address(this));
writeTokenBalance(address(this), address(tokens.USDC), 1e16);
uint256 balanceUSDCbefore = IERC20Token(tokens.USDC).balanceOf(address(this));
IERC20Token(address(tokens.USDC)).approve(addresses.exchangeProxy, 1e16);
IZeroEx(payable(addresses.exchangeProxy)).transformERC20{value: 1e18}(
// input token
IERC20Token(address(tokens.USDC)),
// output token
IERC20Token(address(tokens.USDT)),
// input token amount
1e6,
// min output token amount
order.makerTokenAmount,
// list of transform
transformations
);
log_named_uint("NativeAsset balance before", balanceETHBefore);
log_named_uint("ERC-20 balance before", balanceERC20Before);
log_named_uint("NativeAsset balance after", balanceETHBefore - address(this).balance);
log_named_uint("ERC-20 balance after", IERC20Token(tokens.USDT).balanceOf(address(this)) - balanceERC20Before);
log_named_uint("USDC balance before", balanceUSDCbefore);
log_named_uint("USDC balance after", IERC20Token(tokens.USDT).balanceOf(address(tokens.USDC)));
assert(IERC20Token(tokens.USDT).balanceOf(address(this)) > 0);
} }
function sampleKyberElastic( function sampleKyberElastic(
@ -150,7 +176,7 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
address makerToken, address makerToken,
address quoter, address quoter,
address pool address pool
) public returns (uint256 makerTokenAmount, bytes memory path) { ) private returns (uint256 makerTokenAmount, bytes memory path) {
log_string(" Sampling KyberElastic for tokens"); log_string(" Sampling KyberElastic for tokens");
log_named_address(" ", takerToken); log_named_address(" ", takerToken);
log_string(" -> "); log_string(" -> ");
@ -167,4 +193,64 @@ contract SwapERC20ForERC20Test is Test, ForkUtils, TestUtils {
(uint256 amountOut, , , ) = kyberQuoter.quoteExactInput(path, amount); (uint256 amountOut, , , ) = kyberQuoter.quoteExactInput(path, amount);
return (amountOut, path); return (amountOut, path);
} }
function sampleTraderJoeV2(
uint256 amount,
address takerToken,
address makerToken,
address router,
address pool
) private returns (uint256 makerTokenAmount, uint256 binStep) {
log_string("Sampling TraderJoeV2");
log_named_address("takerToken", takerToken);
log_named_address("makerToken", makerToken);
log_named_address("router", router);
log_named_address("pool", pool);
bool swapForY = ITraderJoeV2Pool(pool).tokenY() == makerToken;
(makerTokenAmount, ) = ITraderJoeV2Router(router).getSwapOut(pool, amount, swapForY);
binStep = ITraderJoeV2Pool(pool).feeParameters().binStep;
}
function deployFQTAndGetDeploymentNonce(
TokenAddresses memory tokens,
ContractAddresses memory addresses
) private returns (uint32) {
createNewFQT(tokens.WrappedNativeToken, addresses.exchangeProxy, addresses.exchangeProxyTransformerDeployer);
return
_findTransformerNonce(address(fillQuoteTransformer), address(addresses.exchangeProxyTransformerDeployer));
}
function settleAndLogBalances(
FillQuoteTransformer.TransformData memory fqtData,
TokenAddresses memory tokens,
ContractAddresses memory addresses
) private {
ITransformERC20Feature.Transformation[] memory transformations = new ITransformERC20Feature.Transformation[](1);
transformations[0].deploymentNonce = deployFQTAndGetDeploymentNonce(tokens, addresses);
transformations[0].data = abi.encode(fqtData);
address sellToken = address(fqtData.sellToken);
address buyToken = address(fqtData.buyToken);
writeTokenBalance(address(this), sellToken, 1e16);
uint256 sellTokenBalanceBefore = IERC20Token(sellToken).balanceOf(address(this));
uint256 buyTokenBalanceBefore = IERC20Token(buyToken).balanceOf(address(this));
IERC20Token(sellToken).approve(addresses.exchangeProxy, 1e16);
IZeroEx(payable(addresses.exchangeProxy)).transformERC20(
IERC20Token(sellToken),
IERC20Token(buyToken),
fqtData.fillAmount,
fqtData.bridgeOrders[0].makerTokenAmount,
transformations
);
log_named_uint("sellToken balance before", sellTokenBalanceBefore);
log_named_uint("sellToken balance after", IERC20Token(sellToken).balanceOf(address(this)));
log_named_uint("buyToken balance before", buyTokenBalanceBefore);
log_named_uint("buyToken balance after", IERC20Token(buyToken).balanceOf(address(this)));
}
} }

View File

@ -88,10 +88,13 @@ struct TokenAddresses {
IEtherToken WrappedNativeToken; IEtherToken WrappedNativeToken;
} }
// keep the names of the struct members in alphabetical order for correct json unparsing
struct LiquiditySources { struct LiquiditySources {
address KyberElasticPool; address KyberElasticPool;
address KyberElasticQuoter; address KyberElasticQuoter;
address KyberElasticRouter; address KyberElasticRouter;
address TraderJoeV2Pool;
address TraderJoeV2Router;
address UniswapV2Router; address UniswapV2Router;
address UniswapV3Router; address UniswapV3Router;
} }
@ -100,6 +103,37 @@ interface IFQT {
function bridgeAdapter() external returns (address); function bridgeAdapter() external returns (address);
} }
interface ITraderJoeV2Pool {
struct FeeParameters {
// 144 lowest bits in slot
uint16 binStep;
uint16 baseFactor;
uint16 filterPeriod;
uint16 decayPeriod;
uint16 reductionFactor;
uint24 variableFeeControl;
uint16 protocolShare;
uint24 maxVolatilityAccumulated;
// 112 highest bits in slot
uint24 volatilityAccumulated;
uint24 volatilityReference;
uint24 indexRef;
uint40 time;
}
function feeParameters() external view returns (FeeParameters memory);
function tokenY() external view returns (address);
}
interface ITraderJoeV2Router {
function getSwapOut(
address pool,
uint256 amountIn,
bool swapForY
) external view returns (uint256 amountOut, uint256 feesIn);
}
interface IKyberElasticQuoter { interface IKyberElasticQuoter {
function quoteExactInput( function quoteExactInput(
bytes memory path, bytes memory path,

View File

@ -1,4 +1,13 @@
[ [
{
"version": "8.5.0",
"changes": [
{
"note": "Add Trader Joe V2 support on Avalanche"
}
],
"timestamp": 1681960738
},
{ {
"version": "8.4.0", "version": "8.4.0",
"changes": [ "changes": [

View File

@ -156,7 +156,7 @@
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c", "wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
"payTakerTransformer": "0xb9a4c32547bc3cdc2ee2fb13cc1a0717dac9888f", "payTakerTransformer": "0xb9a4c32547bc3cdc2ee2fb13cc1a0717dac9888f",
"affiliateFeeTransformer": "0x105679f99d668001370b4621ad8648ac570c860f", "affiliateFeeTransformer": "0x105679f99d668001370b4621ad8648ac570c860f",
"fillQuoteTransformer": "0x7991f2c35ab19472dbfb6f27593f7f6f38fb3eab", "fillQuoteTransformer": "0x540079df6023d39b2686fd9f6c06f1f8f66aca4a",
"positiveSlippageFeeTransformer": "0xadbfdc58a24b6dbc16f21541800f43dd6e282250" "positiveSlippageFeeTransformer": "0xadbfdc58a24b6dbc16f21541800f43dd6e282250"
} }
}, },

View File

@ -1,4 +1,13 @@
[ [
{
"version": "11.21.0",
"changes": [
{
"note": "Add Trader Joe V2 support on Avalanche"
}
],
"timestamp": 1681960738
},
{ {
"version": "11.20.0", "version": "11.20.0",
"changes": [ "changes": [

View File

@ -165,6 +165,7 @@ export enum BridgeProtocol {
AaveV3, AaveV3,
KyberElastic, KyberElastic,
Barter, Barter,
TraderJoeV2,
} }
/** /**