From c717aa37d63ccabb5f553e159ea5cab199d71d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Larsen=20Cundri=C4=8D?= Date: Tue, 23 Jul 2024 18:26:00 +0200 Subject: [PATCH 1/2] Add support for Trader Joe V2.2 --- src/abi/TraderJoeV22Router.json | 1502 +++++++++++++++++ src/dex/index.ts | 2 + src/dex/trader-joe-v2.2/config.ts | 7 + .../trader-joe-v2.2-e2e.test.ts | 101 ++ src/dex/trader-joe-v2.2/trader-joe-v2.2.ts | 180 ++ src/dex/trader-joe-v2.2/types.ts | 38 + 6 files changed, 1830 insertions(+) create mode 100644 src/abi/TraderJoeV22Router.json create mode 100644 src/dex/trader-joe-v2.2/config.ts create mode 100644 src/dex/trader-joe-v2.2/trader-joe-v2.2-e2e.test.ts create mode 100644 src/dex/trader-joe-v2.2/trader-joe-v2.2.ts create mode 100644 src/dex/trader-joe-v2.2/types.ts diff --git a/src/abi/TraderJoeV22Router.json b/src/abi/TraderJoeV22Router.json new file mode 100644 index 000000000..4b7fa174a --- /dev/null +++ b/src/abi/TraderJoeV22Router.json @@ -0,0 +1,1502 @@ +[ + { + "inputs": [ + { + "internalType": "contract ILBFactory", + "name": "factory2_2", + "type": "address" + }, + { + "internalType": "contract IJoeFactory", + "name": "factoryV1", + "type": "address" + }, + { + "internalType": "contract ILBLegacyFactory", + "name": "legacyFactory", + "type": "address" + }, + { + "internalType": "contract ILBLegacyRouter", + "name": "legacyRouter", + "type": "address" + }, + { + "internalType": "contract ILBFactory", + "name": "factory2_1", + "type": "address" + }, + { + "internalType": "contract IWNATIVE", + "name": "wnative", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "JoeLibrary__InsufficientAmount", + "type": "error" + }, + { + "inputs": [], + "name": "JoeLibrary__InsufficientLiquidity", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountSlippage", + "type": "uint256" + } + ], + "name": "LBRouter__AmountSlippageBPTooBig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountXMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountX", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountY", + "type": "uint256" + } + ], + "name": "LBRouter__AmountSlippageCaught", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "LBRouter__BinReserveOverflows", + "type": "error" + }, + { + "inputs": [], + "name": "LBRouter__BrokenSwapSafetyCheck", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentTimestamp", + "type": "uint256" + } + ], + "name": "LBRouter__DeadlineExceeded", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "recipient", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "LBRouter__FailedToSendNATIVE", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "idDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "idSlippage", + "type": "uint256" + } + ], + "name": "LBRouter__IdDesiredOverflows", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "int256", + "name": "id", + "type": "int256" + } + ], + "name": "LBRouter__IdOverflows", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "activeIdDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "idSlippage", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activeId", + "type": "uint256" + } + ], + "name": "LBRouter__IdSlippageCaught", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "name": "LBRouter__InsufficientAmountOut", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "wrongToken", + "type": "address" + } + ], + "name": "LBRouter__InvalidTokenPath", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "version", + "type": "uint256" + } + ], + "name": "LBRouter__InvalidVersion", + "type": "error" + }, + { + "inputs": [], + "name": "LBRouter__LengthsMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + } + ], + "name": "LBRouter__MaxAmountInExceeded", + "type": "error" + }, + { + "inputs": [], + "name": "LBRouter__NotFactoryOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenX", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenY", + "type": "address" + }, + { + "internalType": "uint256", + "name": "binStep", + "type": "uint256" + } + ], + "name": "LBRouter__PairNotCreated", + "type": "error" + }, + { + "inputs": [], + "name": "LBRouter__SenderIsNotWNATIVE", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "LBRouter__SwapOverflows", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "excess", + "type": "uint256" + } + ], + "name": "LBRouter__TooMuchTokensIn", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reserve", + "type": "uint256" + } + ], + "name": "LBRouter__WrongAmounts", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "tokenX", + "type": "address" + }, + { + "internalType": "address", + "name": "tokenY", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amountX", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountY", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "msgValue", + "type": "uint256" + } + ], + "name": "LBRouter__WrongNativeLiquidityParameters", + "type": "error" + }, + { + "inputs": [], + "name": "LBRouter__WrongTokenOrder", + "type": "error" + }, + { + "inputs": [], + "name": "PackedUint128Math__SubUnderflow", + "type": "error" + }, + { + "inputs": [], + "name": "TokenHelper__TransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenX", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenY", + "type": "address" + }, + { + "internalType": "uint256", + "name": "binStep", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountX", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountY", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountXMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activeIdDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "idSlippage", + "type": "uint256" + }, + { + "internalType": "int256[]", + "name": "deltaIds", + "type": "int256[]" + }, + { + "internalType": "uint256[]", + "name": "distributionX", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "distributionY", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "address", + "name": "refundTo", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ILBRouter.LiquidityParameters", + "name": "liquidityParameters", + "type": "tuple" + } + ], + "name": "addLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountXAdded", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYAdded", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountXLeft", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYLeft", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "depositIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "liquidityMinted", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "contract IERC20", + "name": "tokenX", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenY", + "type": "address" + }, + { + "internalType": "uint256", + "name": "binStep", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountX", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountY", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountXMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "activeIdDesired", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "idSlippage", + "type": "uint256" + }, + { + "internalType": "int256[]", + "name": "deltaIds", + "type": "int256[]" + }, + { + "internalType": "uint256[]", + "name": "distributionX", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "distributionY", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "address", + "name": "refundTo", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "internalType": "struct ILBRouter.LiquidityParameters", + "name": "liquidityParameters", + "type": "tuple" + } + ], + "name": "addLiquidityNATIVE", + "outputs": [ + { + "internalType": "uint256", + "name": "amountXAdded", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYAdded", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountXLeft", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYLeft", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "depositIds", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "liquidityMinted", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenX", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenY", + "type": "address" + }, + { + "internalType": "uint24", + "name": "activeId", + "type": "uint24" + }, + { + "internalType": "uint16", + "name": "binStep", + "type": "uint16" + } + ], + "name": "createLBPair", + "outputs": [ + { + "internalType": "contract ILBPair", + "name": "pair", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getFactory", + "outputs": [ + { + "internalType": "contract ILBFactory", + "name": "lbFactory", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getFactoryV2_1", + "outputs": [ + { + "internalType": "contract ILBFactory", + "name": "lbFactory", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ILBPair", + "name": "pair", + "type": "address" + }, + { + "internalType": "uint256", + "name": "price", + "type": "uint256" + } + ], + "name": "getIdFromPrice", + "outputs": [ + { + "internalType": "uint24", + "name": "", + "type": "uint24" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLegacyFactory", + "outputs": [ + { + "internalType": "contract ILBLegacyFactory", + "name": "legacyLBfactory", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getLegacyRouter", + "outputs": [ + { + "internalType": "contract ILBLegacyRouter", + "name": "legacyRouter", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ILBPair", + "name": "pair", + "type": "address" + }, + { + "internalType": "uint24", + "name": "id", + "type": "uint24" + } + ], + "name": "getPriceFromId", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ILBPair", + "name": "pair", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amountOut", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "swapForY", + "type": "bool" + } + ], + "name": "getSwapIn", + "outputs": [ + { + "internalType": "uint128", + "name": "amountIn", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amountOutLeft", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "fee", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ILBPair", + "name": "pair", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amountIn", + "type": "uint128" + }, + { + "internalType": "bool", + "name": "swapForY", + "type": "bool" + } + ], + "name": "getSwapOut", + "outputs": [ + { + "internalType": "uint128", + "name": "amountInLeft", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "amountOut", + "type": "uint128" + }, + { + "internalType": "uint128", + "name": "fee", + "type": "uint128" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getV1Factory", + "outputs": [ + { + "internalType": "contract IJoeFactory", + "name": "factoryV1", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getWNATIVE", + "outputs": [ + { + "internalType": "contract IWNATIVE", + "name": "wnative", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "tokenX", + "type": "address" + }, + { + "internalType": "contract IERC20", + "name": "tokenY", + "type": "address" + }, + { + "internalType": "uint16", + "name": "binStep", + "type": "uint16" + }, + { + "internalType": "uint256", + "name": "amountXMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountYMin", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidity", + "outputs": [ + { + "internalType": "uint256", + "name": "amountX", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountY", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "uint16", + "name": "binStep", + "type": "uint16" + }, + { + "internalType": "uint256", + "name": "amountTokenMin", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountNATIVEMin", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "removeLiquidityNATIVE", + "outputs": [ + { + "internalType": "uint256", + "name": "amountToken", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountNATIVE", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactNATIVEForTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactNATIVEForTokensSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinNATIVE", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForNATIVE", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMinNATIVE", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForNATIVESupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountIn", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountOutMin", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapExactTokensForTokensSupportingFeeOnTransferTokens", + "outputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapNATIVEForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountNATIVEOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address payable", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactNATIVE", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amountOut", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountInMax", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "uint256[]", + "name": "pairBinSteps", + "type": "uint256[]" + }, + { + "internalType": "enum ILBRouter.Version[]", + "name": "versions", + "type": "uint8[]" + }, + { + "internalType": "contract IERC20[]", + "name": "tokenPath", + "type": "address[]" + } + ], + "internalType": "struct ILBRouter.Path", + "name": "path", + "type": "tuple" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "swapTokensForExactTokens", + "outputs": [ + { + "internalType": "uint256[]", + "name": "amountsIn", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC20", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "sweep", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract ILBToken", + "name": "lbToken", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + } + ], + "name": "sweepLBToken", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/src/dex/index.ts b/src/dex/index.ts index f623e50e6..70076798c 100644 --- a/src/dex/index.ts +++ b/src/dex/index.ts @@ -67,6 +67,7 @@ import { QuickSwapV3 } from './quickswap/quickswap-v3'; import { ThenaFusion } from './quickswap/thena-fusion'; import { SwaapV2 } from './swaap-v2/swaap-v2'; import { TraderJoeV21 } from './trader-joe-v2.1/trader-joe-v2.1'; +import { TraderJoeV22 } from './trader-joe-v2.2/trader-joe-v2.2'; import { PancakeswapV3 } from './pancakeswap-v3/pancakeswap-v3'; import { Algebra } from './algebra/algebra'; import { AngleTransmuter } from './angle-transmuter/angle-transmuter'; @@ -93,6 +94,7 @@ const LegacyDexes = [ QuickSwapV3, ThenaFusion, TraderJoeV21, + TraderJoeV22, Lido, AugustusRFQOrder, EtherFi, diff --git a/src/dex/trader-joe-v2.2/config.ts b/src/dex/trader-joe-v2.2/config.ts new file mode 100644 index 000000000..03ed23594 --- /dev/null +++ b/src/dex/trader-joe-v2.2/config.ts @@ -0,0 +1,7 @@ +import { Address } from '@paraswap/core'; +import { Network } from '../../constants'; + +export const TRADERJOE_V2_2_ROUTER_ADDRESS: { [network: number]: Address } = { + [Network.AVALANCHE]: '0x18556DA13313f3532c54711497A8FedAC273220E', + [Network.ARBITRUM]: '0x18556DA13313f3532c54711497A8FedAC273220E', +}; diff --git a/src/dex/trader-joe-v2.2/trader-joe-v2.2-e2e.test.ts b/src/dex/trader-joe-v2.2/trader-joe-v2.2-e2e.test.ts new file mode 100644 index 000000000..3a369a928 --- /dev/null +++ b/src/dex/trader-joe-v2.2/trader-joe-v2.2-e2e.test.ts @@ -0,0 +1,101 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +import { testE2E } from '../../../tests/utils-e2e'; +import { + Tokens, + Holders, + NativeTokenSymbols, +} from '../../../tests/constants-e2e'; + +import { ContractMethod, Network, SwapSide } from '../../constants'; +import { StaticJsonRpcProvider } from '@ethersproject/providers'; +import { generateConfig } from '../../config'; + +const dexKey = 'traderjoev2.2'; + +const testForNetwork = ( + network: Network, + swapMap: Map, +) => { + const tokens = Tokens[network]; + const holders = Holders[network]; + + const nativeSymbol = NativeTokenSymbols[network]; + + const provider = new StaticJsonRpcProvider( + generateConfig(network).privateHttpProvider, + network, + ); + + const tokensToTest = [ + [ + { + symbol: 'USDC', + amount: (10 ** 8).toString(), + }, + { + symbol: 'USDT', + amount: (10 ** 8).toString(), + }, + ], + [ + { + symbol: 'USDT', + amount: (10 ** 8).toString(), + }, + { + symbol: 'DAI', + amount: (10 ** 8).toString(), + }, + ], + ]; + + swapMap.forEach((contractMethods, side) => + contractMethods.forEach((contractMethod: string) => { + tokensToTest.forEach(pair => { + describe(`${contractMethod}`, () => { + it(`${pair[0].symbol} -> ${pair[1].symbol}`, async () => { + await testE2E( + tokens[pair[0].symbol], + tokens[pair[1].symbol], + holders[pair[0].symbol], + side === SwapSide.SELL ? pair[0].amount : pair[1].amount, + side, + dexKey, + contractMethod as any, + network, + provider, + ); + }); + + it(`${nativeSymbol} -> ${pair[0].symbol}`, async () => { + await testE2E( + tokens[nativeSymbol], + tokens[pair[0].symbol], + holders[nativeSymbol], + side === SwapSide.SELL ? '1000000000000000000' : pair[0].amount, + side, + dexKey, + contractMethod as any, + network, + provider, + ); + }); + }); + }); + }), + ); +}; + +// Ensure you have the E2E_ENDPOINT_URL env variable set. + +describe('TraderJoe v2.2 E2E', () => { + describe('Mainnet V6', () => { + const swapMap = new Map([ + [SwapSide.SELL, [ContractMethod.swapExactAmountIn]], + ]); + + testForNetwork(Network.MAINNET, swapMap); + }); +}); diff --git a/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts b/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts new file mode 100644 index 000000000..54c2927fa --- /dev/null +++ b/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts @@ -0,0 +1,180 @@ +import { SwapSide } from '../../constants'; +import { + AdapterExchangeParam, + Address, + DexExchangeParam, + SimpleExchangeParam, +} from '../../types'; +import { IDexTxBuilder } from '../idex'; +import { IDexHelper } from '../../dex-helper'; +import { + getLocalDeadlineAsFriendlyPlaceholder, + SimpleExchange, +} from '../simple-exchange'; +import { NumberAsString } from '@paraswap/core'; +import { AsyncOrSync } from 'ts-essentials'; +import { Interface, JsonFragment } from '@ethersproject/abi'; +import TraderJoeV22RouterABI from '../../abi/TraderJoeV21Router.json'; +import { + TraderJoeV2Data, + TraderJoeV2RouterFunctions, + TraderJoeV2RouterParam, +} from './types'; +import { TRADERJOE_V2_2_ROUTER_ADDRESS } from './config'; +import { extractReturnAmountPosition } from '../../executor/utils'; + +export class TraderJoeV22 + extends SimpleExchange + implements IDexTxBuilder +{ + static dexKeys = ['traderjoev2.2']; + protected routerAddress: string; + exchangeRouterInterface: Interface; + needWrapNative = true; + + constructor(dexHelper: IDexHelper) { + super(dexHelper, 'traderjoev2.2'); + + this.routerAddress = + TRADERJOE_V2_2_ROUTER_ADDRESS[dexHelper.config.data.network]; + + this.exchangeRouterInterface = new Interface( + TraderJoeV22RouterABI as JsonFragment[], + ); + } + + getAdapterParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + data: TraderJoeV2Data, + side: SwapSide, + ): AdapterExchangeParam { + let payload = this.abiCoder.encodeParameters( + ['tuple(tuple(uint256[],uint8[],address[]),uint256)'], + [ + [ + [ + [ + data.binStep, // _pairBinSteps: uint256[] + ], + [ + 2, // _versions: uint8[] + ], + [ + data.tokenIn, + data.tokenOut, // _tokenPath: address[] + ], + ], + getLocalDeadlineAsFriendlyPlaceholder(), // _deadline: uint256 + ], + ], + ); + + return { + targetExchange: this.routerAddress, + payload, + networkFee: '0', + }; + } + + getSimpleParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + data: TraderJoeV2Data, + side: SwapSide, + ): AsyncOrSync { + const swapFunction = + side === SwapSide.SELL + ? TraderJoeV2RouterFunctions.swapExactTokensForTokens + : TraderJoeV2RouterFunctions.swapTokensForExactTokens; + + const swapFunctionParams: TraderJoeV2RouterParam = + side === SwapSide.SELL + ? [ + srcAmount, + destAmount, + [[data.binStep], ['2'], [srcToken, destToken]], + this.augustusAddress, + getLocalDeadlineAsFriendlyPlaceholder(), + ] + : [ + destAmount, + srcAmount, + [[data.binStep], ['2'], [srcToken, destToken]], + this.augustusAddress, + getLocalDeadlineAsFriendlyPlaceholder(), + ]; + + const swapData = this.exchangeRouterInterface.encodeFunctionData( + swapFunction, + swapFunctionParams, + ); + + return this.buildSimpleParamWithoutWETHConversion( + srcToken, + srcAmount, + destToken, + destAmount, + swapData, + this.routerAddress, + ); + } + + getDexParam( + srcToken: Address, + destToken: Address, + srcAmount: NumberAsString, + destAmount: NumberAsString, + recipient: Address, + data: TraderJoeV2Data, + side: SwapSide, + ): DexExchangeParam { + const swapFunction = + side === SwapSide.SELL + ? TraderJoeV2RouterFunctions.swapExactTokensForTokens + : TraderJoeV2RouterFunctions.swapTokensForExactTokens; + + const placeholder = getLocalDeadlineAsFriendlyPlaceholder(); + + const swapFunctionParams: TraderJoeV2RouterParam = + side === SwapSide.SELL + ? [ + srcAmount, + destAmount, + [[data.binStep], ['2'], [srcToken, destToken]], + recipient, + placeholder, + ] + : [ + destAmount, + srcAmount, + [[data.binStep], ['2'], [srcToken, destToken]], + recipient, + placeholder, + ]; + + const swapData = this.exchangeRouterInterface.encodeFunctionData( + swapFunction, + swapFunctionParams, + ); + + return { + needWrapNative: this.needWrapNative, + dexFuncHasRecipient: true, + exchangeData: swapData, + targetExchange: this.routerAddress, + returnAmountPos: + side === SwapSide.SELL + ? extractReturnAmountPosition( + this.exchangeRouterInterface, + swapFunction, + 'amountOut', + ) + : undefined, + }; + } +} diff --git a/src/dex/trader-joe-v2.2/types.ts b/src/dex/trader-joe-v2.2/types.ts new file mode 100644 index 000000000..3a450d627 --- /dev/null +++ b/src/dex/trader-joe-v2.2/types.ts @@ -0,0 +1,38 @@ +import { NumberAsString } from '@paraswap/core'; +import { Address } from '@paraswap/sdk'; + +export type RouterPath = [ + pairBinSteps: NumberAsString[], + versions: NumberAsString[], + tokenPath: Address[], +]; +export type TraderJoeV2RouterSellParams = [ + _amountIn: NumberAsString, + _amountOutMin: NumberAsString, + _routerPath: RouterPath, + to: Address, + _deadline: string, +]; + +export type TraderJoeV2RouterBuyParams = [ + _amountOut: NumberAsString, + _amountInMax: NumberAsString, + _routerPath: RouterPath, + to: Address, + _deadline: string, +]; + +export type TraderJoeV2RouterParam = + | TraderJoeV2RouterSellParams + | TraderJoeV2RouterBuyParams; + +export type TraderJoeV2Data = { + tokenIn: string; // redundant + tokenOut: string; // redundant + binStep: string; +}; + +export enum TraderJoeV2RouterFunctions { + swapExactTokensForTokens = 'swapExactTokensForTokens', + swapTokensForExactTokens = 'swapTokensForExactTokens', +} From b8e9f163e97dfbbd0ceaa88304ac3fce88227cce Mon Sep 17 00:00:00 2001 From: defishrew Date: Thu, 25 Jul 2024 10:31:01 +0200 Subject: [PATCH 2/2] set _versions to 3 --- src/dex/trader-joe-v2.2/trader-joe-v2.2.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts b/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts index 54c2927fa..a6d5f0840 100644 --- a/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts +++ b/src/dex/trader-joe-v2.2/trader-joe-v2.2.ts @@ -60,7 +60,7 @@ export class TraderJoeV22 data.binStep, // _pairBinSteps: uint256[] ], [ - 2, // _versions: uint8[] + 3, // _versions: uint8[] ], [ data.tokenIn, @@ -97,14 +97,14 @@ export class TraderJoeV22 ? [ srcAmount, destAmount, - [[data.binStep], ['2'], [srcToken, destToken]], + [[data.binStep], ['3'], [srcToken, destToken]], this.augustusAddress, getLocalDeadlineAsFriendlyPlaceholder(), ] : [ destAmount, srcAmount, - [[data.binStep], ['2'], [srcToken, destToken]], + [[data.binStep], ['3'], [srcToken, destToken]], this.augustusAddress, getLocalDeadlineAsFriendlyPlaceholder(), ]; @@ -145,14 +145,14 @@ export class TraderJoeV22 ? [ srcAmount, destAmount, - [[data.binStep], ['2'], [srcToken, destToken]], + [[data.binStep], ['3'], [srcToken, destToken]], recipient, placeholder, ] : [ destAmount, srcAmount, - [[data.binStep], ['2'], [srcToken, destToken]], + [[data.binStep], ['3'], [srcToken, destToken]], recipient, placeholder, ];