Skip to content

Commit

Permalink
Merge pull request #196 from ampleforth/dr-delta-fee
Browse files Browse the repository at this point in the history
Fee delta update
  • Loading branch information
aalavandhan authored Feb 26, 2024
2 parents f362edf + e6dc3ce commit eda092c
Show file tree
Hide file tree
Showing 5 changed files with 330 additions and 236 deletions.
76 changes: 55 additions & 21 deletions spot-contracts/contracts/FeePolicy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
//-----------------------------------------------------------------------------
// Vault fee parameters

/// @notice The fixed amount vault fee charged during each deployment.
/// @dev Denominated in the underlying collateral asset and
/// Paid by the vault note holders to the system owner.
uint256 public vaultDeploymentFee;

/// @notice The percentage fee charged on minting vault notes.
uint256 public vaultMintFeePerc;

Expand All @@ -123,11 +128,6 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
/// @notice The percentage fee charged by the vault to swap perp tokens for underlying tokens.
uint256 public vaultPerpToUnderlyingSwapFeePerc;

/// @notice The fixed amount vault fee charged during each deployment.
/// @dev Denominated in the underlying collateral asset and
/// Paid by the vault note holders to the system owner.
uint256 public vaultDeploymentFee;

//-----------------------------------------------------------------------------

/// @notice Contract initializer.
Expand Down Expand Up @@ -262,15 +262,15 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
// Public methods

