Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions spot-contracts/contracts/PerpetualTranche.sol
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,16 @@ contract PerpetualTranche is
}

/// @inheritdoc IPerpetualTranche
function getReserveTokenBalance(IERC20Upgradeable token) external override afterStateUpdate returns (uint256) {
if (!_inReserve(token)) {
return 0;
}
return _reserveBalance(token);
}

/// @inheritdoc IPerpetualTranche
/// @dev In the case of the collateral token, it returns the "virtual" tranche balance.
// In all other cases, it just returns the token balance.
function getReserveTrancheBalance(IERC20Upgradeable tranche) external override afterStateUpdate returns (uint256) {
if (!_inReserve(tranche)) {
return 0;
Expand Down
28 changes: 14 additions & 14 deletions spot-contracts/contracts/RouterV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ contract RouterV1 {
{
IBondController bond = perp.getDepositBond();

BondTranches memory td;
BondTranches memory bt;
uint256[] memory trancheAmts;
(td, trancheAmts, ) = bond.previewDeposit(collateralAmount);
(bt, trancheAmts, ) = bond.previewDeposit(collateralAmount);

return (bond, td.tranches, trancheAmts);
return (bond, bt.tranches, trancheAmts);
}

/// @notice Calculates the amount of perp tokens minted and fees for the operation.
Expand Down Expand Up @@ -100,7 +100,7 @@ contract RouterV1 {
uint256 collateralAmount,
uint256 feePaid
) external afterPerpStateUpdate(perp) {
BondTranches memory td = bond.getTranches();
BondTranches memory bt = bond.getTranches();
IERC20Upgradeable collateralToken = IERC20Upgradeable(bond.collateralToken());
IERC20Upgradeable feeToken = perp.feeToken();

Expand All @@ -119,18 +119,18 @@ contract RouterV1 {
// approves fee to be spent to mint perp tokens
_checkAndApproveMax(feeToken, address(perp), feePaid);

for (uint8 i = 0; i < td.tranches.length; i++) {
uint256 trancheAmt = td.tranches[i].balanceOf(address(this));
uint256 mintAmt = perp.computeMintAmt(td.tranches[i], trancheAmt);
for (uint8 i = 0; i < bt.tranches.length; i++) {
uint256 trancheAmt = bt.tranches[i].balanceOf(address(this));
uint256 mintAmt = perp.computeMintAmt(bt.tranches[i], trancheAmt);
if (mintAmt > 0) {
// approves tranches to be spent
_checkAndApproveMax(td.tranches[i], address(perp), trancheAmt);
_checkAndApproveMax(bt.tranches[i], address(perp), trancheAmt);

// mints perp tokens using tranches
perp.deposit(td.tranches[i], trancheAmt);
perp.deposit(bt.tranches[i], trancheAmt);
} else {
// transfers unused tranches back
td.tranches[i].safeTransfer(msg.sender, trancheAmt);
bt.tranches[i].safeTransfer(msg.sender, trancheAmt);
}
}

Expand Down Expand Up @@ -238,7 +238,7 @@ contract RouterV1 {
RolloverBatch[] calldata rollovers,
uint256 feePaid
) external afterPerpStateUpdate(perp) {
BondTranches memory td = bond.getTranches();
BondTranches memory bt = bond.getTranches();
IERC20Upgradeable collateralToken = IERC20Upgradeable(bond.collateralToken());
IERC20Upgradeable feeToken = perp.feeToken();

Expand Down Expand Up @@ -276,10 +276,10 @@ contract RouterV1 {
}

// transfers unused tranches back
for (uint8 i = 0; i < td.tranches.length; i++) {
uint256 trancheBalance = td.tranches[i].balanceOf(address(this));
for (uint8 i = 0; i < bt.tranches.length; i++) {
uint256 trancheBalance = bt.tranches[i].balanceOf(address(this));
if (trancheBalance > 0) {
td.tranches[i].safeTransfer(msg.sender, trancheBalance);
bt.tranches[i].safeTransfer(msg.sender, trancheBalance);
}
}

Expand Down
5 changes: 5 additions & 0 deletions spot-contracts/contracts/_interfaces/IPerpetualTranche.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ interface IPerpetualTranche is IERC20Upgradeable {
/// @return If the token is part of the reserve.
function inReserve(IERC20Upgradeable token) external returns (bool);

/// @notice Fetches the reserve's token balance.
/// @param token The address of the tranche token held by the reserve.
/// @return The ERC-20 balance of the reserve token.
function getReserveTokenBalance(IERC20Upgradeable token) external returns (uint256);

/// @notice Fetches the reserve's tranche token balance.
/// @param tranche The address of the tranche token held by the reserve.
/// @return The ERC-20 balance of the reserve tranche token.
Expand Down
78 changes: 39 additions & 39 deletions spot-contracts/contracts/_utils/BondHelpers.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ struct BondTranches {
*/
library BondTranchesHelpers {
/// @notice Iterates through the tranche data to find the seniority index of the given tranche.
/// @param td The tranche data object.
/// @param bt The tranche data object.
/// @param t The address of the tranche to check.
/// @return the index of the tranche in the tranches array.
function indexOf(BondTranches memory td, ITranche t) internal pure returns (uint8) {
for (uint8 i = 0; i < td.tranches.length; i++) {
if (td.tranches[i] == t) {
function indexOf(BondTranches memory bt, ITranche t) internal pure returns (uint8) {
for (uint8 i = 0; i < bt.tranches.length; i++) {
if (bt.tranches[i] == t) {
return i;
}
}
Expand All @@ -50,11 +50,11 @@ library TrancheHelpers {
/// @return The collateral balance and the tranche token supply.
function getTrancheCollateralization(ITranche t) internal view returns (uint256, uint256) {
IBondController bond = IBondController(t.bond());
BondTranches memory td;
BondTranches memory bt;
uint256[] memory collateralBalances;
uint256[] memory trancheSupplies;
(td, collateralBalances, trancheSupplies) = BondHelpers.getTrancheCollateralizations(bond);
uint256 trancheIndex = BondTranchesHelpers.indexOf(td, t);
(bt, collateralBalances, trancheSupplies) = BondHelpers.getTrancheCollateralizations(bond);
uint256 trancheIndex = BondTranchesHelpers.indexOf(bt, t);
return (collateralBalances[trancheIndex], trancheSupplies[trancheIndex]);
}
}
Expand Down Expand Up @@ -86,17 +86,17 @@ library BondHelpers {
/// @param b The address of the bond contract.
/// @return The tranche data.
function getTranches(IBondController b) internal view returns (BondTranches memory) {
BondTranches memory td;
BondTranches memory bt;
uint8 trancheCount = b.trancheCount().toUint8();
td.tranches = new ITranche[](trancheCount);
td.trancheRatios = new uint256[](trancheCount);
bt.tranches = new ITranche[](trancheCount);
bt.trancheRatios = new uint256[](trancheCount);
// Max tranches per bond < 2**8 - 1
for (uint8 i = 0; i < trancheCount; i++) {
(ITranche t, uint256 ratio) = b.tranches(i);
td.tranches[i] = t;
td.trancheRatios[i] = ratio;
bt.tranches[i] = t;
bt.trancheRatios[i] = ratio;
}
return td;
return bt;
}

/// @notice Given a bond, returns the tranche at the specified index.
Expand All @@ -122,29 +122,29 @@ library BondHelpers {
uint256[] memory
)
{
BondTranches memory td = getTranches(b);
uint256[] memory trancheAmts = new uint256[](td.tranches.length);
uint256[] memory fees = new uint256[](td.tranches.length);
BondTranches memory bt = getTranches(b);
uint256[] memory trancheAmts = new uint256[](bt.tranches.length);
uint256[] memory fees = new uint256[](bt.tranches.length);

uint256 totalDebt = b.totalDebt();
uint256 collateralBalance = IERC20Upgradeable(b.collateralToken()).balanceOf(address(b));
uint256 feeBps = b.feeBps();

for (uint8 i = 0; i < td.tranches.length; i++) {
trancheAmts[i] = collateralAmount.mulDiv(td.trancheRatios[i], TRANCHE_RATIO_GRANULARITY);
for (uint8 i = 0; i < bt.tranches.length; i++) {
trancheAmts[i] = collateralAmount.mulDiv(bt.trancheRatios[i], TRANCHE_RATIO_GRANULARITY);
if (collateralBalance > 0) {
trancheAmts[i] = trancheAmts[i].mulDiv(totalDebt, collateralBalance);
}
}

if (feeBps > 0) {
for (uint8 i = 0; i < td.tranches.length; i++) {
for (uint8 i = 0; i < bt.tranches.length; i++) {
fees[i] = trancheAmts[i].mulDiv(feeBps, BPS);
trancheAmts[i] -= fees[i];
}
}

return (td, trancheAmts, fees);
return (bt, trancheAmts, fees);
}

/// @notice Given a bond, for each tranche token retrieves the total collateral redeemable
Expand All @@ -162,24 +162,24 @@ library BondHelpers {
uint256[] memory
)
{
BondTranches memory td = getTranches(b);
uint256[] memory collateralBalances = new uint256[](td.tranches.length);
uint256[] memory trancheSupplies = new uint256[](td.tranches.length);
BondTranches memory bt = getTranches(b);
uint256[] memory collateralBalances = new uint256[](bt.tranches.length);
uint256[] memory trancheSupplies = new uint256[](bt.tranches.length);

// When the bond is mature, the collateral is transferred over to the individual tranche token contracts
if (b.isMature()) {
for (uint8 i = 0; i < td.tranches.length; i++) {
trancheSupplies[i] = td.tranches[i].totalSupply();
collateralBalances[i] = IERC20Upgradeable(b.collateralToken()).balanceOf(address(td.tranches[i]));
for (uint8 i = 0; i < bt.tranches.length; i++) {
trancheSupplies[i] = bt.tranches[i].totalSupply();
collateralBalances[i] = IERC20Upgradeable(b.collateralToken()).balanceOf(address(bt.tranches[i]));
}
return (td, collateralBalances, trancheSupplies);
return (bt, collateralBalances, trancheSupplies);
}

// Before the bond is mature, all the collateral is held by the bond contract
uint256 bondCollateralBalance = IERC20Upgradeable(b.collateralToken()).balanceOf(address(b));
uint256 zTrancheIndex = td.tranches.length - 1;
for (uint8 i = 0; i < td.tranches.length; i++) {
trancheSupplies[i] = td.tranches[i].totalSupply();
uint256 zTrancheIndex = bt.tranches.length - 1;
for (uint8 i = 0; i < bt.tranches.length; i++) {
trancheSupplies[i] = bt.tranches[i].totalSupply();

// a to y tranches
if (i != zTrancheIndex) {
Expand All @@ -194,7 +194,7 @@ library BondHelpers {
}
}

return (td, collateralBalances, trancheSupplies);
return (bt, collateralBalances, trancheSupplies);
}

/// @notice For a given bond and user address, computes the maximum number of each of the bond's tranches
Expand All @@ -207,29 +207,29 @@ library BondHelpers {
view
returns (BondTranches memory, uint256[] memory)
{
BondTranches memory td = getTranches(b);
uint256[] memory redeemableAmts = new uint256[](td.tranches.length);
BondTranches memory bt = getTranches(b);
uint256[] memory redeemableAmts = new uint256[](bt.tranches.length);

// Calculate how many underlying assets could be redeemed from each tranche balance,
// assuming other tranches are not an issue, and record the smallest amount.
uint256 minUnderlyingOut = type(uint256).max;
uint8 i;
for (i = 0; i < td.tranches.length; i++) {
uint256 d = td.tranches[i].balanceOf(u).mulDiv(TRANCHE_RATIO_GRANULARITY, td.trancheRatios[i]);
for (i = 0; i < bt.tranches.length; i++) {
uint256 d = bt.tranches[i].balanceOf(u).mulDiv(TRANCHE_RATIO_GRANULARITY, bt.trancheRatios[i]);
if (d < minUnderlyingOut) {
minUnderlyingOut = d;
}

// if one of the balances is zero, we return
if (minUnderlyingOut == 0) {
return (td, redeemableAmts);
return (bt, redeemableAmts);
}
}

for (i = 0; i < td.tranches.length; i++) {
redeemableAmts[i] = td.trancheRatios[i].mulDiv(minUnderlyingOut, TRANCHE_RATIO_GRANULARITY);
for (i = 0; i < bt.tranches.length; i++) {
redeemableAmts[i] = bt.trancheRatios[i].mulDiv(minUnderlyingOut, TRANCHE_RATIO_GRANULARITY);
}

return (td, redeemableAmts);
return (bt, redeemableAmts);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ contract TrancheClassDiscountStrategy is IDiscountStrategy, OwnableUpgradeable {
/// @return The class hash.
function trancheClass(ITranche tranche) public view returns (bytes32) {
IBondController bond = IBondController(tranche.bond());
BondTranches memory td = bond.getTranches();
return keccak256(abi.encode(bond.collateralToken(), td.trancheRatios, td.indexOf(tranche)));
BondTranches memory bt = bond.getTranches();
return keccak256(abi.encode(bond.collateralToken(), bt.trancheRatios, bt.indexOf(tranche)));
}
}
10 changes: 5 additions & 5 deletions spot-contracts/contracts/test/BondHelpersTester.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ contract BondHelpersTester {
return b.secondsToMaturity();
}

function getTranches(IBondController b) public view returns (BondTranches memory td) {
function getTranches(IBondController b) public view returns (BondTranches memory bt) {
return b.getTranches();
}

Expand All @@ -33,7 +33,7 @@ contract BondHelpersTester {
public
view
returns (
BondTranches memory td,
BondTranches memory bt,
uint256[] memory,
uint256[] memory
)
Expand All @@ -42,14 +42,14 @@ contract BondHelpersTester {
}

function indexOf(IBondController b, ITranche t) public view returns (uint8) {
BondTranches memory td = b.getTranches();
return td.indexOf(t);
BondTranches memory bt = b.getTranches();
return bt.indexOf(t);
}

function computeRedeemableTrancheAmounts(IBondController b, address u)
public
view
returns (BondTranches memory td, uint256[] memory)
returns (BondTranches memory bt, uint256[] memory)
{
return b.computeRedeemableTrancheAmounts(u);
}
Expand Down
Loading