From 826b3b508caae83d18fb9adb0ba2afa2fdf7770e Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Fri, 15 Dec 2023 17:55:44 +0400 Subject: [PATCH 01/10] added fee payment to matcher if dst.Token === feeToken --- package-lock.json | 18 ++--- package.json | 4 +- src/Unit/Exchange/callGenerators/erc20.ts | 7 +- .../Exchange/callGenerators/feePayment.ts | 21 ++++++ src/Unit/Exchange/callGenerators/uniswapV2.ts | 2 +- src/Unit/Exchange/generateSwapCalldata.ts | 66 +++++++++++++++---- 6 files changed, 90 insertions(+), 28 deletions(-) create mode 100644 src/Unit/Exchange/callGenerators/feePayment.ts diff --git a/package-lock.json b/package-lock.json index e5dea1e..9d3274b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.28", + "version": "0.20.32", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@orionprotocol/sdk", - "version": "0.20.28", + "version": "0.20.32", "hasInstallScript": true, "license": "ISC", "dependencies": { "@babel/runtime": "^7.21.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@orionprotocol/contracts": "1.22.3", + "@orionprotocol/contracts": "1.22.5", "@types/lodash.clonedeep": "^4.5.9", "bignumber.js": "^9.1.1", "bson-objectid": "^2.0.4", @@ -2421,9 +2421,9 @@ } }, "node_modules/@orionprotocol/contracts": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.3.tgz", - "integrity": "sha512-TVZftFbrHA+ldZSvMAGTntSiTT20UWn6P/+N392A9dv6RtiIXaQpMic5hOhVdIed74DU/KixVxwjVL1Hr0RLGQ==" + "version": "1.22.5", + "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.5.tgz", + "integrity": "sha512-kBgqMw0uqotl9UbSubw5cmEsck5aefS9l9/5DNvFfOfMLY1ewFLtn03X3/mO73ll1Y6tZBtqzYTGNZpcnk7tKA==" }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -13480,9 +13480,9 @@ } }, "@orionprotocol/contracts": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.3.tgz", - "integrity": "sha512-TVZftFbrHA+ldZSvMAGTntSiTT20UWn6P/+N392A9dv6RtiIXaQpMic5hOhVdIed74DU/KixVxwjVL1Hr0RLGQ==" + "version": "1.22.5", + "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.5.tgz", + "integrity": "sha512-kBgqMw0uqotl9UbSubw5cmEsck5aefS9l9/5DNvFfOfMLY1ewFLtn03X3/mO73ll1Y6tZBtqzYTGNZpcnk7tKA==" }, "@sinclair/typebox": { "version": "0.27.8", diff --git a/package.json b/package.json index 98378d0..513f328 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34", + "version": "0.20.34-rc-0", "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.22.3", + "@orionprotocol/contracts": "1.22.5", "@types/lodash.clonedeep": "^4.5.9", "bignumber.js": "^9.1.1", "bson-objectid": "^2.0.4", diff --git a/src/Unit/Exchange/callGenerators/erc20.ts b/src/Unit/Exchange/callGenerators/erc20.ts index e88e24a..bd54dd2 100644 --- a/src/Unit/Exchange/callGenerators/erc20.ts +++ b/src/Unit/Exchange/callGenerators/erc20.ts @@ -1,9 +1,8 @@ import { SwapExecutor__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js" -import type { BigNumberish } from "ethers" +import type { BigNumberish, AddressLike } from "ethers" import { type CallParams, addCallParams } from "./utils.js" -import type { AddressLike } from "ethers" -export async function generateTransferCall( +export function generateTransferCall( token: AddressLike, target: AddressLike, amount: BigNumberish, @@ -20,7 +19,7 @@ export async function generateTransferCall( return addCallParams(calldata, callParams) } -export async function generateApproveCall( +export function generateApproveCall( token: AddressLike, target: AddressLike, amount: BigNumberish, diff --git a/src/Unit/Exchange/callGenerators/feePayment.ts b/src/Unit/Exchange/callGenerators/feePayment.ts new file mode 100644 index 0000000..ee1eb29 --- /dev/null +++ b/src/Unit/Exchange/callGenerators/feePayment.ts @@ -0,0 +1,21 @@ +import { SwapExecutor__factory } from "@orionprotocol/contracts/lib/ethers-v6/index.js" +import type { BigNumberish, AddressLike } from "ethers" +import { type CallParams, addCallParams } from "./utils.js" + + +export function generateFeePaymentCall( + matcher: AddressLike, + token: AddressLike, + amount: BigNumberish, + callParams?: CallParams +) { + + const executorInterface = SwapExecutor__factory.createInterface() + const calldata = executorInterface.encodeFunctionData('payFeeToMatcher', [ + matcher, + token, + amount + ]) + + return addCallParams(calldata, callParams) +} \ No newline at end of file diff --git a/src/Unit/Exchange/callGenerators/uniswapV2.ts b/src/Unit/Exchange/callGenerators/uniswapV2.ts index 19b86b0..4526fca 100644 --- a/src/Unit/Exchange/callGenerators/uniswapV2.ts +++ b/src/Unit/Exchange/callGenerators/uniswapV2.ts @@ -36,7 +36,7 @@ export async function generateUni2Calls( return calls } -export async function generateUni2Call( +export function generateUni2Call( pool: string, assetIn: string, assetOut: string, diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index cefce17..343723a 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -19,6 +19,7 @@ import type { SingleSwap } from "../../types.js"; import { addressLikeToString } from "../../utils/addressLikeToString.js"; import { generateUnwrapAndTransferCall, generateWrapAndTransferCall } from "./callGenerators/weth.js"; import { getExchangeAllowance, getTotalBalance } from "../../utils/getBalance.js"; +import { generateFeePaymentCall } from "./callGenerators/feePayment.js"; export type Factory = "UniswapV2" | "UniswapV3" | "Curve" | "OrionV2" | "OrionV3"; @@ -27,6 +28,9 @@ export type GenerateSwapCalldataWithUnitParams = { minReturnAmount: BigNumberish; initiatorAddress: string; receiverAddress: string; + matcher: AddressLike, + feeToken: AddressLike, + fee: BigNumberish; path: ArrayLike; unit: Unit; }; @@ -37,6 +41,9 @@ export type GenerateSwapCalldataParams = { initiatorAddress: string; receiverAddress: string; path: ArrayLike; + matcher: AddressLike, + feeToken: AddressLike, + fee: BigNumberish; exchangeContractAddress: AddressLike; wethAddress: AddressLike; curveRegistryAddress: AddressLike; @@ -50,6 +57,9 @@ export async function generateSwapCalldataWithUnit({ initiatorAddress, receiverAddress, path: arrayLikePath, + matcher = ZeroAddress, + feeToken = ZeroAddress, + fee = 0, unit, }: GenerateSwapCalldataWithUnitParams): Promise<{ calldata: string; @@ -80,6 +90,9 @@ export async function generateSwapCalldataWithUnit({ receiverAddress, initiatorAddress, path, + matcher, + feeToken, + fee, exchangeContractAddress, wethAddress, curveRegistryAddress, @@ -94,6 +107,9 @@ export async function generateSwapCalldata({ initiatorAddress, receiverAddress, path: arrayLikePath, + matcher = ZeroAddress, + feeToken = ZeroAddress, + fee = 0, exchangeContractAddress, wethAddress: wethAddressLike, curveRegistryAddress: curveRegistryAddressLike, @@ -134,6 +150,9 @@ export async function generateSwapCalldata({ swapDescription, path, amountNativeDecimals, + matcher, + feeToken, + fee, wethAddress, swapExecutorContractAddress, curveRegistryAddress, @@ -159,6 +178,9 @@ async function processSwaps( swapDescription: LibValidator.SwapDescriptionStruct, path: SafeArray, amount: BigNumberish, + matcher: AddressLike, + feeToken: AddressLike, + fee: BigNumberish, wethAddress: string, swapExecutorContractAddress: string, curveRegistryAddress: string, @@ -187,13 +209,17 @@ async function processSwaps( provider )); } - ({ swapDescription, calls } = await wrapOrUnwrapIfNeeded( + + ({swapDescription, calls} = payFeeToMatcher(matcher, feeToken, fee, calls, swapDescription)); + + ({ swapDescription, calls } = wrapOrUnwrapIfNeeded( amount, swapDescription, calls, swapExecutorContractAddress, wethAddress )); + return { swapDescription, calls }; } @@ -259,16 +285,16 @@ async function processMultiFactorySwaps( for (const swap of path) { switch (swap.factory) { case "OrionV2": { - let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0); + let transferCall = generateTransferCall(swap.assetIn, swap.pool, 0); transferCall = pathCallWithBalance(transferCall, swap.assetIn); - const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress); + const uni2Call = generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress); calls.push(transferCall, uni2Call); break; } case "UniswapV2": { - let transferCall = await generateTransferCall(swap.assetIn, swap.pool, 0); + let transferCall = generateTransferCall(swap.assetIn, swap.pool, 0); transferCall = pathCallWithBalance(transferCall, swap.assetIn); - const uni2Call = await generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress); + const uni2Call = generateUni2Call(swap.pool, swap.assetIn, swap.assetOut, swapExecutorContractAddress); calls.push(transferCall, uni2Call); break; } @@ -305,25 +331,41 @@ async function processMultiFactorySwaps( return { swapDescription, calls }; } -async function wrapOrUnwrapIfNeeded( +function payFeeToMatcher( + matcher: AddressLike, + feeToken: AddressLike, + feeAmount: BigNumberish, + calls: BytesLike[], + swapDescription: LibValidator.SwapDescriptionStruct, +) { + feeAmount = BigInt(feeAmount) + if (feeAmount !== 0n && feeToken === swapDescription.dstToken) { + const feePaymentCall = generateFeePaymentCall(matcher, feeToken, feeAmount) + calls.push(feePaymentCall) + } + return {swapDescription, calls} +} + +function wrapOrUnwrapIfNeeded( amount: BigNumberish, swapDescription: LibValidator.SwapDescriptionStruct, calls: BytesLike[], swapExecutorContractAddress: string, wethAddress: string ) { - if (swapDescription.srcToken === ZeroAddress) { - const wrapCall = generateWrapAndTransferCall(swapDescription.srcReceiver, { value: amount }); + const {dstReceiver, srcReceiver, srcToken, dstToken} = swapDescription; + if (srcToken === ZeroAddress) { + const wrapCall = generateWrapAndTransferCall(srcReceiver, { value: amount }); swapDescription.srcReceiver = swapExecutorContractAddress; calls = ([wrapCall] as BytesLike[]).concat(calls); } - if (swapDescription.dstToken === ZeroAddress) { - let unwrapCall = generateUnwrapAndTransferCall(swapDescription.dstReceiver, 0); + if (dstToken === ZeroAddress) { + let unwrapCall = generateUnwrapAndTransferCall(dstReceiver, 0); unwrapCall = pathCallWithBalance(unwrapCall, wethAddress); calls.push(unwrapCall); } else { - let transferCall = await generateTransferCall(swapDescription.dstToken, swapDescription.dstReceiver, 0); - transferCall = pathCallWithBalance(transferCall, swapDescription.dstToken); + let transferCall = generateTransferCall(dstToken, dstReceiver, 0); + transferCall = pathCallWithBalance(transferCall, dstToken); calls.push(transferCall); } return { swapDescription, calls }; From 54bf512d21d5f8891c2cd5e47e8a21c1a856ff9f Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Fri, 15 Dec 2023 18:04:51 +0400 Subject: [PATCH 02/10] delete depricated addLiquidityToPool functionality --- src/Unit/FarmingManager/index.ts | 413 ------------------------------- src/Unit/index.ts | 4 - 2 files changed, 417 deletions(-) delete mode 100644 src/Unit/FarmingManager/index.ts diff --git a/src/Unit/FarmingManager/index.ts b/src/Unit/FarmingManager/index.ts deleted file mode 100644 index f4f7fbb..0000000 --- a/src/Unit/FarmingManager/index.ts +++ /dev/null @@ -1,413 +0,0 @@ -import { Exchange__factory, IUniswapV2Pair__factory, IUniswapV2Router__factory } from '@orionprotocol/contracts/lib/ethers-v6/index.js'; -import { BigNumber } from 'bignumber.js'; -import { ethers } from 'ethers'; -import { simpleFetch } from 'simple-typed-fetch'; -import type Unit from '../index.js'; -import BalanceGuard from '../../BalanceGuard.js'; -import { ADD_LIQUIDITY_GAS_LIMIT, INTERNAL_PROTOCOL_PRECISION, NATIVE_CURRENCY_PRECISION } from '../../constants/index.js'; -import { denormalizeNumber, normalizeNumber } from '../../utils/index.js'; -import getBalances from '../../utils/getBalances.js'; -import getNativeCryptocurrencyName from '../../utils/getNativeCryptocurrencyName.js'; - -const ADD_LIQUIDITY_SLIPPAGE = 0.05; - -export type AddLiquidityParams = { - poolName: string - amountAsset: string - amount: BigNumber.Value - signer: ethers.Signer -} - -export type RemoveAllLiquidityParams = { - poolName: string - signer: ethers.Signer -} - -export default class FarmingManager { - private readonly unit: Unit; - - constructor(unit: Unit) { - this.unit = unit; - } - - public async addLiquidity({ - poolName, - amountAsset, - amount, - signer, - }: AddLiquidityParams) { - const amountBN = new BigNumber(amount); - if (amountBN.isNaN()) throw new Error('Invalid amount'); - if (amountBN.lte(0)) throw new Error('Amount must be greater than 0'); - if (!poolName.includes('-')) throw new Error('Pool name must be in the format of "assetA-AssetB"'); - const [assetA, assetB] = poolName.split('-'); - if (assetA === undefined) throw new Error('Asset A undefined'); - if (assetB === undefined) throw new Error('Asset B undefined'); - if (amountAsset !== assetA && amountAsset !== assetB) throw new Error('Amount asset must be either assetA or assetB'); - - const { - exchangeContractAddress, - assetToAddress, - assetToDecimals, - } = await simpleFetch(this.unit.blockchainService.getInfo)(); - - const walletAddress = await signer.getAddress(); - - const exchangeContract = Exchange__factory - .connect(exchangeContractAddress, this.unit.provider); - - const assetAAddress = assetToAddress[assetA]; - if (assetAAddress === undefined) throw new Error(`Asset '${assetA}' not found`); - const assetBAddress = assetToAddress[assetB]; - if (assetBAddress === undefined) throw new Error(`Asset '${assetB}' not found`); - - const assetADecimals = assetToDecimals[assetA]; - if (assetADecimals === undefined) throw new Error(`Decimals for asset '${assetA}' not found`); - const assetBDecimals = assetToDecimals[assetB]; - if (assetBDecimals === undefined) throw new Error(`Decimals for asset '${assetB}' not found`); - - const nativeCryptocurrency = getNativeCryptocurrencyName(assetToAddress); - const balances = await getBalances( - { - [assetA]: assetAAddress, - [assetB]: assetBAddress, - [nativeCryptocurrency]: ethers.ZeroAddress, - }, - this.unit.aggregator, - walletAddress, - exchangeContract, - this.unit.provider, - ); - const balanceGuard = new BalanceGuard( - balances, - { - address: ethers.ZeroAddress, - name: nativeCryptocurrency, - }, - this.unit.provider, - signer, - ); - - const poolsConfig = await simpleFetch(this.unit.blockchainService.getPoolsConfig)(); - const pool = poolsConfig.pools[poolName]; - if (!pool) throw new Error(`Pool ${poolName} not found`); - - const pairContract = IUniswapV2Pair__factory - .connect(pool.lpTokenAddress, this.unit.provider); - const routerContract = IUniswapV2Router__factory - .connect(poolsConfig.routerAddress, this.unit.provider); - - let pairTokensIsInversed = false; - const token0 = await pairContract.token0(); - const wrappedNativeAddress = await routerContract.WETH(); - - // const token1 = await pairContract.token1(); - if (token0.toLowerCase() !== wrappedNativeAddress.toLowerCase()) pairTokensIsInversed = true; - - const { _reserve0, _reserve1 } = await pairContract.getReserves(); - - const assetAReserve = pairTokensIsInversed ? _reserve1 : _reserve0; - const assetBReserve = pairTokensIsInversed ? _reserve0 : _reserve1; - - const denormalizedAssetAReserve = denormalizeNumber(assetAReserve, BigInt(assetADecimals)); - const denormalizedAssetBReserve = denormalizeNumber(assetBReserve, BigInt(assetBDecimals)); - - const price = denormalizedAssetBReserve.div(denormalizedAssetAReserve); - - const assetAIsNativeCurrency = assetAAddress === ethers.ZeroAddress; - const assetBIsNativeCurrency = assetBAddress === ethers.ZeroAddress; - - const assetAAmount = assetA === amountAsset ? amountBN : amountBN.div(price); - const assetBAmount = assetA === amountAsset ? amountBN.multipliedBy(price) : amountBN; - - const assetAAmountWithSlippage = assetAAmount.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE); - const assetBAmountWithSlippage = assetBAmount.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE); - - balanceGuard.registerRequirement({ - reason: `${assetA} liquidity`, - amount: assetAAmount.toString(), - asset: { - name: assetA, - address: assetAAddress, - }, - spenderAddress: exchangeContractAddress, - sources: ['exchange', 'wallet'], - }); - - balanceGuard.registerRequirement({ - reason: `${assetB} liquidity`, - amount: assetBAmount.toString(), - asset: { - name: assetB, - address: assetBAddress, - }, - spenderAddress: exchangeContractAddress, - sources: ['exchange', 'wallet'], - }); - - const unsignedTx = await exchangeContract.withdrawToPool.populateTransaction( - assetBIsNativeCurrency ? assetBAddress : assetAAddress, - assetBIsNativeCurrency ? assetAAddress : assetBAddress, - assetBIsNativeCurrency - ? normalizeNumber(assetBAmount, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString() - : normalizeNumber(assetAAmount, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString(), - assetBIsNativeCurrency - ? normalizeNumber(assetAAmount, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString() - : normalizeNumber(assetBAmount, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString(), - assetBIsNativeCurrency - ? normalizeNumber(assetBAmountWithSlippage, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString() - : normalizeNumber(assetAAmountWithSlippage, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString(), - assetBIsNativeCurrency - ? normalizeNumber(assetAAmountWithSlippage, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString() - : normalizeNumber(assetBAmountWithSlippage, INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_FLOOR).toString(), - ); - - const { gasPrice, maxFeePerGas } = await this.unit.provider.getFeeData(); - - const transactionCost = BigInt(ADD_LIQUIDITY_GAS_LIMIT) * (gasPrice ?? 0n); - const denormalizedTransactionCost = denormalizeNumber(transactionCost, BigInt(NATIVE_CURRENCY_PRECISION)); - - balanceGuard.registerRequirement({ - reason: 'Network fee', - asset: { - name: nativeCryptocurrency, - address: ethers.ZeroAddress, - }, - amount: denormalizedTransactionCost.toString(), - sources: ['wallet'], - }); - - const nonce = await this.unit.provider.getTransactionCount(walletAddress, 'pending'); - - const network = await this.unit.provider.getNetwork(); - - if (assetAIsNativeCurrency || assetBIsNativeCurrency) { - const contractBalance = balances[nativeCryptocurrency]?.exchange; - if (!contractBalance) throw new Error(`No balance for '${nativeCryptocurrency}'`); - const nativeAssetAmount = assetBIsNativeCurrency ? assetBAmount : assetAAmount; - - if (nativeAssetAmount.gt(contractBalance)) { - unsignedTx.value = normalizeNumber( - nativeAssetAmount.minus(contractBalance), - NATIVE_CURRENCY_PRECISION, - BigNumber.ROUND_CEIL, - ); - } - } - - if (gasPrice !== null && maxFeePerGas !== null) { - unsignedTx.gasPrice = gasPrice; - unsignedTx.maxFeePerGas = maxFeePerGas; - } - unsignedTx.chainId = network.chainId; - unsignedTx.nonce = nonce; - unsignedTx.from = walletAddress; - const gasLimit = await this.unit.provider.estimateGas(unsignedTx); - unsignedTx.gasLimit = gasLimit; - - await balanceGuard.check(true); - - const signedTx = await signer.signTransaction(unsignedTx); - const txResponse = await this.unit.provider.broadcastTransaction(signedTx); - console.log(`Add liquidity tx sent: ${txResponse.hash}. Waiting for confirmation...`); - const txReceipt = await txResponse.wait(); - if (txReceipt?.status === 1) { - console.log(`Add liquidity tx confirmed: ${txReceipt.hash}`); - } else { - console.log(`Add liquidity tx failed: ${txReceipt?.hash}`); - } - } - - public async removeAllLiquidity({ - poolName, - signer, - }: RemoveAllLiquidityParams) { - if (!poolName.includes('-')) throw new Error('Pool name must be in the format of "assetA-AssetB"'); - const [assetA, assetB] = poolName.split('-'); - if (assetA === undefined) throw new Error('Asset A is not defined'); - if (assetB === undefined) throw new Error('Asset B is not defined'); - - const { - assetToAddress, - assetToDecimals, - exchangeContractAddress, - } = await simpleFetch(this.unit.blockchainService.getInfo)(); - - const assetAAddress = assetToAddress[assetA]; - if (assetAAddress === undefined) throw new Error(`Asset '${assetA}' not found`); - const assetBAddress = assetToAddress[assetB]; - if (assetBAddress === undefined) throw new Error(`Asset '${assetB}' not found`); - - const assetADecimals = assetToDecimals[assetA]; - if (assetADecimals === undefined) throw new Error(`Decimals for asset '${assetA}' not found`); - const assetBDecimals = assetToDecimals[assetB]; - if (assetBDecimals === undefined) throw new Error(`Decimals for asset '${assetB}' not found`); - - const poolsConfig = await simpleFetch(this.unit.blockchainService.getPoolsConfig)(); - const pool = poolsConfig.pools[poolName]; - if (!pool) throw new Error(`Pool ${poolName} not found`); - - const walletAddress = await signer.getAddress(); - - const exchangeContract = Exchange__factory - .connect(exchangeContractAddress, this.unit.provider); - const nativeCryptocurrency = getNativeCryptocurrencyName(assetToAddress); - const balances = await getBalances( - { - [assetA]: assetAAddress, - [assetB]: assetBAddress, - [`${poolName} LP Token`]: pool.lpTokenAddress, - [nativeCryptocurrency]: ethers.ZeroAddress, - }, - this.unit.aggregator, - walletAddress, - exchangeContract, - this.unit.provider, - ); - - const balanceGuard = new BalanceGuard( - balances, - { - address: ethers.ZeroAddress, - name: nativeCryptocurrency, - }, - this.unit.provider, - signer, - ); - - const pairContract = IUniswapV2Pair__factory - .connect(pool.lpTokenAddress, this.unit.provider); - - const { _reserve0, _reserve1 } = await pairContract.getReserves(); - - const routerContract = IUniswapV2Router__factory - .connect(poolsConfig.routerAddress, this.unit.provider); - - let pairTokensIsInversed = false; - - const lpTokenUserBalance = await pairContract.balanceOf(walletAddress); - const lpTokenDecimals = await pairContract.decimals(); - - const token0 = await pairContract.token0(); - const totalSupply = await pairContract.totalSupply(); - const wrappedNativeAddress = await routerContract.WETH(); - if (token0.toLowerCase() !== wrappedNativeAddress.toLowerCase()) pairTokensIsInversed = true; - - const denormalizedLpTokenUserBalance = denormalizeNumber(lpTokenUserBalance, lpTokenDecimals); - const denormalizedLpTokenSupply = denormalizeNumber(totalSupply, lpTokenDecimals); - - const userShare = denormalizedLpTokenUserBalance.div(denormalizedLpTokenSupply); - - const assetAReserve = pairTokensIsInversed ? _reserve1 : _reserve0; - const assetBReserve = pairTokensIsInversed ? _reserve0 : _reserve1; - - const denormalizedAssetAReserve = denormalizeNumber(assetAReserve, BigInt(assetADecimals)); - const denormalizedAssetBReserve = denormalizeNumber(assetBReserve, BigInt(assetBDecimals)); - - const denormalizedUserPooledAssetA = denormalizedAssetAReserve.multipliedBy(userShare); - const denormalizedUserPooledAssetB = denormalizedAssetBReserve.multipliedBy(userShare); - - const denormalizedUserPooledAssetAWithSlippage = denormalizedUserPooledAssetA.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE); - const denormalizedUserPooledAssetBWithSlippage = denormalizedUserPooledAssetB.multipliedBy(1 - ADD_LIQUIDITY_SLIPPAGE); - - const assetAIsNativeCurrency = assetAAddress === ethers.ZeroAddress; - const assetBIsNativeCurrency = assetBAddress === ethers.ZeroAddress; - - balanceGuard.registerRequirement({ - reason: `${poolName} liquidity`, - asset: { - name: `${poolName} LP Token`, - address: pool.lpTokenAddress, - }, - spenderAddress: poolsConfig.routerAddress, - amount: denormalizedLpTokenUserBalance.toString(), - sources: ['wallet'], - }); - - let unsignedTx: ethers.TransactionLike; - if (assetAIsNativeCurrency || assetBIsNativeCurrency) { - unsignedTx = await routerContract.removeLiquidityETH.populateTransaction( - assetBIsNativeCurrency ? assetAAddress : assetBAddress, // token - lpTokenUserBalance, - assetBIsNativeCurrency - ? normalizeNumber( - denormalizedUserPooledAssetAWithSlippage, - assetADecimals, - BigNumber.ROUND_FLOOR, - ).toString() - : normalizeNumber( - denormalizedUserPooledAssetBWithSlippage, - assetBDecimals, - BigNumber.ROUND_FLOOR, - ).toString(), // token min - assetBIsNativeCurrency - ? normalizeNumber( - denormalizedUserPooledAssetBWithSlippage, - assetBDecimals, - BigNumber.ROUND_FLOOR, - ).toString() - : normalizeNumber( - denormalizedUserPooledAssetAWithSlippage, - assetADecimals, - BigNumber.ROUND_FLOOR, - ).toString(), // eth min - walletAddress, - Math.floor(Date.now() / 1000) + 60 * 20, - ); - } else { - unsignedTx = await routerContract.removeLiquidity.populateTransaction( - assetAAddress, - assetBAddress, - lpTokenUserBalance, - normalizeNumber( - denormalizedUserPooledAssetAWithSlippage, - assetADecimals, - BigNumber.ROUND_FLOOR, - ).toString(), - normalizeNumber( - denormalizedUserPooledAssetBWithSlippage, - assetBDecimals, - BigNumber.ROUND_FLOOR, - ).toString(), - walletAddress, - Math.floor(Date.now() / 1000) + 60 * 20, - ); - } - - const { gasPrice } = await this.unit.provider.getFeeData() - - const transactionCost = BigInt(ADD_LIQUIDITY_GAS_LIMIT) * (gasPrice ?? 0n); - const denormalizedTransactionCost = denormalizeNumber(transactionCost, BigInt(NATIVE_CURRENCY_PRECISION)); - - balanceGuard.registerRequirement({ - reason: 'Network fee', - asset: { - name: nativeCryptocurrency, - address: ethers.ZeroAddress, - }, - amount: denormalizedTransactionCost.toString(), - sources: ['wallet'], - }); - - await balanceGuard.check(true); - const nonce = await this.unit.provider.getTransactionCount(walletAddress, 'pending'); - const network = await this.unit.provider.getNetwork(); - - unsignedTx.chainId = network.chainId; - unsignedTx.gasPrice = gasPrice; - unsignedTx.nonce = nonce; - unsignedTx.from = walletAddress; - const gasLimit = await this.unit.provider.estimateGas(unsignedTx); - unsignedTx.gasLimit = gasLimit; - - const signedTx = await signer.signTransaction(unsignedTx); - const txResponse = await this.unit.provider.broadcastTransaction(signedTx); - console.log(`Remove all liquidity tx sent: ${txResponse.hash}. Waiting for confirmation...`); - const txReceipt = await txResponse.wait(); - if (txReceipt?.status === 1) { - console.log(`Remove all liquidity tx confirmed: ${txReceipt.hash}`); - } else { - console.log(`Remove all liquidity tx failed: ${txReceipt?.hash}`); - } - } -} diff --git a/src/Unit/index.ts b/src/Unit/index.ts index d79200e..c77bf1c 100644 --- a/src/Unit/index.ts +++ b/src/Unit/index.ts @@ -8,7 +8,6 @@ import type { VerboseUnitConfig, } from '../types.js'; import Exchange from './Exchange/index.js'; -import FarmingManager from './FarmingManager/index.js'; import { chains, envs } from '../config/index.js'; import type { networkCodes } from '../constants/index.js'; import { IndexerService } from '../services/Indexer/index.js'; @@ -35,8 +34,6 @@ export default class Unit { public readonly exchange: Exchange; - public readonly farmingManager: FarmingManager; - public readonly config: VerboseUnitConfig; public readonly contracts: Record; @@ -123,6 +120,5 @@ export default class Unit { this.config.basicAuth ); this.exchange = new Exchange(this); - this.farmingManager = new FarmingManager(this); } } From ba24f065edff49d50a17ad5edfca693d83e99d56 Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 10:54:29 +0400 Subject: [PATCH 03/10] update contracts depedency --- package-lock.json | 18 +++++++++--------- package.json | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9d3274b..b2f5812 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.32", + "version": "0.20.34-rc-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@orionprotocol/sdk", - "version": "0.20.32", + "version": "0.20.34-rc-0", "hasInstallScript": true, "license": "ISC", "dependencies": { "@babel/runtime": "^7.21.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@orionprotocol/contracts": "1.22.5", + "@orionprotocol/contracts": "1.22.6", "@types/lodash.clonedeep": "^4.5.9", "bignumber.js": "^9.1.1", "bson-objectid": "^2.0.4", @@ -2421,9 +2421,9 @@ } }, "node_modules/@orionprotocol/contracts": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.5.tgz", - "integrity": "sha512-kBgqMw0uqotl9UbSubw5cmEsck5aefS9l9/5DNvFfOfMLY1ewFLtn03X3/mO73ll1Y6tZBtqzYTGNZpcnk7tKA==" + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.6.tgz", + "integrity": "sha512-pPQGPNBcf1LQlNJk/Iq4BtV6ccuDSEBJhBIEORNf93vgYyUJ3SZ5O2/5y/nWgywLghPh2WwoAhnUKFeUEUmgsA==" }, "node_modules/@sinclair/typebox": { "version": "0.27.8", @@ -13480,9 +13480,9 @@ } }, "@orionprotocol/contracts": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.5.tgz", - "integrity": "sha512-kBgqMw0uqotl9UbSubw5cmEsck5aefS9l9/5DNvFfOfMLY1ewFLtn03X3/mO73ll1Y6tZBtqzYTGNZpcnk7tKA==" + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-1.22.6.tgz", + "integrity": "sha512-pPQGPNBcf1LQlNJk/Iq4BtV6ccuDSEBJhBIEORNf93vgYyUJ3SZ5O2/5y/nWgywLghPh2WwoAhnUKFeUEUmgsA==" }, "@sinclair/typebox": { "version": "0.27.8", diff --git a/package.json b/package.json index 513f328..5b18e0c 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "@babel/runtime": "^7.21.0", "@ethersproject/abstract-signer": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@orionprotocol/contracts": "1.22.5", + "@orionprotocol/contracts": "1.22.6", "@types/lodash.clonedeep": "^4.5.9", "bignumber.js": "^9.1.1", "bson-objectid": "^2.0.4", From fabce0540e39a9e3aa6cad7261bdac5aebfc8660 Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 10:59:57 +0400 Subject: [PATCH 04/10] bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b18e0c..f3526bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34-rc-0", + "version": "0.20.34-rc-1", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", From 7cd71b2c60e15124eb16aa35d2d81a90ca886bcd Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 11:10:35 +0400 Subject: [PATCH 05/10] fee parameter should be in exchange decimals --- package.json | 2 +- src/Unit/Exchange/generateSwapCalldata.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f3526bf..d308744 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34-rc-1", + "version": "0.20.34-rc-2", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index 343723a..fa807b6 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -138,6 +138,7 @@ export async function generateSwapCalldata({ flags: 0, }; const amountNativeDecimals = await exchangeToNativeDecimals(srcToken, amount, provider); + const feeNativeDecimals = await exchangeToNativeDecimals(feeToken, fee, provider) path = SafeArray.from(arrayLikePath).map((singleSwap) => { if (singleSwap.assetIn == ethers.ZeroAddress) singleSwap.assetIn = wethAddress; @@ -152,7 +153,7 @@ export async function generateSwapCalldata({ amountNativeDecimals, matcher, feeToken, - fee, + feeNativeDecimals, wethAddress, swapExecutorContractAddress, curveRegistryAddress, @@ -210,7 +211,7 @@ async function processSwaps( )); } - ({swapDescription, calls} = payFeeToMatcher(matcher, feeToken, fee, calls, swapDescription)); + ({swapDescription, calls} = await payFeeToMatcher(matcher, feeToken, fee, calls, swapDescription)); ({ swapDescription, calls } = wrapOrUnwrapIfNeeded( amount, @@ -331,14 +332,13 @@ async function processMultiFactorySwaps( return { swapDescription, calls }; } -function payFeeToMatcher( +async function payFeeToMatcher( matcher: AddressLike, feeToken: AddressLike, feeAmount: BigNumberish, calls: BytesLike[], swapDescription: LibValidator.SwapDescriptionStruct, ) { - feeAmount = BigInt(feeAmount) if (feeAmount !== 0n && feeToken === swapDescription.dstToken) { const feePaymentCall = generateFeePaymentCall(matcher, feeToken, feeAmount) calls.push(feePaymentCall) From b38f0ba424a006eeba5d89dbf55f0ee1a5488536 Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 11:56:27 +0400 Subject: [PATCH 06/10] convert addresslike to string --- package.json | 2 +- src/Unit/Exchange/generateSwapCalldata.ts | 13 ++++++++----- src/utils/addressLikeToString.ts | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index d308744..fccdd62 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34-rc-2", + "version": "0.20.34-rc-3", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index fa807b6..5527478 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -107,8 +107,8 @@ export async function generateSwapCalldata({ initiatorAddress, receiverAddress, path: arrayLikePath, - matcher = ZeroAddress, - feeToken = ZeroAddress, + matcher: matcherAddressLike = ZeroAddress, + feeToken: feeTokenAddressLike = ZeroAddress, fee = 0, exchangeContractAddress, wethAddress: wethAddressLike, @@ -123,6 +123,8 @@ export async function generateSwapCalldata({ const wethAddress = await addressLikeToString(wethAddressLike); const curveRegistryAddress = await addressLikeToString(curveRegistryAddressLike); const swapExecutorContractAddress = await addressLikeToString(swapExecutorContractAddressLike); + const feeToken = await addressLikeToString(feeTokenAddressLike); + const matcher = await addressLikeToString(matcherAddressLike); let path = SafeArray.from(arrayLikePath); const { assetIn: srcToken } = path.first(); @@ -333,13 +335,14 @@ async function processMultiFactorySwaps( } async function payFeeToMatcher( - matcher: AddressLike, - feeToken: AddressLike, + matcher: string, + feeToken: string, feeAmount: BigNumberish, calls: BytesLike[], swapDescription: LibValidator.SwapDescriptionStruct, ) { - if (feeAmount !== 0n && feeToken === swapDescription.dstToken) { + + if (BigInt(feeAmount) !== 0n && feeToken === swapDescription.dstToken) { const feePaymentCall = generateFeePaymentCall(matcher, feeToken, feeAmount) calls.push(feePaymentCall) } diff --git a/src/utils/addressLikeToString.ts b/src/utils/addressLikeToString.ts index 974c505..86fd132 100644 --- a/src/utils/addressLikeToString.ts +++ b/src/utils/addressLikeToString.ts @@ -5,5 +5,5 @@ export async function addressLikeToString(address: AddressLike): Promise if (typeof address !== 'string') { address = await address.getAddress() } - return address + return address.toLowerCase() } \ No newline at end of file From fc00a8bff0b0dbaed3bf2bdec203b20668c7a5bd Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 12:42:38 +0400 Subject: [PATCH 07/10] fix types --- src/Unit/Exchange/generateSwapCalldata.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index 5527478..a13096a 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -181,8 +181,8 @@ async function processSwaps( swapDescription: LibValidator.SwapDescriptionStruct, path: SafeArray, amount: BigNumberish, - matcher: AddressLike, - feeToken: AddressLike, + matcher: string, + feeToken: string, fee: BigNumberish, wethAddress: string, swapExecutorContractAddress: string, From 06f1f3d8cf25a1c9440f987dfa8dd3c5ff76319d Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 13:01:56 +0400 Subject: [PATCH 08/10] add debug console.log --- package.json | 2 +- src/Unit/Exchange/generateSwapCalldata.ts | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fccdd62..0b27452 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34-rc-3", + "version": "0.20.34-rc-4", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index a13096a..1280d2c 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -341,7 +341,10 @@ async function payFeeToMatcher( calls: BytesLike[], swapDescription: LibValidator.SwapDescriptionStruct, ) { - + console.log(matcher) + console.log(feeAmount) + console.log(feeToken) + console.log(swapDescription.dstToken) if (BigInt(feeAmount) !== 0n && feeToken === swapDescription.dstToken) { const feePaymentCall = generateFeePaymentCall(matcher, feeToken, feeAmount) calls.push(feePaymentCall) From 7672b9daf825864a5d14fa3290cfcc4aef4454e9 Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 13:10:08 +0400 Subject: [PATCH 09/10] transform all addresses to lower case --- package.json | 2 +- src/Unit/Exchange/generateSwapCalldata.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 0b27452..577e05f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34-rc-4", + "version": "0.20.34-rc-5", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index 1280d2c..c46f648 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -79,8 +79,10 @@ export async function generateSwapCalldataWithUnit({ let path = SafeArray.from(arrayLikePathCopy); path = SafeArray.from(arrayLikePathCopy).map((swapInfo) => { - swapInfo.assetIn = assetToAddress[swapInfo.assetIn] ?? swapInfo.assetIn.toLowerCase(); - swapInfo.assetOut = assetToAddress[swapInfo.assetOut] ?? swapInfo.assetOut.toLowerCase(); + swapInfo.assetIn = assetToAddress[swapInfo.assetIn] ?? swapInfo.assetIn + swapInfo.assetOut = assetToAddress[swapInfo.assetOut] ?? swapInfo.assetOut + swapInfo.assetIn = swapInfo.assetIn.toLowerCase() + swapInfo.assetOut = swapInfo.assetOut.toLowerCase() return swapInfo; }); From a0bed6b5b60a8badf482c0b74a50f5fc082a41a2 Mon Sep 17 00:00:00 2001 From: Steam Deck User <0xlomonoshka@gmail.com> Date: Mon, 18 Dec 2023 13:38:09 +0400 Subject: [PATCH 10/10] transform all addresses to lower case x2 --- package.json | 2 +- src/Unit/Exchange/generateSwapCalldata.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 577e05f..8051bf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.20.34-rc-5", + "version": "0.20.34-rc-6", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Unit/Exchange/generateSwapCalldata.ts b/src/Unit/Exchange/generateSwapCalldata.ts index c46f648..f0ac04c 100644 --- a/src/Unit/Exchange/generateSwapCalldata.ts +++ b/src/Unit/Exchange/generateSwapCalldata.ts @@ -127,7 +127,11 @@ export async function generateSwapCalldata({ const swapExecutorContractAddress = await addressLikeToString(swapExecutorContractAddressLike); const feeToken = await addressLikeToString(feeTokenAddressLike); const matcher = await addressLikeToString(matcherAddressLike); - let path = SafeArray.from(arrayLikePath); + let path = SafeArray.from(arrayLikePath).map((swapInfo) => { + swapInfo.assetIn = swapInfo.assetIn.toLowerCase() + swapInfo.assetOut = swapInfo.assetOut.toLowerCase() + return swapInfo; + }); const { assetIn: srcToken } = path.first(); const { assetOut: dstToken } = path.last();