Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bigz/perp-funding-offset #576

Merged
merged 9 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions programs/drift/src/controller/funding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use crate::error::DriftResult;
use crate::get_then_update_id;
use crate::math::amm;
use crate::math::casting::Cast;
use crate::math::constants::{FUNDING_RATE_BUFFER, ONE_HOUR_I128, TWENTY_FOUR_HOUR};
use crate::math::constants::{
FUNDING_RATE_BUFFER, FUNDING_RATE_OFFSET_DENOMINATOR, ONE_HOUR_I128, TWENTY_FOUR_HOUR,
};
use crate::math::funding::{calculate_funding_payment, calculate_funding_rate_long_short};
use crate::math::helpers::on_the_hour_update;
use crate::math::safe_math::SafeMath;
Expand Down Expand Up @@ -217,9 +219,19 @@ pub fn update_funding_rate(
// low periodicity => quickly updating/settled funding rates => lower funding rate payment per interval
let price_spread = mid_price_twap.cast::<i64>()?.safe_sub(oracle_price_twap)?;

// add offset 1/FUNDING_RATE_OFFSET_DENOMINATOR*365. if FUNDING_RATE_OFFSET_DENOMINATOR = 5000 => 7.3% annualized rate
let price_spread_with_offset = price_spread.safe_add(
oracle_price_twap
.abs()
.safe_div(FUNDING_RATE_OFFSET_DENOMINATOR)?,
)?;

// clamp price divergence to 3% for funding rate calculation
let max_price_spread = oracle_price_twap.safe_div(33)?; // 3%
let clamped_price_spread = max(-max_price_spread, min(price_spread, max_price_spread));
let clamped_price_spread = max(
0xbigz marked this conversation as resolved.
Show resolved Hide resolved
-max_price_spread,
min(price_spread_with_offset, max_price_spread),
);

let funding_rate = clamped_price_spread
.cast::<i128>()?
Expand Down
3 changes: 3 additions & 0 deletions programs/drift/src/math/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ pub const DEFAULT_BASE_ASSET_AMOUNT_STEP_SIZE: u64 = BASE_PRECISION_U64 / 10000;
pub const DEFAULT_QUOTE_ASSET_AMOUNT_TICK_SIZE: u64 =
PRICE_PRECISION_U64 / DEFAULT_BASE_ASSET_AMOUNT_STEP_SIZE; // 1e-2

// FUNDING
pub const FUNDING_RATE_OFFSET_DENOMINATOR: i64 = 5000; // 5000 => 7.3% annualized rate for hourly funding

// ORDERS
pub const AUCTION_DERIVE_PRICE_FRACTION: i64 = 200;

Expand Down
1 change: 1 addition & 0 deletions sdk/src/constants/numericConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const AMM_TIMES_PEG_TO_QUOTE_PRECISION_RATIO =
export const MARGIN_PRECISION = TEN_THOUSAND;
export const BID_ASK_SPREAD_PRECISION = new BN(1000000); // 10^6
export const LIQUIDATION_PCT_PRECISION = TEN_THOUSAND;
export const FUNDING_RATE_OFFSET_DENOMINATOR = new BN(5000);

export const FIVE_MINUTE = new BN(60 * 5);
export const ONE_HOUR = new BN(60 * 60);
Expand Down
7 changes: 6 additions & 1 deletion sdk/src/math/funding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
QUOTE_PRECISION,
ZERO,
ONE,
FUNDING_RATE_OFFSET_DENOMINATOR,
} from '../constants/numericConstants';
import { PerpMarketAccount, isVariant } from '../types';
import { OraclePriceData } from '../oracles/types';
Expand Down Expand Up @@ -156,7 +157,11 @@ export async function calculateAllEstimatedFundingRate(
// }

const twapSpread = markTwap.sub(oracleTwap);
const twapSpreadPct = twapSpread
const twapSpreadWithOffset = twapSpread.add(
BN.abs(oracleTwap).div(FUNDING_RATE_OFFSET_DENOMINATOR)
);

const twapSpreadPct = twapSpreadWithOffset
.mul(PRICE_PRECISION)
.mul(new BN(100))
.div(oracleTwap);
Expand Down
5 changes: 4 additions & 1 deletion test-scripts/single-anchor-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ if [ "$1" != "--skip-build" ]
cp target/idl/drift.json sdk/src/idl/
fi

test_files=(prepegMarketOrderBaseAssetAmount.ts)
test_files=(liquidityProvider.ts)
test_files=(spotSwap.ts)
test_files=(cappedSymFunding.ts)
test_files=(liquidateBorrowForPerpPnl.ts)

for test_file in ${test_files[@]}; do
ANCHOR_TEST_FILE=${test_file} anchor test --skip-build || exit 1;
Expand Down
29 changes: 22 additions & 7 deletions tests/delistMarket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ describe('delist market', () => {

await driftClient.fetchAccounts();
const perpMarket = await driftClient.getPerpMarketAccount(marketIndex);
console.log(perpMarket.amm.cumulativeFundingRateLong.toString());
// console.log(perpMarket.amm.cumulativeFundingRateLong.toString());
assert(!perpMarket.amm.cumulativeFundingRateLong.eq(ZERO));

await liquidatorDriftClient.addPerpLpShares(BASE_PRECISION, marketIndex);
Expand Down Expand Up @@ -583,11 +583,26 @@ describe('delist market', () => {
assert(loserUser.perpPositions[0].quoteAssetAmount.eq(new BN(0)));
const marketAfter0 = driftClient.getPerpMarketAccount(marketIndex);

const finalPnlResultMin0 = new BN(1000021789000 - 100090);
const finalPnlResultMin0 = new BN(1000020719000 - 100090);
console.log(marketAfter0.pnlPool.scaledBalance.toString());
console.log(marketAfter0.pnlPool.scaledBalance.toString());
console.log(marketAfter0.pnlPool.scaledBalance.toString());

// console.log(
// 'lastFundingRateLong:',
// marketAfter0.amm.lastFundingRateLong.toString()
// );
// console.log(
// 'lastFundingRateShort:',
// marketAfter0.amm.lastFundingRateShort.toString()
// );

assert(marketAfter0.amm.lastFundingRateLong.toString() === '24205208');
assert(marketAfter0.amm.lastFundingRateShort.toString() === '24205208');

assert(marketAfter0.pnlPool.scaledBalance.gt(finalPnlResultMin0));
assert(
marketAfter0.pnlPool.scaledBalance.lt(new BN(1000021789000 + 1000000))
marketAfter0.pnlPool.scaledBalance.lt(new BN(1000020719000 + 1000000))
);

const txSig2 = await driftClient.settlePNL(
Expand All @@ -610,10 +625,10 @@ describe('delist market', () => {

const marketAfter = driftClient.getPerpMarketAccount(marketIndex);

const finalPnlResultMin = new BN(969700933000 - 109000);
const finalPnlResultMin = new BN(969699125000 - 109000);
console.log('pnlPool:', marketAfter.pnlPool.scaledBalance.toString());
assert(marketAfter.pnlPool.scaledBalance.gt(finalPnlResultMin));
assert(marketAfter.pnlPool.scaledBalance.lt(new BN(969700933000 + 109000)));
assert(marketAfter.pnlPool.scaledBalance.lt(new BN(969699125000 + 109000)));

console.log('feePool:', marketAfter.amm.feePool.scaledBalance.toString());
console.log(
Expand Down Expand Up @@ -684,10 +699,10 @@ describe('delist market', () => {
console.log(usdcMarket.revenuePool.scaledBalance.toString());
assert(usdcMarket.revenuePool.scaledBalance.gt(ZERO));
assert(
usdcMarket.revenuePool.scaledBalance.gt(new BN(969765629000 - 100000))
usdcMarket.revenuePool.scaledBalance.gt(new BN(969763827000 - 100000))
);
assert(
usdcMarket.revenuePool.scaledBalance.lt(new BN(969765629000 + 100000))
usdcMarket.revenuePool.scaledBalance.lt(new BN(969763827000 + 100000))
);

console.log('works');
Expand Down
25 changes: 21 additions & 4 deletions tests/imbalancePerpPnl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -757,14 +757,30 @@ describe('imbalanced large perp pnl w/ borrow hitting limits', () => {
market0.marketIndex
);
oraclePriceData0.confidence = new BN(0); //oraclePriceData0.price.div(new BN(1000));
console.log(
'market0.amm.totalFeeMinusDistributions:',
market0.amm.totalFeeMinusDistributions.toString()
);
assert(market0.amm.totalFeeMinusDistributions.lt(new BN('0')));

// assert(market0.amm.totalFeeMinusDistributions.eq(new BN('254313115')));
const prepegAMM = calculateUpdatedAMM(market0.amm, oraclePriceData0);
const [bid, ask] = examineSpread(market0, oraclePriceData0);
console.log(
'prepegAMM.totalFeeMinusDistributions:',
prepegAMM.totalFeeMinusDistributions.toString()
);
assert(
prepegAMM.totalFeeMinusDistributions.eq(
market0.amm.totalFeeMinusDistributions
)
);

console.log(prepegAMM.pegMultiplier.toString());
console.log(bid.toString());
console.log(ask.toString());
assert(bid.eq(new BN('254194105')));
assert(prepegAMM.pegMultiplier.eq(new BN('254313115')));
assert(prepegAMM.pegMultiplier.eq(new BN('254313114'))); // lowered by 1 for funding offset change
assert(oraclePriceData0.price.eq(new BN('260500000')));
assert(ask.eq(new BN('266567441')));

Expand Down Expand Up @@ -794,7 +810,7 @@ describe('imbalanced large perp pnl w/ borrow hitting limits', () => {
);
const prepegAMM1 = calculateUpdatedAMM(market0.amm, oraclePriceData1);
console.log(prepegAMM1.pegMultiplier.toString());
assert(prepegAMM1.pegMultiplier.eq(new BN(254313115)));
assert(prepegAMM1.pegMultiplier.eq(new BN(254313114))); // lower by 1 for funding offset change
});

it('resolvePerpPnlDeficit', async () => {
Expand Down Expand Up @@ -890,8 +906,9 @@ describe('imbalanced large perp pnl w/ borrow hitting limits', () => {
);

console.log('pnlimbalance:', imbalance.toString());
assert(imbalance.lt(new BN(43454561797 + 20000))); //44k still :o
assert(imbalance.gt(new BN(43454561797 - 20000))); //44k still :o
const expectedOffset = 43454489193; // used to be 43454561797
assert(imbalance.lt(new BN(expectedOffset + 20000))); //44k still :o
assert(imbalance.gt(new BN(expectedOffset - 20000))); //44k still :o

console.log(
'revenueWithdrawSinceLastSettle:',
Expand Down
3 changes: 2 additions & 1 deletion tests/liquidateBorrowForPerpPnl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,13 @@ describe('liquidate borrow for perp pnl', () => {
await driftClient.updateInitialPctToLiquidate(
LIQUIDATION_PCT_PRECISION.toNumber()
);
// await driftClient.updateLiquidationDuration(1);

await initializeQuoteSpotMarket(driftClient, usdcMint.publicKey);
await initializeSolSpotMarket(driftClient, solOracle);
await driftClient.updatePerpAuctionDuration(new BN(0));

const periodicity = new BN(0);
const periodicity = new BN(3600);

await driftClient.initializePerpMarket(
0,
Expand Down