Skip to content

Commit

Permalink
refactor fee constants into SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
tommyzhao451 committed Aug 9, 2024
1 parent 6856f17 commit 0b049c6
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 41 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>",
"license": "MIT",
Expand Down
16 changes: 9 additions & 7 deletions src/viem/aggregator/optimalRebalanceV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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),
};
};
Expand Down
49 changes: 30 additions & 19 deletions src/viem/automan/getFees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)
Expand All @@ -44,7 +55,7 @@ function getFeeBipsFromSpecificToken(
: BigInt(MAX_FEE_PIPS);
}

export function getFeeBips(
export function getFeeReinvestBips(
position: Position,
collectableTokenAmounts: CollectableTokenAmounts,
): bigint {
Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/viem/transaction/getReinvestTx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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),
);
Expand Down
32 changes: 20 additions & 12 deletions test/jest/fees.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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 = {
Expand All @@ -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,
);

Expand All @@ -96,7 +101,7 @@ describe('getFeeBips', () => {
expect(collectableTokenAmounts.token0Amount.toSignificant()).toBe(
'0.000000139808',
);
expect(getFeeBips(position, collectableTokenAmounts)).toBe(
expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe(
7999962480377385n,
);

Expand All @@ -108,7 +113,7 @@ describe('getFeeBips', () => {
expect(collectableTokenAmounts.token0Amount.toSignificant()).toBe(
'0.000000139808',
);
expect(getFeeBips(position, collectableTokenAmounts)).toBe(
expect(getFeeReinvestBips(position, collectableTokenAmounts)).toBe(
8000000000000000n,
);
});
Expand Down Expand Up @@ -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
Expand All @@ -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,
);
});
Expand Down Expand Up @@ -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,
);

Expand All @@ -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,
);
});
Expand Down Expand Up @@ -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),
);
});
Expand Down

0 comments on commit 0b049c6

Please sign in to comment.