diff --git a/src/dex/camelot/camelot.ts b/src/dex/camelot/camelot.ts index 9ad942f86..8f6b80db3 100644 --- a/src/dex/camelot/camelot.ts +++ b/src/dex/camelot/camelot.ts @@ -646,6 +646,7 @@ export class Camelot isFeeTokenInRoute: Object.values(transferFees).some(f => f !== 0), pools: [ { + stable: pairParam.stable, address: pairParam.exchange, fee: parseInt(pairParam.fee), direction: pairParam.direction, @@ -843,9 +844,17 @@ export class Camelot if (side === SwapSide.BUY) throw new Error('Buy not supported'); let exchangeDataTypes = ['bytes4', 'bytes32']; + const isStable = data.pools.some(pool => !!pool.stable); + const isStablePoolAndPoolCount = isStable + ? BigNumber.from(1) + .shl(255) + .or(BigNumber.from(data.pools.length)) + .toHexString() + : hexZeroPad(hexlify(data.pools.length), 32); + let exchangeDataToPack = [ hexZeroPad(hexlify(0), 4), - hexZeroPad(hexlify(data.pools.length), 32), + isStablePoolAndPoolCount, ]; const pools = encodePools(data.pools, this.feeFactor); diff --git a/src/dex/solidly/solidly.ts b/src/dex/solidly/solidly.ts index 6bd7fd853..369b2b21d 100644 --- a/src/dex/solidly/solidly.ts +++ b/src/dex/solidly/solidly.ts @@ -409,6 +409,7 @@ export class Solidly extends UniswapV2 { isFeeTokenInRoute: Object.values(transferFees).some(f => f !== 0), pools: [ { + stable: pairParam.stable, address: pairParam.exchange, fee: parseInt(pairParam.fee), direction: pairParam.direction, @@ -657,9 +658,17 @@ export class Solidly extends UniswapV2 { if (side === SwapSide.BUY) throw new Error(`Buy not supported`); let exchangeDataTypes = ['bytes4', 'bytes32']; + const isStable = data.pools.some(pool => !!pool.stable); + const isStablePoolAndPoolCount = isStable + ? BigNumber.from(1) + .shl(255) + .or(BigNumber.from(data.pools.length)) + .toHexString() + : hexZeroPad(hexlify(data.pools.length), 32); + let exchangeDataToPack = [ hexZeroPad(hexlify(0), 4), - hexZeroPad(hexlify(data.pools.length), 32), + isStablePoolAndPoolCount, ]; const pools = encodePools(data.pools, this.feeFactor); diff --git a/src/dex/solidly/types.ts b/src/dex/solidly/types.ts index 4db1c4b32..b0895dd5c 100644 --- a/src/dex/solidly/types.ts +++ b/src/dex/solidly/types.ts @@ -19,9 +19,12 @@ export interface SolidlyPoolOrderedParams extends UniswapV2PoolOrderedParams { stable: boolean; } -export type SolidlyData = UniswapV2Data & { isFeeTokenInRoute: boolean }; +export type SolidlyPool = UniswapPool & { stable: boolean }; -export type SolidlyPool = UniswapPool; +export type SolidlyData = { + isFeeTokenInRoute: boolean; + pools: SolidlyPool[]; +} & UniswapV2Data; export interface DexParams extends Omit { feeCode: number; diff --git a/src/executor/Executor02BytecodeBuilder.ts b/src/executor/Executor02BytecodeBuilder.ts index 90cf76be8..120819c4e 100644 --- a/src/executor/Executor02BytecodeBuilder.ts +++ b/src/executor/Executor02BytecodeBuilder.ts @@ -7,7 +7,6 @@ import { } from '@paraswap/core'; import { DexExchangeBuildParam, - DexExchangeParam, DexExchangeParamWithBooleanNeedWrapNative, } from '../types'; import { Executors, Flag, SpecialDex } from './types'; @@ -475,6 +474,7 @@ export class Executor02BytecodeBuilder extends ExecutorBytecodeBuilder< swap: OptimalSwap, swapCallData: string, flag: Flag, + isRoot = false, ) { const data = this.packVerticalBranchingData(swapCallData); @@ -486,16 +486,34 @@ export class Executor02BytecodeBuilder extends ExecutorBytecodeBuilder< let destTokenPos: number; if (isEthDest) { - anyDexOnSwapNeedsWrapNative = this.anyDexOnSwapNeedsWrapNative( - priceRoute, - swap, - exchangeParams, - ); - anyDexOnSwapDoesntNeedWrapNative = this.anyDexOnSwapDoesntNeedWrapNative( - priceRoute, - swap, - exchangeParams, - ); + if (!isRoot) { + anyDexOnSwapNeedsWrapNative = this.anyDexOnSwapNeedsWrapNative( + priceRoute, + swap, + exchangeParams, + ); + anyDexOnSwapDoesntNeedWrapNative = + this.anyDexOnSwapDoesntNeedWrapNative( + priceRoute, + swap, + exchangeParams, + ); + } else { + anyDexOnSwapNeedsWrapNative = priceRoute.bestRoute.some(route => + this.anyDexOnSwapNeedsWrapNative( + priceRoute, + route.swaps[route.swaps.length - 1], + exchangeParams, + ), + ); + anyDexOnSwapDoesntNeedWrapNative = priceRoute.bestRoute.some(route => + this.anyDexOnSwapDoesntNeedWrapNative( + priceRoute, + route.swaps[route.swaps.length - 1], + exchangeParams, + ), + ); + } } if ( @@ -1313,6 +1331,7 @@ export class Executor02BytecodeBuilder extends ExecutorBytecodeBuilder< needWrapEth ? Flag.DONT_INSERT_FROM_AMOUNT_DONT_CHECK_BALANCE_AFTER_SWAP // 0 : Flag.DONT_INSERT_FROM_AMOUNT_CHECK_SRC_TOKEN_BALANCE_AFTER_SWAP, // 8 + true, // isRoot branch ); } diff --git a/src/executor/executor02-bytecode-builder-e2e.test.ts b/src/executor/executor02-bytecode-builder-e2e.test.ts index 514fc60e2..04b47edf7 100644 --- a/src/executor/executor02-bytecode-builder-e2e.test.ts +++ b/src/executor/executor02-bytecode-builder-e2e.test.ts @@ -1497,6 +1497,36 @@ describe('Executor02ByteCodeBuilder e2e tests', () => { ); }); }); + + describe('USDCe -> MATIC', () => { + const dexKeys = ['CurveV2', 'UniswapV3', 'SushiSwapV3', 'SwaapV2']; + + const tokenASymbol: string = 'USDCe'; + const tokenBSymbol: string = 'MATIC'; + const tokenAAmount: string = '1978798814'; + + const side = SwapSide.SELL; + + it(`${tokenASymbol} -> ${tokenBSymbol}`, async () => { + await testE2E( + tokens[tokenASymbol], + tokens[tokenBSymbol], + holders[tokenASymbol], + tokenAAmount, + side, + dexKeys, + contractMethod, + network, + provider, + undefined, + undefined, + undefined, + 100, + 2000, + false, + ); + }); + }); }); });