Skip to content

Commit

Permalink
Merge pull request #192 from ampleforth/return-val
Browse files Browse the repository at this point in the history
Common types refactor
  • Loading branch information
aalavandhan authored Feb 3, 2024
2 parents ada8cc5 + 69c88bb commit 8bdfc1a
Show file tree
Hide file tree
Showing 15 changed files with 318 additions and 308 deletions.
5 changes: 4 additions & 1 deletion spot-contracts/contracts/BondIssuer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.19;

import { IBondFactory } from "./_interfaces/buttonwood/IBondFactory.sol";
import { IBondController } from "./_interfaces/buttonwood/IBondController.sol";
import { IBondIssuer, NoMaturedBonds } from "./_interfaces/IBondIssuer.sol";
import { IBondIssuer } from "./_interfaces/IBondIssuer.sol";

import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { EnumerableSetUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";
Expand All @@ -12,6 +12,9 @@ import { BondHelpers } from "./_utils/BondHelpers.sol";
/// @notice Expected tranche ratios to sum up to {TRANCHE_RATIO_GRANULARITY}.
error UnacceptableTrancheRatios();

/// @notice Expected at least one matured bond.
error NoMaturedBonds();

/**
* @title BondIssuer
*
Expand Down
7 changes: 4 additions & 3 deletions spot-contracts/contracts/FeePolicy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity ^0.8.19;

import { IFeePolicy } from "./_interfaces/IFeePolicy.sol";
import { SubscriptionParams } from "./_interfaces/CommonTypes.sol";

import { MathUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol";
import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
Expand Down Expand Up @@ -79,10 +80,10 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
uint256 public constant SR_UPPER_BOUND = 2 * ONE; // 2.0 or 200%

//-----------------------------------------------------------------------------
/// @notice The target subscription ratio i.e) the normalization factor.
/// @inheritdoc IFeePolicy
/// @dev The ratio under which the system is considered "under-subscribed".
/// Adds a safety buffer to ensure that rollovers are better sustained.
uint256 public targetSubscriptionRatio;
uint256 public override targetSubscriptionRatio;

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

Expand Down Expand Up @@ -311,7 +312,7 @@ contract FeePolicy is IFeePolicy, OwnableUpgradeable {
}

/// @inheritdoc IFeePolicy
function computeDeviationRatio(IFeePolicy.SubscriptionParams memory s) public view returns (uint256) {
function computeDeviationRatio(SubscriptionParams memory s) public view returns (uint256) {
return computeDeviationRatio(s.perpTVL, s.vaultTVL, s.seniorTR);
}

Expand Down
111 changes: 46 additions & 65 deletions spot-contracts/contracts/PerpetualTranche.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ pragma solidity ^0.8.19;

import { IERC20MetadataUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import { IERC20Upgradeable, IPerpetualTranche, IBondIssuer, IFeePolicy, IBondController, ITranche } from "./_interfaces/IPerpetualTranche.sol";
import { IVault } from "./_interfaces/IVault.sol";
import { UnauthorizedCall, UnauthorizedTransferOut, UnacceptableReference, UnexpectedDecimals, UnexpectedAsset, UnacceptableDeposit, UnacceptableRedemption, UnacceptableParams } from "./_interfaces/ProtocolErrors.sol";
import { IRolloverVault } from "./_interfaces/IRolloverVault.sol";
import { TokenAmount, RolloverData, SubscriptionParams } from "./_interfaces/CommonTypes.sol";
import { UnauthorizedCall, UnauthorizedTransferOut, UnacceptableReference, UnexpectedDecimals, UnexpectedAsset, UnacceptableDeposit, UnacceptableRedemption, UnacceptableParams, UnacceptableRollover, ExceededMaxSupply, ExceededMaxMintPerTranche } from "./_interfaces/ProtocolErrors.sol";

import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
Expand All @@ -18,15 +19,6 @@ import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/
import { BondHelpers } from "./_utils/BondHelpers.sol";
import { TrancheHelpers } from "./_utils/TrancheHelpers.sol";

/// @notice Expected rollover to be acceptable.
error UnacceptableRollover();

/// @notice Expected supply to be lower than the defined max supply.
error ExceededMaxSupply();

/// @notice Expected the total mint amount per tranche to be lower than the limit.
error ExceededMaxMintPerTranche();

/**
* @title PerpetualTranche
*
Expand Down Expand Up @@ -110,7 +102,7 @@ contract PerpetualTranche is

/// @notice Event emitted when the authorized rollover vault is updated.
/// @param vault The address of the rollover vault.
event UpdatedVault(address vault);
event UpdatedVault(IRolloverVault vault);

//-------------------------------------------------------------------------
// Perp Math Basics:
Expand Down Expand Up @@ -224,7 +216,7 @@ contract PerpetualTranche is
/// @notice Address of the authorized rollover vault.
/// @dev If this address is set, only the rollover vault can perform rollovers.
/// If not rollovers are publicly accessible.
address public vault;
IRolloverVault public override vault;

//--------------------------------------------------------------------------
// Modifiers
Expand All @@ -245,7 +237,7 @@ contract PerpetualTranche is

/// @dev Throws if called not called by vault.
modifier onlyVault() {
if (vault != _msgSender()) {
if (address(vault) != _msgSender()) {
revert UnauthorizedCall();
}
_;
Expand Down Expand Up @@ -311,7 +303,7 @@ contract PerpetualTranche is

/// @notice Updates the reference to the rollover vault.
/// @param newVault The address of the new vault.
function updateVault(address newVault) public onlyOwner {
function updateVault(IRolloverVault newVault) public onlyOwner {
if (address(newVault) == address(0)) {
revert UnacceptableReference();
}
Expand Down Expand Up @@ -427,7 +419,7 @@ contract PerpetualTranche is
nonReentrant
whenNotPaused
afterStateUpdate
returns (IERC20Upgradeable[] memory, uint256[] memory)
returns (TokenAmount[] memory)
{
// gets the current perp supply
uint256 perpSupply = totalSupply();
Expand All @@ -439,51 +431,35 @@ contract PerpetualTranche is

// Calculates the fee adjusted share of reserve tokens to be redeemed
// NOTE: This operation should precede any token transfers.
(IERC20Upgradeable[] memory tokensOuts, uint256[] memory tokenOutAmts) = _computeRedemptionAmts(
perpAmtBurnt,
perpSupply
);
TokenAmount[] memory tokensOut = _computeRedemptionAmts(perpAmtBurnt, perpSupply);

// burns perp tokens from the sender
_burn(msg.sender, perpAmtBurnt);

// transfers reserve tokens out
for (uint256 i = 0; i < tokensOuts.length; i++) {
if (tokenOutAmts[i] > 0) {
_transferOutOfReserve(msg.sender, tokensOuts[i], tokenOutAmts[i]);
for (uint256 i = 0; i < tokensOut.length; i++) {
if (tokensOut[i].amount > 0) {
_transferOutOfReserve(msg.sender, tokensOut[i].token, tokensOut[i].amount);
}
}

return (tokensOuts, tokenOutAmts);
return tokensOut;
}

/// @inheritdoc IPerpetualTranche
function rollover(
ITranche trancheIn,
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable
)
external
override
onlyVault
nonReentrant
whenNotPaused
afterStateUpdate
returns (IPerpetualTranche.RolloverData memory)
{
) external override onlyVault nonReentrant whenNotPaused afterStateUpdate returns (RolloverData memory) {
// verifies if rollover is acceptable
if (!_isAcceptableRollover(trancheIn, tokenOut)) {
revert UnacceptableRollover();
}

// Calculates the fee adjusted amount of tranches exchanged during a rolled over
// NOTE: This operation should precede any token transfers.
IPerpetualTranche.RolloverData memory r = _computeRolloverAmt(
trancheIn,
tokenOut,
trancheInAmtAvailable,
type(uint256).max
);
RolloverData memory r = _computeRolloverAmt(trancheIn, tokenOut, trancheInAmtAvailable, type(uint256).max);

// Verifies if rollover amount is acceptable
if (r.trancheInAmt <= 0 || r.tokenOutAmt <= 0) {
Expand Down Expand Up @@ -606,9 +582,13 @@ contract PerpetualTranche is
external
override
afterStateUpdate
returns (IERC20Upgradeable[] memory, uint256[] memory)
returns (TokenAmount[] memory)
{
return _computeRedemptionAmts(perpAmtBurnt, totalSupply());
uint256 perpSupply = totalSupply();
if (perpSupply == 0) {
revert UnacceptableRedemption();
}
return _computeRedemptionAmts(perpAmtBurnt, perpSupply);
}

/// @inheritdoc IPerpetualTranche
Expand All @@ -618,7 +598,7 @@ contract PerpetualTranche is
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable,
uint256 tokenOutAmtRequested
) external override afterStateUpdate returns (IPerpetualTranche.RolloverData memory) {
) external override afterStateUpdate returns (RolloverData memory) {
return _computeRolloverAmt(trancheIn, tokenOut, trancheInAmtAvailable, tokenOutAmtRequested);
}

Expand Down Expand Up @@ -761,7 +741,7 @@ contract PerpetualTranche is
if (!_isProtocolCaller()) {
// Minting more perps reduces the subscription ratio,
// We check the post-mint subscription state to account for fees accordingly.
IFeePolicy.SubscriptionParams memory s = _querySubscriptionState();
SubscriptionParams memory s = _querySubscriptionState();
feePerc = feePolicy.computePerpMintFeePerc(
feePolicy.computeDeviationRatio(s.perpTVL + valueIn, s.vaultTVL, s.seniorTR)
);
Expand Down Expand Up @@ -790,7 +770,7 @@ contract PerpetualTranche is
function _computeRedemptionAmts(uint256 perpAmtBurnt, uint256 perpSupply)
private
view
returns (IERC20Upgradeable[] memory, uint256[] memory)
returns (TokenAmount[] memory)
{
//-----------------------------------------------------------------------------
// We charge no burn fee when interacting with other parts of the system.
Expand All @@ -801,7 +781,7 @@ contract PerpetualTranche is
// 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.
IFeePolicy.SubscriptionParams memory s = _querySubscriptionState();
SubscriptionParams memory s = _querySubscriptionState();
feePerc = (perpSupply > 0)
? feePolicy.computePerpBurnFeePerc(
feePolicy.computeDeviationRatio(
Expand All @@ -816,21 +796,20 @@ contract PerpetualTranche is

// Compute redemption amounts
uint256 reserveCount = _reserveCount();
IERC20Upgradeable[] memory reserveTokens = new IERC20Upgradeable[](reserveCount);
uint256[] memory redemptionAmts = new uint256[](reserveCount);
TokenAmount[] memory reserveTokens = new TokenAmount[](reserveCount);
for (uint256 i = 0; i < reserveCount; i++) {
reserveTokens[i] = _reserveAt(i);
redemptionAmts[i] = (perpSupply > 0)
? reserveTokens[i].balanceOf(address(this)).mulDiv(perpAmtBurnt, perpSupply)
: 0;
reserveTokens[i] = TokenAmount({
token: _reserveAt(i),
amount: _reserveAt(i).balanceOf(address(this)).mulDiv(perpAmtBurnt, perpSupply)
});

// The burn fees are settled by simply redeeming for fewer tranches.
if (feePerc > 0) {
redemptionAmts[i] = redemptionAmts[i].mulDiv(FEE_ONE_PERC - feePerc, FEE_ONE_PERC);
reserveTokens[i].amount = reserveTokens[i].amount.mulDiv(FEE_ONE_PERC - feePerc, FEE_ONE_PERC);
}
}

return (reserveTokens, redemptionAmts);
return (reserveTokens);
}

/// @dev Computes the amount of reserve tokens that can be rolled out for the given amount of tranches deposited.
Expand All @@ -840,7 +819,7 @@ contract PerpetualTranche is
IERC20Upgradeable tokenOut,
uint256 trancheInAmtAvailable,
uint256 tokenOutAmtRequested
) private view returns (IPerpetualTranche.RolloverData memory) {
) private view returns (RolloverData memory) {
//-----------------------------------------------------------------------------
// The rollover fees are settled by, adjusting the exchange rate
// between `trancheInAmt` and `tokenOutAmt`.
Expand All @@ -850,8 +829,6 @@ contract PerpetualTranche is
);
//-----------------------------------------------------------------------------

IPerpetualTranche.RolloverData memory r;

// We compute "price" as the value of a unit token.
// The perp, tranche tokens and the underlying are denominated as fixed point numbers
// with the same number of decimals.
Expand All @@ -874,16 +851,18 @@ contract PerpetualTranche is
uint256 tokenOutBalance = tokenOut.balanceOf(address(this));
tokenOutAmtRequested = MathUpgradeable.min(tokenOutAmtRequested, tokenOutBalance);
if (trancheInAmtAvailable <= 0 || trancheInPrice <= 0 || tokenOutPrice <= 0 || tokenOutAmtRequested <= 0) {
return r;
return RolloverData({ trancheInAmt: 0, tokenOutAmt: 0 });
}
//-----------------------------------------------------------------------------
// Basic rollover with fees:
// (1 +/- f) . (trancheInAmt . trancheInPrice) = (tokenOutAmt . tokenOutPrice)
//-----------------------------------------------------------------------------

// Given the amount of tranches In, we compute the amount of tokens out
r.trancheInAmt = trancheInAmtAvailable;
r.tokenOutAmt = r.trancheInAmt.mulDiv(trancheInPrice, tokenOutPrice);
RolloverData memory r = RolloverData({
trancheInAmt: trancheInAmtAvailable,
tokenOutAmt: trancheInAmtAvailable.mulDiv(trancheInPrice, tokenOutPrice)
});

// A positive fee percentage implies that perp charges rotators by
// accepting tranchesIn at a discount, i.e) fewer tokens out.
Expand Down Expand Up @@ -1008,11 +987,13 @@ contract PerpetualTranche is
}

/// @dev Queries the current subscription state of the perp and vault systems.
function _querySubscriptionState() private view returns (IFeePolicy.SubscriptionParams memory s) {
s.perpTVL = _reserveValue();
s.vaultTVL = IVault(vault).getTVL();
s.seniorTR = _depositBond.getSeniorTrancheRatio();
return s;
function _querySubscriptionState() private view returns (SubscriptionParams memory) {
return
SubscriptionParams({
perpTVL: _reserveValue(),
vaultTVL: IRolloverVault(vault).getTVL(),
seniorTR: _depositBond.getSeniorTrancheRatio()
});
}

/// @dev Calculates the total value of all the tranches in the reserve.
Expand Down Expand Up @@ -1069,6 +1050,6 @@ contract PerpetualTranche is
/// @dev Checks if caller is another module within the protocol.
/// If so, we do not charge mint/burn for internal operations.
function _isProtocolCaller() private view returns (bool) {
return (_msgSender() == vault);
return (_msgSender() == address(vault));
}
}
Loading

0 comments on commit 8bdfc1a

Please sign in to comment.