From 0b049c67d579bfce1fb6c567c2f41f6ebdf8f3ad Mon Sep 17 00:00:00 2001 From: tommyzhao451 Date: Fri, 9 Aug 2024 16:14:39 -0700 Subject: [PATCH] refactor fee constants into SDK --- package.json | 2 +- src/viem/aggregator/optimalRebalanceV2.ts | 16 ++++---- src/viem/automan/getFees.ts | 49 ++++++++++++++--------- src/viem/transaction/getReinvestTx.ts | 4 +- test/jest/fees.test.ts | 32 +++++++++------ 5 files changed, 62 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index b3f02178..da4a87a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@aperture_finance/uniswap-v3-automation-sdk", - "version": "3.4.22-fees1", + "version": "3.4.22-fees2", "description": "SDK for Aperture's Uniswap V3 automation platform", "author": "Aperture Finance ", "license": "MIT", diff --git a/src/viem/aggregator/optimalRebalanceV2.ts b/src/viem/aggregator/optimalRebalanceV2.ts index 1530fef2..bfd79321 100644 --- a/src/viem/aggregator/optimalRebalanceV2.ts +++ b/src/viem/aggregator/optimalRebalanceV2.ts @@ -9,6 +9,11 @@ import { simulateRebalance, simulateRemoveLiquidity, } from '../automan'; +import { + FEE_REBALANCE_SWAP_RATIO, + FEE_REBALANCE_USD, + MAX_FEE_PIPS, +} from '../automan/getFees'; import { PositionDetails } from '../position'; import { ALL_SOLVERS, E_Solver, getSolver } from '../solver'; import { @@ -20,9 +25,6 @@ import { } from './internal'; import { SolverResult } from './types'; -const feeRatio = 0.0007; // 0.07% fee -const feeCoefficient = 1e18; - /** * Get the optimal amount of liquidity to rebalance for a given position. * @param chainId The chain ID. @@ -116,12 +118,12 @@ export async function optimalRebalanceV2( ? position.pool.token0.decimals : position.pool.token1.decimals; - // swap token value * 0.0007 + 0.15 + // swapTokenValue * FEE_REBALANCE_SWAP_RATIO + FEE_REBALANCE_USD const feeUSD = new Big(poolAmountIn.toString()) .div(10 ** decimals) .mul(tokenInPrice) - .mul(feeRatio) - .add(0.15); + .mul(FEE_REBALANCE_SWAP_RATIO) + .add(FEE_REBALANCE_USD); const token0USD = new Big(receive0.toString()) .mul(tokenPrices[0]) @@ -152,7 +154,7 @@ export async function optimalRebalanceV2( } return { - feeBips: BigInt(feeUSD.div(positionUSD).mul(feeCoefficient).toFixed(0)), + feeBips: BigInt(feeUSD.div(positionUSD).mul(MAX_FEE_PIPS).toFixed(0)), feeUSD: feeUSD.toFixed(5), }; }; diff --git a/src/viem/automan/getFees.ts b/src/viem/automan/getFees.ts index 75f979ff..baa2e170 100644 --- a/src/viem/automan/getFees.ts +++ b/src/viem/automan/getFees.ts @@ -4,22 +4,33 @@ import { CurrencyAmount } from '@uniswap/smart-order-router'; import { CollectableTokenAmounts } from '../position'; export const MAX_FEE_PIPS = 1e18; +export const FEE_REBALANCE_USD = parseFloat( + // Flat fee for rebalancing. + process.env.FEE_REBALANCE_USD || '0.15', +); +export const FEE_REBALANCE_SWAP_RATIO = parseFloat( + // Fees on the swap amount for rebalancing. + process.env.FEE_REBALANCE_SWAP_RATIO || '0.0015', +); +export const FEE_SWAP_RATIO = parseFloat( + // Fees on the swap amount. + process.env.FEE_SWAP_RATIO || '0.0025', +); +const FEE_REINVEST_RATIO = JSON.parse( + // Fees on the reinvest amount, included in autocompound and rebalance. + process.env.FEE_REINVEST_RATIO || + '{"100": 0.0007, "500": 0.001, "2500": 0.0013, "3000": 0.0013, "10000": 0.0015}', +); +const FEE_DEFAULT_REINVEST_RATIO = parseFloat( + // Default fee on the reinvest amount if FeeAmount not found, such as for slipstream. + process.env.FEE_DEFAULT_REINVEST_RATIO || '0.001', +); -const POOL_FEE_TO_APTR_FEE: { - [key in FeeAmount]: number; -} = { - [FeeAmount.LOWEST]: 0.0007, - [FeeAmount.LOW]: 0.001, - [FeeAmount.PCS_V3_MEDIUM]: 0.0013, - [FeeAmount.MEDIUM]: 0.0013, - [FeeAmount.HIGH]: 0.0015, -}; - -export function getAptrFeesOnLpFees(feeAmount: FeeAmount) { - return POOL_FEE_TO_APTR_FEE[feeAmount] || 0.001; +export function getFeeReinvestRatio(feeAmount: FeeAmount) { + return FEE_REINVEST_RATIO[feeAmount] || FEE_DEFAULT_REINVEST_RATIO; } -function getFeeBipsFromSpecificToken( +function getFeeReinvestBipsFromSpecificToken( principalAmount: CurrencyAmount, collectableTokenAmount: CurrencyAmount, feeAmount: FeeAmount, @@ -31,7 +42,7 @@ function getFeeBipsFromSpecificToken( // so multiply by MAX_FEE_PIPS to charge the correct fee ratio. .multiply(MAX_FEE_PIPS) .multiply( - getAptrFeesOnLpFees(feeAmount) * + getFeeReinvestRatio(feeAmount) * 10 ** principalAmount.currency.decimals, ) // Cancel out the decimals between the feesCollects and principal. .divide(principalAmount) @@ -44,7 +55,7 @@ function getFeeBipsFromSpecificToken( : BigInt(MAX_FEE_PIPS); } -export function getFeeBips( +export function getFeeReinvestBips( position: Position, collectableTokenAmounts: CollectableTokenAmounts, ): bigint { @@ -54,25 +65,25 @@ export function getFeeBips( if (principalAmount1.equalTo(0)) { return 0n; } - return getFeeBipsFromSpecificToken( + return getFeeReinvestBipsFromSpecificToken( principalAmount1, collectableTokenAmounts.token1Amount, position.pool.fee, ); } if (principalAmount1.equalTo(0)) { - return getFeeBipsFromSpecificToken( + return getFeeReinvestBipsFromSpecificToken( principalAmount0, collectableTokenAmounts.token0Amount, position.pool.fee, ); } - const feeBips0 = getFeeBipsFromSpecificToken( + const feeBips0 = getFeeReinvestBipsFromSpecificToken( principalAmount0, collectableTokenAmounts.token0Amount, position.pool.fee, ); - const feeBips1 = getFeeBipsFromSpecificToken( + const feeBips1 = getFeeReinvestBipsFromSpecificToken( principalAmount1, collectableTokenAmounts.token1Amount, position.pool.fee, diff --git a/src/viem/transaction/getReinvestTx.ts b/src/viem/transaction/getReinvestTx.ts index 570500a7..742c058c 100644 --- a/src/viem/transaction/getReinvestTx.ts +++ b/src/viem/transaction/getReinvestTx.ts @@ -4,7 +4,7 @@ import { AutomatedMarketMakerEnum } from 'aperture-lens/dist/src/viem'; import { Address, PublicClient, TransactionRequest } from 'viem'; import { getAutomanReinvestCalldata } from '../automan'; -import { getFeeBips } from '../automan/getFees'; +import { getFeeReinvestBips } from '../automan/getFees'; import { PositionDetails, viewCollectableTokenAmounts } from '../position'; import { getAmountsWithSlippage } from './transaction'; import { SimulatedAmounts } from './types'; @@ -38,7 +38,7 @@ export async function getReinvestTx( await PositionDetails.fromPositionId(chainId, amm, positionId, client); const { apertureAutoman } = getAMMInfo(chainId, amm)!; - const feeBips = getFeeBips( + const feeBips = getFeeReinvestBips( position, await viewCollectableTokenAmounts(chainId, amm, positionId, client), ); diff --git a/test/jest/fees.test.ts b/test/jest/fees.test.ts index 016d90a8..a4438b52 100644 --- a/test/jest/fees.test.ts +++ b/test/jest/fees.test.ts @@ -9,7 +9,10 @@ import JSBI from 'jsbi'; import { ApertureSupportedChainId, getChainInfo } from '../../src'; import { getPool, getPublicClient } from '../../src/viem'; -import { MAX_FEE_PIPS, getFeeBips } from '../../src/viem/automan/getFees'; +import { + MAX_FEE_PIPS, + getFeeReinvestBips, +} from '../../src/viem/automan/getFees'; import { CollectableTokenAmounts } from '../../src/viem/position'; dotenvConfig(); @@ -63,10 +66,12 @@ describe('getFeeBips', () => { '0.000456', ); // feeBips = min(lpCollectsFeesToken0 * rate / pricipalToken0, lpCollectsFeesToken0 * rate / pricipalToken0) * 1e18 - // feeBips = min(0.000000000000000123 * getAptrFeesOnLpFees(FeeAmount.LOW) / 0.000000017476, 0.000456 * getAptrFeesOnLpFees(FeeAmount.LOW) / 0.000057) * 1e18 + // feeBips = min(0.000000000000000123 * getFeeReinvestRatio(FeeAmount.LOW) / 0.000000017476, 0.000456 * getFeeReinvestRatio(FeeAmount.LOW) / 0.000057) * 1e18 // feeBips = min(0.000000000000000123 * 0.001 / 0.000000017476, 0.000456 * 0.001 / 0.000057) * 1e18 // feeBips = min(7.038e-12, 8.0e-3) * 1e18 = 7.038e-12 * 1e18 = 7.038e6 - expect(getFeeBips(position, collectableTokenAmounts)).toBe(7038190n); + expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe( + 7038190n, + ); // Test less feesBips on token1. collectableTokenAmounts = { @@ -80,10 +85,10 @@ describe('getFeeBips', () => { '0.000456', ); // feeBips = min(lpCollectsFeesToken0 * rate / pricipalToken0, lpCollectsFeesToken0 * rate / pricipalToken0) * 1e18 - // feeBips = min(0.123456789123456789 * getAptrFeesOnLpFees(FeeAmount.LOW) / 0.000000017476, 0.000001 * getAptrFeesOnLpFees(FeeAmount.LOW) / 0.000057) * 1e18 + // feeBips = min(0.123456789123456789 * getFeeReinvestRatio(FeeAmount.LOW) / 0.000000017476, 0.000001 * getFeeReinvestRatio(FeeAmount.LOW) / 0.000057) * 1e18 // feeBips = min(0.123456789123456789 * 0.001 / 0.000000017476, 0.000456 * 0.001 / 0.000057) * 1e18 // feeBips = min(7064, 0.008) * 1e18 = 0.008 * 1e18 = 8e15 - expect(getFeeBips(position, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe( 8000000000000000n, ); @@ -96,7 +101,7 @@ describe('getFeeBips', () => { expect(collectableTokenAmounts.token0Amount.toSignificant()).toBe( '0.000000139808', ); - expect(getFeeBips(position, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe( 7999962480377385n, ); @@ -108,7 +113,7 @@ describe('getFeeBips', () => { expect(collectableTokenAmounts.token0Amount.toSignificant()).toBe( '0.000000139808', ); - expect(getFeeBips(position, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe( 8000000000000000n, ); }); @@ -141,7 +146,10 @@ describe('getFeeBips', () => { }); expect(positionLowFee.amount0.toSignificant()).toBe('0.0000000174754'); expect(positionLowFee.amount1.toSignificant()).toBe('0.000057'); - const lowFeeBips = getFeeBips(positionLowFee, collectableTokenAmounts); + const lowFeeBips = getFeeReinvestBips( + positionLowFee, + collectableTokenAmounts, + ); // feeBips = min(lpCollectsFeesToken0 * rate / pricipalToken0, lpCollectsFeesToken0 * rate / pricipalToken0) * 1e18 // feeBips = min(0.000000000000000123 * 0.0007 * 1e18 / 0.0000000174754, 0.000456 * 0.0007 * 1e18 / 0.000057) // feeBips = min(4926913, 5.6e15) = 4926913 @@ -166,7 +174,7 @@ describe('getFeeBips', () => { // feeBips = min(lpCollectsFeesToken0 * rate / pricipalToken0, lpCollectsFeesToken0 * rate / pricipalToken0) * 1e18 // feeBips = min(0.000000000000000123 * 0.0015 * 1e18 / 0.0000000174754, 0.000456 * 0.0015 * 1e18 / 0.000057) // feeBips = min(10546013, 5.1.2e16) = 4926913 - expect(getFeeBips(positionHighFee, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(positionHighFee, collectableTokenAmounts)).toBe( 10546013n, ); }); @@ -207,7 +215,7 @@ describe('getFeeBips', () => { expect(token1Position.amount0.toSignificant()).toBe('0'); expect(token1Position.amount1.toSignificant()).toBe('54.3777'); // 0.000456 * 0.001 * 1e18 / 54.3777 = 8385785255 - expect(getFeeBips(token1Position, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(token1Position, collectableTokenAmounts)).toBe( 8385785255n, ); @@ -220,7 +228,7 @@ describe('getFeeBips', () => { expect(token0Position.amount0.toSignificant()).toBe('0.00000000000000007'); expect(token0Position.amount1.toSignificant()).toBe('0'); // 0.000000000000000123 * 0.001 * 1e18 / 0.00000000000000007 = 1.757e15 - expect(getFeeBips(token0Position, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(token0Position, collectableTokenAmounts)).toBe( 1757142857142857n, ); }); @@ -264,7 +272,7 @@ describe('getFeeBips', () => { // feeBips = min(lpCollectsFeesToken0 * rate / pricipalToken0, lpCollectsFeesToken0 * rate / pricipalToken0) * 1e18 // feeBips = min(999999 * 0.001 * 1e18 / 0.0000000174754, 1000000 * 0.001 * 1e18 / 0.000057) // feeBips = min(5.7e28, 1.754e25) = 1.754e25 - expect(getFeeBips(position, collectableTokenAmounts)).toBe( + expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe( BigInt(MAX_FEE_PIPS), ); });