/// @inheritdoc IFeePolicy
function computePerpMintFeePerc(uint256 dr) public view override returns (uint256) {
// When the system is under-subscribed we charge a perp mint fee.
return (dr <= ONE) ? perpMintFeePerc : 0;
/// @dev Minting perps reduces system dr, i.e) drPost < drPre.
function computePerpMintFeePerc(uint256 drPre, uint256 drPost) public view override returns (uint256) {
return _stepFnFeePerc(drPost, drPre, perpMintFeePerc, 0);
}

/// @inheritdoc IFeePolicy
function computePerpBurnFeePerc(uint256 dr) public view override returns (uint256) {
// When the system is over-subscribed we charge a perp redemption fee.
return (dr > ONE) ? perpBurnFeePerc : 0;
/// @dev Burning perps increases system dr, i.e) drPost > drPre.
function computePerpBurnFeePerc(uint256 drPre, uint256 drPost) public view override returns (uint256) {
return _stepFnFeePerc(drPre, drPost, 0, perpBurnFeePerc);
}

/// @inheritdoc IFeePolicy
Expand All @@ -286,13 +286,13 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
}

/// @inheritdoc IFeePolicy
function computeVaultMintFeePerc(uint256 dr) external view override returns (uint256) {
// When the system is over-subscribed the vault charges a mint fee.
return (dr > ONE) ? vaultMintFeePerc : 0;
/// @dev Minting vault notes increases system dr, i.e) drPost > drPre.
function computeVaultMintFeePerc(uint256 drPre, uint256 drPost) external view override returns (uint256) {
return _stepFnFeePerc(drPre, drPost, 0, vaultMintFeePerc);
}

/// @inheritdoc IFeePolicy
function computeVaultBurnFeePerc(uint256 /*dr*/) external view override returns (uint256) {
function computeVaultBurnFeePerc(uint256 /*drPre*/, uint256 /*drPost*/) external view override returns (uint256) {
return vaultBurnFeePerc;
}

Expand All @@ -302,15 +302,31 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
}

/// @inheritdoc IFeePolicy
function computeUnderlyingToPerpSwapFeePercs(uint256 dr) external view override returns (uint256, uint256) {
// When the deviation ratio is below the bound, swapping is disabled. (fees are set to 100%)
return (computePerpMintFeePerc(dr), (dr < deviationRatioBoundLower) ? ONE : vaultUnderlyingToPerpSwapFeePerc);
/// @dev Swapping by minting perps reduces system dr, i.e) drPost < drPre.
function computeUnderlyingToPerpSwapFeePercs(
uint256 drPre,
uint256 drPost
) external view override returns (uint256, uint256) {
// When the after op deviation ratio is below the bound,
// swapping is disabled. (fees are set to 100%)
return (
computePerpMintFeePerc(drPre, drPost),
(drPost < deviationRatioBoundLower ? ONE : vaultUnderlyingToPerpSwapFeePerc)
);
}

/// @inheritdoc IFeePolicy
function computePerpToUnderlyingSwapFeePercs(uint256 dr) external view override returns (uint256, uint256) {
// When the deviation ratio is above the bound, swapping is disabled. (fees are set to 100%)
return (computePerpBurnFeePerc(dr), (dr > deviationRatioBoundUpper) ? ONE : vaultPerpToUnderlyingSwapFeePerc);
/// @dev Swapping by burning perps increases system dr, i.e) drPost > drPre.
function computePerpToUnderlyingSwapFeePercs(
uint256 drPre,
uint256 drPost
) external view override returns (uint256, uint256) {
// When the after op deviation ratio is above the bound,
// swapping is disabled. (fees are set to 100%)
return (
computePerpBurnFeePerc(drPre, drPost),
(drPost > deviationRatioBoundUpper ? ONE : vaultPerpToUnderlyingSwapFeePerc)
);
}

/// @inheritdoc IFeePolicy
Expand All @@ -329,4 +345,22 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
uint256 juniorTR = TRANCHE_RATIO_GRANULARITY - seniorTR;
return (vaultTVL * seniorTR).mulDiv(ONE, (perpTVL * juniorTR)).mulDiv(ONE, targetSubscriptionRatio);
}

/// @dev Computes step function fee perc, with a dr cutoff at 1.0. Expects drL < drU.
function _stepFnFeePerc(uint256 drL, uint256 drU, uint256 f1, uint256 f2) private pure returns (uint256) {
// When drU is below the cutoff, we use f1.
if (drU <= ONE) {
return f1;
}
// When drL is above the cutoff, we use f2.
else if (drL > ONE) {
return f2;
}
// Otherwise we use f1 and f2 partially.
else {
uint256 deltaDR = drU - drL;
return (f1.mulDiv(ONE - drL, deltaDR, MathUpgradeable.Rounding.Up) +
f2.mulDiv(drU - ONE, deltaDR, MathUpgradeable.Rounding.Up));
}
}
}
8 changes: 2 additions & 6 deletions spot-contracts/contracts/PerpetualTranche.sol
Original file line number Diff line number Diff line change
Expand Up @@ -680,10 +680,9 @@ contract PerpetualTranche is
uint256 feePerc = 0;
uint256 perpTVL = 0;
if (!_isProtocolCaller()) {
// Minting more perps reduces the subscription ratio,
// We check the post-mint subscription state to account for fees accordingly.
SubscriptionParams memory s = _querySubscriptionState();
feePerc = feePolicy.computePerpMintFeePerc(
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(s.perpTVL + valueIn, s.vaultTVL, s.seniorTR)
);
perpTVL = s.perpTVL;
Expand Down Expand Up @@ -716,12 +715,9 @@ contract PerpetualTranche is
uint256 feePerc = 0;

if (!_isProtocolCaller()) {
// Burning perps increases the subscription ratio,
// We check the post-burn subscription state to account for fees accordingly.
// We calculate the perp post-burn TVL, by multiplying the current TVL by
// the fraction of supply remaining.
SubscriptionParams memory s = _querySubscriptionState();
feePerc = feePolicy.computePerpBurnFeePerc(
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(
s.perpTVL.mulDiv(perpSupply - perpAmtBurnt, perpSupply),
s.vaultTVL,
Expand Down
24 changes: 17 additions & 7 deletions spot-contracts/contracts/RolloverVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,10 @@ contract RolloverVault is
/// @inheritdoc IVault
function computeMintAmt(uint256 underlyingAmtIn) public returns (uint256) {
//-----------------------------------------------------------------------------
SubscriptionParams memory s = _querySubscriptionState(perp);
uint256 feePerc = feePolicy.computeVaultMintFeePerc(
feePolicy.computeDeviationRatio(_querySubscriptionState(perp))
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(s.perpTVL, s.vaultTVL + underlyingAmtIn, s.seniorTR)
);
//-----------------------------------------------------------------------------

Expand All @@ -540,14 +542,20 @@ contract RolloverVault is
}

/// @inheritdoc IVault
function computeRedemptionAmts(uint256 notes) public returns (TokenAmount[] memory) {
function computeRedemptionAmts(uint256 noteAmtBurnt) public returns (TokenAmount[] memory) {
uint256 noteSupply = totalSupply();

//-----------------------------------------------------------------------------
SubscriptionParams memory s = _querySubscriptionState(perp);
uint256 feePerc = feePolicy.computeVaultBurnFeePerc(
feePolicy.computeDeviationRatio(_querySubscriptionState(perp))
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(
s.perpTVL,
s.vaultTVL.mulDiv(noteSupply - noteAmtBurnt, noteSupply),
s.seniorTR
)
);
//-----------------------------------------------------------------------------

uint256 noteSupply = totalSupply();
uint8 assetCount_ = 1 + uint8(_deployed.length());

// aggregating vault assets to be redeemed
Expand All @@ -557,7 +565,7 @@ contract RolloverVault is
IERC20Upgradeable underlying_ = underlying;
redemptions[0] = TokenAmount({
token: underlying_,
amount: underlying_.balanceOf(address(this)).mulDiv(notes, noteSupply)
amount: underlying_.balanceOf(address(this)).mulDiv(noteAmtBurnt, noteSupply)
});
redemptions[0].amount = redemptions[0].amount.mulDiv(FEE_ONE - feePerc, FEE_ONE);

Expand All @@ -566,7 +574,7 @@ contract RolloverVault is
IERC20Upgradeable token = IERC20Upgradeable(_deployed.at(i - 1));
redemptions[i] = TokenAmount({
token: token,
amount: token.balanceOf(address(this)).mulDiv(notes, noteSupply)
amount: token.balanceOf(address(this)).mulDiv(noteAmtBurnt, noteSupply)
});

// deduct redemption fee
Expand Down Expand Up @@ -594,6 +602,7 @@ contract RolloverVault is
// When user swaps underlying for vault's perps -> perps are minted by the vault
// We thus compute fees based on the post-mint subscription state.
(uint256 perpFeePerc, uint256 vaultFeePerc) = feePolicy.computeUnderlyingToPerpSwapFeePercs(
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(s.perpTVL + underlyingAmtIn, s.vaultTVL, s.seniorTR)
);
//-----------------------------------------------------------------------------
Expand All @@ -620,6 +629,7 @@ contract RolloverVault is
// When user swaps perps for vault's underlying -> perps are redeemed by the vault
// We thus compute fees based on the post-burn subscription state.
(uint256 perpFeePerc, uint256 vaultFeePerc) = feePolicy.computePerpToUnderlyingSwapFeePercs(
feePolicy.computeDeviationRatio(s),
feePolicy.computeDeviationRatio(s.perpTVL - underlyingAmtOut, s.vaultTVL, s.seniorTR)
);
//-----------------------------------------------------------------------------
Expand Down
20 changes: 14 additions & 6 deletions spot-contracts/contracts/_interfaces/IFeePolicy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { SubscriptionParams } from "./CommonTypes.sol";

interface IFeePolicy {
/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return The percentage of the mint perp tokens to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computePerpMintFeePerc(uint256 dr) external view returns (uint256);
function computePerpMintFeePerc(uint256 dr, uint256 dr_) external view returns (uint256);

/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return The percentage of the burnt perp tokens to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computePerpBurnFeePerc(uint256 dr) external view returns (uint256);
function computePerpBurnFeePerc(uint256 dr, uint256 dr_) external view returns (uint256);

/// @param dr The current system deviation ratio.
/// @return The applied exchange rate adjustment between tranches into perp and
Expand All @@ -27,35 +29,41 @@ interface IFeePolicy {
function computePerpRolloverFeePerc(uint256 dr) external view returns (int256);

/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return The percentage of the mint vault note amount to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computeVaultMintFeePerc(uint256 dr) external view returns (uint256);
function computeVaultMintFeePerc(uint256 dr, uint256 dr_) external view returns (uint256);

/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return The percentage of the burnt vault note amount to be charged as fees,
/// as a fixed-point number with {DECIMALS} decimal places.
function computeVaultBurnFeePerc(uint256 dr) external view returns (uint256);
function computeVaultBurnFeePerc(uint256 dr, uint256 dr_) external view returns (uint256);

/// @return The fixed amount fee charged by the vault during each deployment,
/// denominated in the underlying collateral asset.
function computeVaultDeploymentFee() external view returns (uint256);

/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return perpFeePerc The percentage of perp tokens out to be charged as swap fees by perp,
/// as a fixed-point numbers with {DECIMALS} decimal places.
/// @return vaultFeePerc The percentage of perp tokens out to be charged as swap fees by the vault,
/// as a fixed-point numbers with {DECIMALS} decimal places.
function computeUnderlyingToPerpSwapFeePercs(
uint256 dr
uint256 dr,
uint256 dr_
) external view returns (uint256 perpFeePerc, uint256 vaultFeePerc);

/// @param dr The current system deviation ratio.
/// @param dr_ The deviation ratio of the system after the operation is complete.
/// @return perpFeePerc The percentage of underlying tokens out to be charged as swap fees by perp,
/// as a fixed-point numbers with {DECIMALS} decimal places.
/// @return vaultFeePerc The percentage of underlying tokens out to be charged as swap fees by the vault,
/// as a fixed-point numbers with {DECIMALS} decimal places.
function computePerpToUnderlyingSwapFeePercs(
uint256 dr
uint256 dr,
uint256 dr_
) external view returns (uint256 perpFeePerc, uint256 vaultFeePerc);

/// @return Number of decimals representing a multiplier of 1.0. So, 100% = 1*10**decimals.
Expand Down
Loading

0 comments on commit eda092c

Please sign in to comment.