@@ -3,13 +3,11 @@ pragma solidity ^0.8.20;
33
44import { IFeePolicy } from "./_interfaces/IFeePolicy.sol " ;
55import { SubscriptionParams } from "./_interfaces/CommonTypes.sol " ;
6- import { InvalidPerc, InvalidTargetSRBounds, InvalidDRBounds, InvalidSigmoidAsymptotes } from "./_interfaces/ProtocolErrors.sol " ;
6+ import { InvalidPerc, InvalidTargetSRBounds, InvalidDRBounds } from "./_interfaces/ProtocolErrors.sol " ;
77
88import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol " ;
99import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol " ;
1010import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol " ;
11- import { Sigmoid } from "./_utils/Sigmoid.sol " ;
12-
1311/**
1412 * @title FeePolicy
1513 *
@@ -39,8 +37,7 @@ import { Sigmoid } from "./_utils/Sigmoid.sol";
3937 *
4038 *
4139 * The rollover fees are signed and can flow in either direction based on the `deviationRatio`.
42- * The fee is a percentage is computed through a sigmoid function.
43- * The slope and asymptotes are set by the owner.
40+ * The fee function parameters are set by the owner.
4441 *
4542 * CRITICAL: The rollover fee percentage is NOT annualized, the fee percentage is applied per rollover.
4643 * The number of rollovers per year changes based on the duration of perp's minting bond.
@@ -54,6 +51,7 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
5451 // Libraries
5552 using MathUpgradeable for uint256 ;
5653 using SafeCastUpgradeable for uint256 ;
54+ using SafeCastUpgradeable for int256 ;
5755
5856 // Replicating value used here:
5957 // https://github.com/buttonwood-protocol/tranche/blob/main/contracts/BondController.sol
@@ -67,10 +65,6 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
6765 /// @notice Fixed point representation of 1.0 or 100%.
6866 uint256 public constant ONE = (1 * 10 ** DECIMALS);
6967
70- /// @notice Sigmoid asymptote bound.
71- /// @dev Set to 0.05 or 5%, i.e) the rollover fee can be at most 5% on either direction.
72- uint256 public constant SIGMOID_BOUND = ONE / 20 ;
73-
7468 /// @notice Target subscription ratio lower bound, 0.75 or 75%.
7569 uint256 public constant TARGET_SR_LOWER_BOUND = (ONE * 75 ) / 100 ;
7670
@@ -100,17 +94,28 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
10094 /// @notice The percentage fee charged on burning perp tokens.
10195 uint256 public perpBurnFeePerc;
10296
103- struct RolloverFeeSigmoidParams {
104- /// @notice Lower asymptote
105- int256 lower;
106- /// @notice Upper asymptote
107- int256 upper;
108- /// @notice sigmoid slope
109- int256 growth;
97+ /// @dev NOTE: We updated the type of the parameters from int256 to uint256, which is an upgrade safe operation.
98+ struct RolloverFeeParams {
99+ /// @notice The maximum debasement rate for perp,
100+ /// i.e) the maximum rate perp pays the vault for rollovers.
101+ /// @dev This is represented as fixed point number with {DECIMALS} places.
102+ /// For example, setting this to (0.1 / 13), would mean that the yearly perp debasement rate is capped at ~10%.
103+ uint256 maxPerpDebasementPerc;
104+ /// @notice The slope of the linear fee curve when (dr <= 1).
105+ /// @dev This is represented as fixed point number with {DECIMALS} places.
106+ /// Setting it to (1.0 / 13), would mean that it would take 1 year for dr to increase to 1.0.
107+ /// (assuming no other changes to the system)
108+ uint256 m1;
109+ /// @notice The slope of the linear fee curve when (dr > 1).
110+ /// @dev This is represented as fixed point number with {DECIMALS} places.
111+ /// Setting it to (1.0 / 13), would mean that it would take 1 year for dr to decrease to 1.0.
112+ /// (assuming no other changes to the system)
113+ uint256 m2;
110114 }
111115
112- /// @notice Parameters which control the asymptotes and the slope of the perp token's rollover fee.
113- RolloverFeeSigmoidParams public perpRolloverFee;
116+ /// @notice Parameters which control the perp rollover fee,
117+ /// i.e) the funding rate for holding perps.
118+ RolloverFeeParams public perpRolloverFee;
114119
115120 //-----------------------------------------------------------------------------
116121
@@ -151,9 +156,9 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
151156 vaultPerpToUnderlyingSwapFeePerc = ONE;
152157
153158 // NOTE: With the current bond length of 28 days, rollover rate is annualized by dividing by: 365/28 ~= 13
154- perpRolloverFee.lower = - int256 ( ONE) / (30 * 13 ); // -0.033 /13 = -0.00253 (3.3 % annualized)
155- perpRolloverFee.upper = int256 ( ONE) / (10 * 13 ); // 0.1/13 = 0.00769 (10% annualized)
156- perpRolloverFee.growth = 5 * int256 (ONE ); // 5.0
159+ perpRolloverFee.maxPerpDebasementPerc = ONE / (10 * 13 ); // 0.1 /13 = 0.0077 (10 % annualized)
160+ perpRolloverFee.m1 = ONE / (3 * 13 ); // 0.025
161+ perpRolloverFee.m2 = ONE / ( 3 * 13 ); // 0.025
157162
158163 targetSubscriptionRatio = (ONE * 133 ) / 100 ; // 1.33
159164 deviationRatioBoundLower = (ONE * 75 ) / 100 ; // 0.75
@@ -206,17 +211,11 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
206211 perpBurnFeePerc = perpBurnFeePerc_;
207212 }
208213
209- /// @notice Update the parameters determining the slope and asymptotes of the sigmoid fee curve.
210- /// @param p Lower, Upper and Growth sigmoid paramters are fixed point numbers with {DECIMALS} places.
211- function updatePerpRolloverFees (RolloverFeeSigmoidParams calldata p ) external onlyOwner {
212- // If the bond duration is 28 days and 13 rollovers happen per year,
213- // perp can be inflated or enriched up to ~65% annually.
214- if (p.lower < - int256 (SIGMOID_BOUND) || p.upper > int256 (SIGMOID_BOUND) || p.lower > p.upper) {
215- revert InvalidSigmoidAsymptotes ();
216- }
217- perpRolloverFee.lower = p.lower;
218- perpRolloverFee.upper = p.upper;
219- perpRolloverFee.growth = p.growth;
214+ /// @notice Update the parameters determining the rollover fee curve.
215+ /// @dev Back into the per-rollover percentage based on the bond duration, and thus number of rollovers per year.
216+ /// @param p Paramters are fixed point numbers with {DECIMALS} places.
217+ function updatePerpRolloverFees (RolloverFeeParams calldata p ) external onlyOwner {
218+ perpRolloverFee = p;
220219 }
221220
222221 /// @notice Updates the vault mint fee parameters.
@@ -274,14 +273,16 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
274273
275274 /// @inheritdoc IFeePolicy
276275 function computePerpRolloverFeePerc (uint256 dr ) external view override returns (int256 ) {
277- return
278- Sigmoid.compute (
279- dr.toInt256 (),
280- perpRolloverFee.lower,
281- perpRolloverFee.upper,
282- perpRolloverFee.growth,
283- ONE.toInt256 ()
276+ if (dr <= ONE) {
277+ uint256 negPerpRate = MathUpgradeable.min (
278+ perpRolloverFee.m1.mulDiv (ONE - dr, ONE),
279+ perpRolloverFee.maxPerpDebasementPerc
284280 );
281+ return - 1 * negPerpRate.toInt256 ();
282+ } else {
283+ uint256 perpRate = perpRolloverFee.m2.mulDiv (dr - ONE, ONE);
284+ return perpRate.toInt256 ();
285+ }
285286 }
286287
287288 /// @inheritdoc IFeePolicy
0 commit comments