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:
parent
ff104e7505
commit
b483805a22
@ -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": [
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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": [
|
||||||
|
@ -156,7 +156,7 @@
|
|||||||
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
|
"wethTransformer": "0x9b8b52391071d71cd4ad1e61d7f273268fa34c6c",
|
||||||
"payTakerTransformer": "0xb9a4c32547bc3cdc2ee2fb13cc1a0717dac9888f",
|
"payTakerTransformer": "0xb9a4c32547bc3cdc2ee2fb13cc1a0717dac9888f",
|
||||||
"affiliateFeeTransformer": "0x105679f99d668001370b4621ad8648ac570c860f",
|
"affiliateFeeTransformer": "0x105679f99d668001370b4621ad8648ac570c860f",
|
||||||
"fillQuoteTransformer": "0x7991f2c35ab19472dbfb6f27593f7f6f38fb3eab",
|
"fillQuoteTransformer": "0x540079df6023d39b2686fd9f6c06f1f8f66aca4a",
|
||||||
"positiveSlippageFeeTransformer": "0xadbfdc58a24b6dbc16f21541800f43dd6e282250"
|
"positiveSlippageFeeTransformer": "0xadbfdc58a24b6dbc16f21541800f43dd6e282250"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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": [
|
||||||
|
@ -165,6 +165,7 @@ export enum BridgeProtocol {
|
|||||||
AaveV3,
|
AaveV3,
|
||||||
KyberElastic,
|
KyberElastic,
|
||||||
Barter,
|
Barter,
|
||||||
|
TraderJoeV2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user