From cdc3a78eb91a5f6d2d2b7ad547f84c59a3714754 Mon Sep 17 00:00:00 2001 From: lomonoshka Date: Mon, 30 Oct 2023 19:54:47 +0400 Subject: [PATCH] Change final transfer location. Add wrap/unwrap functionality --- package-lock.json | 18 +- package.json | 4 +- src/Unit/Exchange/callGenerators/curve.ts | 52 ++-- src/Unit/Exchange/callGenerators/uniswapV2.ts | 4 +- src/Unit/Exchange/callGenerators/uniswapV3.ts | 8 +- src/Unit/Exchange/callGenerators/weth.ts | 32 ++ src/Unit/Exchange/generateSwapCalldata.ts | 273 +++++++++--------- 7 files changed, 213 insertions(+), 178 deletions(-) create mode 100644 src/Unit/Exchange/callGenerators/weth.ts diff --git a/package-lock.json b/package-lock.json index b77e8ec..9e5ad1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.10", + "version": "0.20.10-rc101", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@orionprotocol/sdk", - "version": "0.20.10", + "version": "0.20.10-rc101", "hasInstallScript": true, "license": "ISC", "dependencies": { "@babel/runtime": "^7.21.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@orionprotocol/contracts": "1.19.5", + "@orionprotocol/contracts": "1.22.1", "bignumber.js": "^9.1.1", "bson-objectid": "^2.0.4", "buffer": "^6.0.3", @@ -2419,9 +2419,9 @@ } }, "node_modules/@orionprotocol/contracts": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.19.5.tgz", - "integrity": "sha512-z8oWz+BswG+kN2dZCgjmQJwNc52S3aAnchZX0JRMe8+l/4WHIYDJQ3W9pEClzvg/86LO41DAHmS73rHNrGAARw==" + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.1.tgz", + "integrity": "sha512-DrIyAmZ+LK3Eflv/gk6Uq3shpTLjeG4wV6PoKVxJKoqk05qL35cJs5V/2it16s5NolcQliFrtJ54G3xI78gTwA==" }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -13460,9 +13460,9 @@ } }, "@orionprotocol/contracts": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.19.5.tgz", - "integrity": "sha512-z8oWz+BswG+kN2dZCgjmQJwNc52S3aAnchZX0JRMe8+l/4WHIYDJQ3W9pEClzvg/86LO41DAHmS73rHNrGAARw==" + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.1.tgz", + "integrity": "sha512-DrIyAmZ+LK3Eflv/gk6Uq3shpTLjeG4wV6PoKVxJKoqk05qL35cJs5V/2it16s5NolcQliFrtJ54G3xI78gTwA==" }, "@sinclair/typebox": { "version": "0.27.8", diff --git a/package.json b/package.json index 8da21a6..18ea5e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.10-rc101", + "version": "0.20.10-rc102", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", @@ -88,7 +88,7 @@ "@babel/runtime": "^7.21.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@orionprotocol/contracts": "1.19.5", + "@orionprotocol/contracts": "1.22.1", "bignumber.js": "^9.1.1", "bson-objectid": "^2.0.4", "buffer": "^6.0.3", diff --git a/src/Unit/Exchange/callGenerators/curve.ts b/src/Unit/Exchange/callGenerators/curve.ts index 7fc54d3..eb9d29e 100644 --- a/src/Unit/Exchange/callGenerators/curve.ts +++ b/src/Unit/Exchange/callGenerators/curve.ts @@ -1,28 +1,44 @@ -import { SwapExecutor__factory, CurveRegistry__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js" -import type { BigNumberish, JsonRpcProvider } from "ethers" -import { addCallParams } from "./utils.js" -import type { SingleSwap } from "../../../types.js" +import { + SwapExecutor__factory, + CurveRegistry__factory, + ERC20__factory, +} from "@orionprotocol/contracts/lib/ethers-v6/index.js"; +import { MaxUint256, type BigNumberish, type JsonRpcProvider } from "ethers"; +import { addCallParams } from "./utils.js"; +import type { SingleSwap } from "../../../types.js"; +import { generateApproveCall } from "./erc20.js"; +import type { BytesLike } from "ethers"; export async function generateCurveStableSwapCall( amount: BigNumberish, to: string, swap: SingleSwap, provider: JsonRpcProvider, + swapExecutorContractAddress: string, curveRegistry: string ) { - const executorInterface = SwapExecutor__factory.createInterface() - const registry = CurveRegistry__factory.connect(curveRegistry, provider) - const { pool, assetIn, assetOut } = swap - const [i, j,] = await registry.get_coin_indices(pool, assetIn, assetOut) + const executorInterface = SwapExecutor__factory.createInterface(); + const registry = CurveRegistry__factory.connect(curveRegistry, provider); + const { pool, assetIn, assetOut } = swap; + const firstToken = ERC20__factory.connect(assetIn, provider) + const executorAllowance = await firstToken.allowance(swapExecutorContractAddress, pool) - let calldata = executorInterface.encodeFunctionData('curveSwapStableAmountIn', [ - pool, - assetOut, - i, - j, - to, - amount, - ]) + const calls: BytesLike[] = [] + if (executorAllowance <= BigInt(amount)) { + const approveCall = await generateApproveCall( + assetIn, + pool, + MaxUint256 + ); + calls.push(approveCall); + } - return addCallParams(calldata) -} \ No newline at end of file + const [i, j] = await registry.get_coin_indices(pool, assetIn, assetOut); + let calldata = executorInterface.encodeFunctionData( + "curveSwapStableAmountIn", + [pool, assetOut, i, j, to, amount] + ); + calls.push(addCallParams(calldata)) + + return calls +} diff --git a/src/Unit/Exchange/callGenerators/uniswapV2.ts b/src/Unit/Exchange/callGenerators/uniswapV2.ts index 6d34820..19b86b0 100644 --- a/src/Unit/Exchange/callGenerators/uniswapV2.ts +++ b/src/Unit/Exchange/callGenerators/uniswapV2.ts @@ -1,7 +1,7 @@ import { SwapExecutor__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js" import { SafeArray } from "../../../utils/safeGetters.js" import { type BytesLike, type BigNumberish, concat, ethers, toBeHex } from "ethers" -import { addCallParams, generateCalls } from "./utils.js" +import { addCallParams } from "./utils.js" import type { SingleSwap } from "../../../types.js" export async function generateUni2Calls( @@ -33,7 +33,7 @@ export async function generateUni2Calls( ]) calls.push(addCallParams(calldata)) - return generateCalls(calls) + return calls } export async function generateUni2Call( diff --git a/src/Unit/Exchange/callGenerators/uniswapV3.ts b/src/Unit/Exchange/callGenerators/uniswapV3.ts index 2ef3f04..67bfcec 100644 --- a/src/Unit/Exchange/callGenerators/uniswapV3.ts +++ b/src/Unit/Exchange/callGenerators/uniswapV3.ts @@ -1,7 +1,7 @@ import { SwapExecutor__factory, UniswapV3Pool__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js" -import { type BigNumberish , type BytesLike, ethers, JsonRpcProvider } from "ethers" +import { type BigNumberish , ethers, JsonRpcProvider } from "ethers" import { SafeArray } from "../../../utils/safeGetters.js" -import { addCallParams, generateCalls } from "./utils.js" +import { addCallParams } from "./utils.js" import type { SingleSwap } from "../../../types.js" export async function generateUni3Call( @@ -49,7 +49,7 @@ export async function generateUni3Calls( let calldata = executorInterface.encodeFunctionData('uniswapV3SwapTo', [encodedPools, recipient, amount]) calldata = addCallParams(calldata) - return generateCalls([calldata]) + return [calldata] } export async function generateOrion3Calls( @@ -67,7 +67,7 @@ export async function generateOrion3Calls( let calldata = executorInterface.encodeFunctionData('orionV3SwapTo', [encodedPools, recipient, amount]) calldata = addCallParams(calldata) - return generateCalls([calldata]) + return [calldata] } export async function encodePoolV3( diff --git a/src/Unit/Exchange/callGenerators/weth.ts b/src/Unit/Exchange/callGenerators/weth.ts new file mode 100644 index 0000000..7aaf566 --- /dev/null +++ b/src/Unit/Exchange/callGenerators/weth.ts @@ -0,0 +1,32 @@ +import { SwapExecutor__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js" +import type { BigNumberish } from "ethers" +import { type CallParams, addCallParams } from "./utils.js" +import type { AddressLike } from "ethers" + +export function generateWrapAndTransferCall( + target: AddressLike, + callParams?: CallParams +) { + + const executorInterface = SwapExecutor__factory.createInterface() + const calldata = executorInterface.encodeFunctionData('wrapAndTransfer', [ + target, + ]) + + return addCallParams(calldata, callParams) +} + +export function generateUnwrapAndTransferCall( + target: AddressLike, + amount: BigNumberish, + callParams?: CallParams +) { + + const executorInterface = SwapExecutor__factory.createInterface() + const calldata = executorInterface.encodeFunctionData('unwrapAndTransfer', [ + target, + amount + ]) + + return addCallParams(calldata, callParams) +} \ No newline at end of file diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index c28c02f..cef0f02 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -1,61 +1,65 @@ -import type { LibValidator } from '@orionprotocol/contracts/lib/ethers-v6/Exchange.js'; +import type { LibValidator } from "@orionprotocol/contracts/lib/ethers-v6/Exchange.js"; +import { ethers, type BigNumberish, type BytesLike, JsonRpcProvider, ZeroAddress } from "ethers"; +import { safeGet, SafeArray } from "../../utils/safeGetters.js"; +import { simpleFetch } from "simple-typed-fetch"; +import type Unit from "../index.js"; +import { generateUni2Calls, generateUni2Call } from "./callGenerators/uniswapV2.js"; import { - ERC20__factory -} from '@orionprotocol/contracts/lib/ethers-v6/index.js'; -import { ethers, type BigNumberish, type BytesLike, JsonRpcProvider } from 'ethers'; -import { safeGet, SafeArray } from '../../utils/safeGetters.js'; -import { simpleFetch } from 'simple-typed-fetch'; -import type Unit from '../index.js'; -import { generateUni2Calls, generateUni2Call } from './callGenerators/uniswapV2.js'; -import { generateUni3Calls, generateOrion3Calls, generateUni3Call, generateOrion3Call } from './callGenerators/uniswapV3.js'; -import { exchangeToNativeDecimals, generateCalls, pathCallWithBalance } from './callGenerators/utils.js'; -import { generateApproveCall, generateTransferCall } from './callGenerators/erc20.js'; -import { generateCurveStableSwapCall } from './callGenerators/curve.js'; -import type { SingleSwap } from '../../types.js'; -import type { AddressLike } from 'ethers'; -import { addressLikeToString } from '../../utils/addressLikeToString.js'; + generateUni3Calls, + generateOrion3Calls, + generateUni3Call, + generateOrion3Call, +} from "./callGenerators/uniswapV3.js"; +import { exchangeToNativeDecimals, generateCalls, pathCallWithBalance } from "./callGenerators/utils.js"; +import { generateTransferCall } from "./callGenerators/erc20.js"; +import { generateCurveStableSwapCall } from "./callGenerators/curve.js"; +import type { SingleSwap } from "../../types.js"; +import type { AddressLike } from "ethers"; +import { addressLikeToString } from "../../utils/addressLikeToString.js"; +import { generateUnwrapAndTransferCall, generateWrapAndTransferCall } from "./callGenerators/weth.js"; -export type Factory = "UniswapV2" | "UniswapV3" | "Curve" | "OrionV2" | "OrionV3" +export type Factory = "UniswapV2" | "UniswapV3" | "Curve" | "OrionV2" | "OrionV3"; export type GenerateSwapCalldataWithUnitParams = { - amount: BigNumberish - minReturnAmount: BigNumberish - receiverAddress: string - path: ArrayLike - unit: Unit -} + amount: BigNumberish; + minReturnAmount: BigNumberish; + receiverAddress: string; + path: ArrayLike; + unit: Unit; +}; export type GenerateSwapCalldataParams = { - amount: BigNumberish - minReturnAmount: BigNumberish - receiverAddress: string - path: ArrayLike - wethAddress: AddressLike, - curveRegistryAddress: AddressLike, - swapExecutorContractAddress: AddressLike, - exchangeContractAddress: AddressLike, - provider: JsonRpcProvider -} + amount: BigNumberish; + minReturnAmount: BigNumberish; + receiverAddress: string; + path: ArrayLike; + wethAddress: AddressLike; + curveRegistryAddress: AddressLike; + swapExecutorContractAddress: AddressLike; + provider: JsonRpcProvider; +}; export async function generateSwapCalldataWithUnit({ amount, minReturnAmount, receiverAddress, path: arrayLikePath, - unit -}: GenerateSwapCalldataWithUnitParams -): Promise<{ calldata: string, swapDescription: LibValidator.SwapDescriptionStruct }> { + unit, +}: GenerateSwapCalldataWithUnitParams): Promise<{ + calldata: string; + swapDescription: LibValidator.SwapDescriptionStruct; +}> { if (arrayLikePath == undefined || arrayLikePath.length == 0) { - throw new Error('Empty path'); + throw new Error("Empty path"); } - const wethAddress = safeGet(unit.contracts, 'WETH') - const curveRegistryAddress = safeGet(unit.contracts, 'curveRegistry') - const { assetToAddress, swapExecutorContractAddress, exchangeContractAddress } = await simpleFetch(unit.blockchainService.getInfo)(); + const wethAddress = safeGet(unit.contracts, "WETH"); + const curveRegistryAddress = safeGet(unit.contracts, "curveRegistry"); + const { assetToAddress, swapExecutorContractAddress } = await simpleFetch(unit.blockchainService.getInfo)(); let path = SafeArray.from(arrayLikePath).map((swapInfo) => { swapInfo.assetIn = assetToAddress[swapInfo.assetIn] ?? swapInfo.assetIn.toLowerCase(); swapInfo.assetOut = assetToAddress[swapInfo.assetOut] ?? swapInfo.assetOut.toLowerCase(); return swapInfo; - }) + }); return generateSwapCalldata({ amount, @@ -65,9 +69,8 @@ export async function generateSwapCalldataWithUnit({ wethAddress, curveRegistryAddress, swapExecutorContractAddress, - exchangeContractAddress, - provider: unit.provider - }) + provider: unit.provider, + }); } export async function generateSwapCalldata({ @@ -78,198 +81,182 @@ export async function generateSwapCalldata({ wethAddress: wethAddressLike, curveRegistryAddress: curveRegistryAddressLike, swapExecutorContractAddress: swapExecutorContractAddressLike, - exchangeContractAddress: exchangeContractAddressLike, provider, }: GenerateSwapCalldataParams) { - const wethAddress = await addressLikeToString(wethAddressLike) - const curveRegistryAddress = await addressLikeToString(curveRegistryAddressLike) - const swapExecutorContractAddress = await addressLikeToString(swapExecutorContractAddressLike) - const exchangeContractAddress = await addressLikeToString(exchangeContractAddressLike) - let path = SafeArray.from(arrayLikePath) + const wethAddress = await addressLikeToString(wethAddressLike); + const curveRegistryAddress = await addressLikeToString(curveRegistryAddressLike); + const swapExecutorContractAddress = await addressLikeToString(swapExecutorContractAddressLike); + let path = SafeArray.from(arrayLikePath); - const { factory, assetIn: srcToken } = path.first() - const dstToken = path.last().assetOut + const { factory, assetIn: srcToken } = path.first(); + const dstToken = path.last().assetOut; + const amountNativeDecimals = await exchangeToNativeDecimals(srcToken, amount, provider); + const minReturnAmountNativeDecimals = await exchangeToNativeDecimals(dstToken, minReturnAmount, provider); let swapDescription: LibValidator.SwapDescriptionStruct = { srcToken: srcToken, dstToken: dstToken, srcReceiver: swapExecutorContractAddress, dstReceiver: receiverAddress, - amount, - minReturnAmount, - flags: 0 - } - const amountNativeDecimals = await exchangeToNativeDecimals(srcToken, amount, provider); + amount: amountNativeDecimals, + minReturnAmount: minReturnAmountNativeDecimals, + flags: 0, + }; path = SafeArray.from(arrayLikePath).map((singleSwap) => { - if (singleSwap.assetIn == ethers.ZeroAddress) singleSwap.assetIn = wethAddress - if (singleSwap.assetOut == ethers.ZeroAddress) singleSwap.assetOut = wethAddress + if (singleSwap.assetIn == ethers.ZeroAddress) singleSwap.assetIn = wethAddress; + if (singleSwap.assetOut == ethers.ZeroAddress) singleSwap.assetOut = wethAddress; return singleSwap; }); - - const isSingleFactorySwap = path.every(singleSwap => singleSwap.factory === factory) - let calldata: BytesLike + + const isSingleFactorySwap = path.every((singleSwap) => singleSwap.factory === factory); + let calls: BytesLike[]; if (isSingleFactorySwap) { - ({ swapDescription, calldata } = await processSingleFactorySwaps( + ({ swapDescription, calls } = await processSingleFactorySwaps( factory, swapDescription, path, - exchangeContractAddress, amountNativeDecimals, swapExecutorContractAddress, curveRegistryAddress, provider - )) + )); } else { - ({ swapDescription, calldata } = await processMultiFactorySwaps( + ({ swapDescription, calls } = await processMultiFactorySwaps( swapDescription, path, - exchangeContractAddress, amountNativeDecimals, swapExecutorContractAddress, curveRegistryAddress, provider - )) + )); } - return { swapDescription, calldata } + calls = wrapOrUnwrapIfNeeded(swapDescription, calls); + const calldata = generateCalls(calls); + return { swapDescription, calldata }; } async function processSingleFactorySwaps( factory: Factory, swapDescription: LibValidator.SwapDescriptionStruct, path: SafeArray, - recipient: string, amount: BigNumberish, swapExecutorContractAddress: string, curveRegistryAddress: string, provider: JsonRpcProvider ) { - let calldata: BytesLike + let calls: BytesLike[] = []; switch (factory) { - case 'OrionV2': { - swapDescription.srcReceiver = path.first().pool - calldata = await generateUni2Calls(path, recipient); + case "OrionV2": { + swapDescription.srcReceiver = path.first().pool; + calls = await generateUni2Calls(path, swapExecutorContractAddress); break; } - case 'UniswapV2': { - swapDescription.srcReceiver = path.first().pool - calldata = await generateUni2Calls(path, recipient); + case "UniswapV2": { + swapDescription.srcReceiver = path.first().pool; + calls = await generateUni2Calls(path, swapExecutorContractAddress); break; } - case 'UniswapV3': { - calldata = await generateUni3Calls(path, amount, recipient, provider) + case "UniswapV3": { + calls = await generateUni3Calls(path, amount, swapExecutorContractAddress, provider); break; } - case 'OrionV3': { - calldata = await generateOrion3Calls(path, amount, recipient, provider) + case "OrionV3": { + calls = await generateOrion3Calls(path, amount, swapExecutorContractAddress, provider); break; } - case 'Curve': { + case "Curve": { if (path.length > 1) { - throw new Error('Supporting only single stable swap on curve') + throw new Error("Supporting only single stable swap on curve"); } - const { pool, assetIn } = path.first() - const firstToken = ERC20__factory.connect(assetIn, provider) - const executorAllowance = await firstToken.allowance(swapExecutorContractAddress, pool) - const calls: BytesLike[] = [] - if (executorAllowance <= BigInt(amount)) { - const approveCall = await generateApproveCall( - assetIn, - pool, - ethers.MaxUint256 - ) - calls.push(approveCall) - } - let curveCall = await generateCurveStableSwapCall( + calls = await generateCurveStableSwapCall( amount, - recipient, + swapExecutorContractAddress, path.first(), provider, + swapExecutorContractAddress, curveRegistryAddress ); - calls.push(curveCall) - calldata = await generateCalls(calls) break; } default: { - throw new Error(`Factory ${factory} is not supported`) + throw new Error(`Factory ${factory} is not supported`); } } - return { swapDescription, calldata } + return { swapDescription, calls }; } async function processMultiFactorySwaps( swapDescription: LibValidator.SwapDescriptionStruct, path: SafeArray, - recipient: string, amount: BigNumberish, swapExecutorContractAddress: string, curveRegistryAddress: string, provider: JsonRpcProvider ) { - let calls: BytesLike[] = [] + let calls: BytesLike[] = []; + if (swapDescription.srcToken === ZeroAddress) { + const wrapCall = await generateWrapAndTransferCall(swapExecutorContractAddress, { value: amount }); + calls.push(wrapCall); + } for (const swap of path) { switch (swap.factory) { - case 'OrionV2': { - let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0) - transferCall = pathCallWithBalance(transferCall, swap.assetIn) - const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress) - calls = calls.concat([transferCall, uni2Call]) + case "OrionV2": { + let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0); + transferCall = pathCallWithBalance(transferCall, swap.assetIn); + const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress); + calls.push(transferCall, uni2Call); break; } - case 'UniswapV2': { - let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0) - transferCall = pathCallWithBalance(transferCall, swap.assetIn) - const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress) - calls = calls.concat([transferCall, uni2Call]) + case "UniswapV2": { + let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0); + transferCall = pathCallWithBalance(transferCall, swap.assetIn); + const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress); + calls.push(transferCall, uni2Call); break; } - case 'UniswapV3': { - let uni3Call = await generateUni3Call(swap, 0, swapExecutorContractAddress, provider) - uni3Call = pathCallWithBalance(uni3Call, swap.assetIn) - calls.push(uni3Call) + case "UniswapV3": { + let uni3Call = await generateUni3Call(swap, 0, swapExecutorContractAddress, provider); + uni3Call = pathCallWithBalance(uni3Call, swap.assetIn); + calls.push(uni3Call); break; } - case 'OrionV3': { - let orion3Call = await generateOrion3Call(swap, 0, swapExecutorContractAddress, provider) - orion3Call = pathCallWithBalance(orion3Call, swap.assetIn) - calls.push(orion3Call) + case "OrionV3": { + let orion3Call = await generateOrion3Call(swap, 0, swapExecutorContractAddress, provider); + orion3Call = pathCallWithBalance(orion3Call, swap.assetIn); + calls.push(orion3Call); break; } - case 'Curve': { - const { pool, assetIn } = swap - const firstToken = ERC20__factory.connect(assetIn, provider) - const executorAllowance = await firstToken.allowance(swapExecutorContractAddress, pool) - if (executorAllowance <= BigInt(amount)) { - const approveCall = await generateApproveCall( - assetIn, - pool, - ethers.MaxUint256 - ) - calls.push(approveCall) - } - let curveCall = await generateCurveStableSwapCall( + case "Curve": { + let curveCalls = await generateCurveStableSwapCall( amount, swapExecutorContractAddress, swap, provider, + swapExecutorContractAddress, curveRegistryAddress ); - curveCall = pathCallWithBalance(curveCall, swap.assetIn) - calls.push(curveCall) + calls.push(...curveCalls); break; } default: { - throw new Error(`Factory ${swap.factory} is not supported`) + throw new Error(`Factory ${swap.factory} is not supported`); } } } - const dstToken = swapDescription.dstToken - let finalTransferCall = await generateTransferCall(dstToken, recipient, 0) - finalTransferCall = pathCallWithBalance(finalTransferCall, dstToken) - calls.push(finalTransferCall) - const calldata = generateCalls(calls) - - return { swapDescription, calldata } + return { swapDescription, calls }; +} + +function wrapOrUnwrapIfNeeded(swapDescription: LibValidator.SwapDescriptionStruct, calls: BytesLike[]): BytesLike[] { + if (swapDescription.srcToken === ZeroAddress) { + const wrapCall = generateWrapAndTransferCall(swapDescription.dstReceiver, { value: swapDescription.amount }); + calls = ([wrapCall] as BytesLike[]).concat(calls); + } + if (swapDescription.dstToken === ZeroAddress) { + let unwrapCall = generateUnwrapAndTransferCall(swapDescription.dstReceiver, 0); + unwrapCall = pathCallWithBalance(unwrapCall, swapDescription.dstToken); + calls.push(unwrapCall); + } + return calls; }