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 51a3ce5..68d26fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.10", + "version": "0.20.10-rc107", "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 da40ee6..e792a27 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -1,50 +1,113 @@ -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'; + 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"; +import { Exchange__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js"; +import getBalance from "../../utils/getBalance.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; +}; export type GenerateSwapCalldataParams = { - amount: BigNumberish - minReturnAmount: BigNumberish - receiverAddress: string - path: ArrayLike - unit: Unit -} + amount: BigNumberish; + minReturnAmount: BigNumberish; + receiverAddress: string; + useContractBalance: boolean; + path: ArrayLike; + wethAddress: AddressLike; + curveRegistryAddress: AddressLike; + swapExecutorContractAddress: AddressLike; + provider: JsonRpcProvider; +}; -export default async function generateSwapCalldata({ +export async function generateSwapCalldataWithUnit({ amount, minReturnAmount, receiverAddress, path: arrayLikePath, - unit -}: GenerateSwapCalldataParams -): 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)(); - let path = SafeArray.from(arrayLikePath).map((swapInfo) => { + const wethAddress = safeGet(unit.contracts, "WETH"); + const curveRegistryAddress = safeGet(unit.contracts, "curveRegistry"); + const { assetToAddress, swapExecutorContractAddress, exchangeContractAddress } = await simpleFetch( + unit.blockchainService.getInfo + )(); + + let path = SafeArray.from(arrayLikePath); + const { wallet } = await getBalance( + unit.aggregator, + path.first().assetIn, + safeGet(assetToAddress, path.first().assetIn), + receiverAddress, + Exchange__factory.connect(exchangeContractAddress, unit.provider), + unit.provider + ); + + path = SafeArray.from(arrayLikePath).map((swapInfo) => { swapInfo.assetIn = assetToAddress[swapInfo.assetIn] ?? swapInfo.assetIn.toLowerCase(); swapInfo.assetOut = assetToAddress[swapInfo.assetOut] ?? swapInfo.assetOut.toLowerCase(); return swapInfo; - }) + }); - const { factory, assetIn: srcToken } = path.first() - const dstToken = path.last().assetOut + return generateSwapCalldata({ + amount, + minReturnAmount, + receiverAddress, + useContractBalance: BigInt(wallet.toString()) < BigInt(amount), + path, + wethAddress, + curveRegistryAddress, + swapExecutorContractAddress, + provider: unit.provider, + }); +} + +export async function generateSwapCalldata({ + amount, + minReturnAmount, + receiverAddress, + useContractBalance, + path: arrayLikePath, + wethAddress: wethAddressLike, + curveRegistryAddress: curveRegistryAddressLike, + swapExecutorContractAddress: swapExecutorContractAddressLike, + provider, +}: GenerateSwapCalldataParams) { + 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; let swapDescription: LibValidator.SwapDescriptionStruct = { srcToken: srcToken, @@ -53,178 +116,186 @@ export default async function generateSwapCalldata({ dstReceiver: receiverAddress, amount, minReturnAmount, - flags: 0 - } - const amountNativeDecimals = await exchangeToNativeDecimals(srcToken, amount, unit.provider); + flags: 0, + }; + const amountNativeDecimals = await exchangeToNativeDecimals(srcToken, amount, provider); 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, - unit.provider - )) + provider + )); } else { - ({ swapDescription, calldata } = await processMultiFactorySwaps( + ({ swapDescription, calls } = await processMultiFactorySwaps( swapDescription, path, - exchangeContractAddress, amountNativeDecimals, swapExecutorContractAddress, curveRegistryAddress, - unit.provider - )) + provider + )); } - return { swapDescription, calldata } + ({ swapDescription, calls } = await wrapOrUnwrapIfNeeded( + amountNativeDecimals, + swapDescription, + calls, + swapExecutorContractAddress, + wethAddress + )); + const calldata = generateCalls(calls); + + if (useContractBalance) { + swapDescription.flags = 1n << 255n; + } + + 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 }; +} + +async function wrapOrUnwrapIfNeeded( + amount: BigNumberish, + swapDescription: LibValidator.SwapDescriptionStruct, + calls: BytesLike[], + swapExecutorContractAddress: string, + wethAddress: string +) { + if (swapDescription.srcToken === ZeroAddress) { + const wrapCall = generateWrapAndTransferCall(swapDescription.srcReceiver, { value: amount }); + swapDescription.srcReceiver = swapExecutorContractAddress; + calls = ([wrapCall] as BytesLike[]).concat(calls); + } + if (swapDescription.dstToken === ZeroAddress) { + let unwrapCall = generateUnwrapAndTransferCall(swapDescription.dstReceiver, 0); + unwrapCall = pathCallWithBalance(unwrapCall, wethAddress); + calls.push(unwrapCall); + } else { + let transferCall = await generateTransferCall(swapDescription.dstToken, swapDescription.dstReceiver, 0); + transferCall = pathCallWithBalance(transferCall, swapDescription.dstToken); + calls.push(transferCall); + } + return { swapDescription, calls }; } diff --git a/src/Unit/Exchange/index.ts b/src/Unit/Exchange/index.ts index f6b75a3..c25b7b9 100644 --- a/src/Unit/Exchange/index.ts +++ b/src/Unit/Exchange/index.ts @@ -1,7 +1,7 @@ import type Unit from '../index.js'; import deposit, { type DepositParams } from './deposit.js'; import getSwapInfo, { type GetSwapInfoParams } from './getSwapInfo.js'; -import generateSwapCalldata, { type GenerateSwapCalldataParams } from './generateSwapCalldata.js'; +import {generateSwapCalldataWithUnit, type GenerateSwapCalldataParams } from './generateSwapCalldata.js'; import withdraw, { type WithdrawParams } from './withdraw.js'; type PureDepositParams = Omit @@ -39,7 +39,7 @@ export default class Exchange { } public generateSwapCalldata(params: PureGenerateSwapCalldataParams) { - return generateSwapCalldata({ + return generateSwapCalldataWithUnit({ ...params, unit: this.unit }) diff --git a/src/index.ts b/src/index.ts index a23d913..7b72aa7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ BigNumber.config({ EXPONENTIAL_AT: 1e+9 }); export * as config from './config/index.js'; export { default as Unit } from './Unit/index.js'; export { default as Orion } from './Orion/index.js'; +export {generateSwapCalldata} from './Unit/Exchange/generateSwapCalldata.js'; export { default as factories} from './constants/factories.js'; export * as utils from './utils/index.js'; export * as services from './services/index.js'; diff --git a/src/utils/addressLikeToString.ts b/src/utils/addressLikeToString.ts new file mode 100644 index 0000000..974c505 --- /dev/null +++ b/src/utils/addressLikeToString.ts @@ -0,0 +1,9 @@ +import type { AddressLike } from "ethers"; + +export async function addressLikeToString(address: AddressLike): Promise { + address = await address + if (typeof address !== 'string') { + address = await address.getAddress() + } + return address +} \ No newline at end of file