Skip to content

Commit

Permalink
Merge pull request #36 from OlympusDAO/yrf-update
Browse files Browse the repository at this point in the history
Update YieldRepurchaseFacility to be independent of RBS
  • Loading branch information
0xJem authored Feb 12, 2025
2 parents 8883345 + e5e115f commit d53bfd5
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 87 deletions.
3 changes: 3 additions & 0 deletions deployments/.mainnet-1739165363.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"YieldRepurchaseFacility": "0x271e35a8555a62F6bA76508E85dfD76D580B0692"
}
25 changes: 9 additions & 16 deletions src/policies/YieldRepurchaseFacility.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {IYieldRepo} from "policies/interfaces/IYieldRepo.sol";
import {RolesConsumer, ROLESv1} from "modules/ROLES/OlympusRoles.sol";
import {TRSRYv1} from "modules/TRSRY/TRSRY.v1.sol";
import {PRICEv1} from "modules/PRICE/PRICE.v1.sol";
import {RANGEv2} from "modules/RANGE/RANGE.v2.sol";
import {CHREGv1} from "modules/CHREG/CHREG.v1.sol";

interface BurnableERC20 {
Expand Down Expand Up @@ -53,7 +52,6 @@ contract YieldRepurchaseFacility is IYieldRepo, Policy, RolesConsumer {
// Modules
TRSRYv1 public TRSRY;
PRICEv1 public PRICE;
RANGEv2 public RANGE;
CHREGv1 public CHREG;

// External contracts
Expand Down Expand Up @@ -115,18 +113,16 @@ contract YieldRepurchaseFacility is IYieldRepo, Policy, RolesConsumer {
}

function configureDependencies() external override returns (Keycode[] memory dependencies) {
dependencies = new Keycode[](5);
dependencies = new Keycode[](4);
dependencies[0] = toKeycode("TRSRY");
dependencies[1] = toKeycode("PRICE");
dependencies[2] = toKeycode("RANGE");
dependencies[3] = toKeycode("CHREG");
dependencies[4] = toKeycode("ROLES");
dependencies[2] = toKeycode("CHREG");
dependencies[3] = toKeycode("ROLES");

TRSRY = TRSRYv1(getModuleAddress(dependencies[0]));
PRICE = PRICEv1(getModuleAddress(dependencies[1]));
RANGE = RANGEv2(getModuleAddress(dependencies[2]));
CHREG = CHREGv1(getModuleAddress(dependencies[3]));
ROLES = ROLESv1(getModuleAddress(dependencies[4]));
CHREG = CHREGv1(getModuleAddress(dependencies[2]));
ROLES = ROLESv1(getModuleAddress(dependencies[3]));

_oracleDecimals = PRICE.decimals();
}
Expand All @@ -149,7 +145,7 @@ contract YieldRepurchaseFacility is IYieldRepo, Policy, RolesConsumer {
/// @return major The major version of the policy.
/// @return minor The minor version of the policy.
function VERSION() external pure returns (uint8 major, uint8 minor) {
return (1, 1);
return (1, 2);
}

///////////////////////// EXTERNAL /////////////////////////
Expand Down Expand Up @@ -228,13 +224,10 @@ contract YieldRepurchaseFacility is IYieldRepo, Policy, RolesConsumer {
function _createMarket(uint256 bidAmount) internal {
// Calculate inverse prices from the oracle feed
// The start price is the current market price, which is also the last price since this is called on a heartbeat
// The min price is the upper cushion price, since we don't want to buy above this level
uint256 minPrice = 10 ** (_oracleDecimals * 2) / RANGE.price(true, true); // upper wall = (true, true) => high = true, wall = true
// The min price is the inverse of the maximum price of OHM in USDS
uint256 minPrice = 0; // Min price of zero means max price of infinity -- no cap
uint256 initialPrice = 10 ** (_oracleDecimals * 2) / ((PRICE.getLastPrice() * 97) / 100); // 3% below current stated price in case oracle is stale

// If the min price is greater than or equal to the initial price, we don't want to create a market
if (minPrice >= initialPrice) return;

// Calculate scaleAdjustment for bond market
// Price decimals are returned from the perspective of the quote token
// so the operations assume payoutPriceDecimal is zero and quotePriceDecimals
Expand Down Expand Up @@ -262,7 +255,7 @@ contract YieldRepurchaseFacility is IYieldRepo, Policy, RolesConsumer {
capacityInQuote: false,
capacity: bidAmount,
formattedInitialPrice: initialPrice.mulDiv(bondScale, oracleScale),
formattedMinimumPrice: minPrice.mulDiv(bondScale, oracleScale),
formattedMinimumPrice: minPrice,
debtBuffer: 100_000, // 100%
vesting: uint48(0), // Instant swaps
conclusion: uint48(block.timestamp + 1 days), // 1 day from now
Expand Down
8 changes: 8 additions & 0 deletions src/scripts/deploy/savedDeployments/yieldRepo_v1_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"sequence": [
{
"name": "YieldRepurchaseFacility",
"args": {}
}
]
}
2 changes: 1 addition & 1 deletion src/scripts/env.json
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@
"ReserveMigrator": "0x986b99579BEc7B990331474b66CcDB94Fa2419F5",
"RolesAdmin": "0xb216d714d91eeC4F7120a732c11428857C659eC8",
"TreasuryCustodian": "0xC9518AC915e46D707585116451Dc19c164513Ccf",
"YieldRepurchaseFacility": "0xcaA3d3E653A626e2656d2E799564fE952D39d855",
"YieldRepurchaseFacility": "0x271e35a8555a62F6bA76508E85dfD76D580B0692",
"ZeroDistributor": "0x44a7a09ccddb4338e062f1a3849f9a82bdbf2aaa",
"pOLY": "0xb37796941cA55b7E4243841930C104Ee325Da5a1"
},
Expand Down
105 changes: 35 additions & 70 deletions src/test/policies/YieldRepurchaseFacility.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,12 @@ import {IBondAggregator} from "interfaces/IBondAggregator.sol";
import {FullMath} from "libraries/FullMath.sol";

import "src/Kernel.sol";
import {OlympusRange} from "modules/RANGE/OlympusRange.sol";
import {OlympusTreasury} from "modules/TRSRY/OlympusTreasury.sol";
import {OlympusMinter} from "modules/MINTR/OlympusMinter.sol";
import {OlympusRoles} from "modules/ROLES/OlympusRoles.sol";
import {OlympusClearinghouseRegistry} from "modules/CHREG/OlympusClearinghouseRegistry.sol";
import {RolesAdmin} from "policies/RolesAdmin.sol";
import {YieldRepurchaseFacility} from "policies/YieldRepurchaseFacility.sol";
import {Operator} from "policies/Operator.sol";
import {BondCallback} from "policies/BondCallback.sol";

// solhint-disable-next-line max-states-count
contract YieldRepurchaseFacilityTest is Test {
Expand All @@ -57,7 +54,6 @@ contract YieldRepurchaseFacilityTest is Test {

Kernel internal kernel;
MockPrice internal PRICE;
OlympusRange internal RANGE;
OlympusTreasury internal TRSRY;
OlympusMinter internal MINTR;
OlympusRoles internal ROLES;
Expand All @@ -67,8 +63,6 @@ contract YieldRepurchaseFacilityTest is Test {
MockClearinghouse internal clearinghouse;
YieldRepurchaseFacility internal yieldRepo;
RolesAdmin internal rolesAdmin;
BondCallback internal callback; // only used by operator, not by yieldRepo
Operator internal operator;

uint256 initialReserves = 105_000_000e18;
uint256 initialConversionRate = 1_05e16;
Expand Down Expand Up @@ -112,14 +106,6 @@ contract YieldRepurchaseFacilityTest is Test {

/// Deploy modules (some mocks)
PRICE = new MockPrice(kernel, uint48(8 hours), 10 * 1e18);
RANGE = new OlympusRange(
kernel,
ERC20(ohm),
ERC20(reserve),
uint256(100),
[uint256(1500), uint256(2000)],
[uint256(1500), uint256(2000)]
);
TRSRY = new OlympusTreasury(kernel);
MINTR = new OlympusMinter(kernel, address(ohm));
ROLES = new OlympusRoles(kernel);
Expand All @@ -140,28 +126,6 @@ contract YieldRepurchaseFacilityTest is Test {
}

{
/// Deploy bond callback
callback = new BondCallback(kernel, IBondAggregator(address(aggregator)), ohm);

/// Deploy operator
operator = new Operator(
kernel,
IBondSDA(address(auctioneer)),
callback,
[address(ohm), address(reserve), address(sReserve), address(oldReserve)],
[
uint32(2000), // cushionFactor
uint32(5 days), // duration
uint32(100_000), // debtBuffer
uint32(1 hours), // depositInterval
uint32(1000), // reserveFactor
uint32(1 hours), // regenWait
uint32(5), // regenThreshold
uint32(7) // regenObserve
// uint32(8 hours) // observationFrequency
]
);

/// Deploy protocol loop
yieldRepo = new YieldRepurchaseFacility(
kernel,
Expand All @@ -180,16 +144,13 @@ contract YieldRepurchaseFacilityTest is Test {

/// Install modules
kernel.executeAction(Actions.InstallModule, address(PRICE));
kernel.executeAction(Actions.InstallModule, address(RANGE));
kernel.executeAction(Actions.InstallModule, address(TRSRY));
kernel.executeAction(Actions.InstallModule, address(MINTR));
kernel.executeAction(Actions.InstallModule, address(ROLES));
kernel.executeAction(Actions.InstallModule, address(CHREG));

/// Approve policies
kernel.executeAction(Actions.ActivatePolicy, address(yieldRepo));
kernel.executeAction(Actions.ActivatePolicy, address(callback));
kernel.executeAction(Actions.ActivatePolicy, address(operator));
kernel.executeAction(Actions.ActivatePolicy, address(rolesAdmin));
}
{
Expand All @@ -198,9 +159,6 @@ contract YieldRepurchaseFacilityTest is Test {
/// YieldRepurchaseFacility ROLES
rolesAdmin.grantRole("heart", address(heart));
rolesAdmin.grantRole("loop_daddy", guardian);

/// Operator ROLES
rolesAdmin.grantRole("operator_admin", address(guardian));
}

// Mint tokens to users, clearinghouse, and TRSRY for testing
Expand Down Expand Up @@ -231,10 +189,6 @@ contract YieldRepurchaseFacilityTest is Test {
vm.prank(alice);
ohm.approve(address(teller), testOhm * 20);

// Initialise the operator so that the range prices are set
vm.prank(guardian);
operator.initialize();

// Set principal receivables for the clearinghouse
clearinghouse.setPrincipalReceivables(uint256(100_000_000e18));

Expand Down Expand Up @@ -365,11 +319,7 @@ contract YieldRepurchaseFacilityTest is Test {
marketPrice,
((uint256(1e36) / ((10e18 * 97) / 100)) * 10 ** uint8(36 + 1)) / 10 ** uint8(18 + 1)
);
assertEq(
minPrice,
(((uint256(1e36) / ((10e18 * 120e16) / 1e18))) * 10 ** uint8(36 + 1)) /
10 ** uint8(18 + 1)
);
assertEq(minPrice, 0);
}

// Check that the epoch has been incremented
Expand All @@ -395,18 +345,25 @@ contract YieldRepurchaseFacilityTest is Test {
// Check that the initial yield was withdrawn from the TRSRY
assertEq(
sReserve.balanceOf(address(TRSRY)),
trsryBalance - sReserve.previewWithdraw(initialYield)
trsryBalance - sReserve.previewWithdraw(initialYield),
"TRSRY wrapped reserve balance"
);

// Check that the yieldRepo contract has the correct reserve balance
assertEq(reserve.balanceOf(address(yieldRepo)), initialYield / 7);
assertEq(
reserve.balanceOf(address(yieldRepo)),
initialYield / 7,
"yieldRepo reserve balance"
);
assertEq(
sReserve.balanceOf(address(yieldRepo)),
sReserve.previewDeposit(initialYield - initialYield / 7)
sReserve.previewDeposit(initialYield - initialYield / 7),
"yieldRepo wrapped reserve balance"
);

// Check that a bond market was not created
assertEq(aggregator.marketCounter(), nextBondMarketId);
// Check that a bond market was created
// This is because the current price is greater than the wall, and the wall no longer prevents a new bond market from being created
assertEq(aggregator.marketCounter(), nextBondMarketId + 1, "marketCount");
}

function test_endEpoch_isShutdown() public {
Expand Down Expand Up @@ -527,16 +484,21 @@ contract YieldRepurchaseFacilityTest is Test {
yieldRepo.endEpoch();

// Check that a new bond market was created
assertEq(aggregator.marketCounter(), nextBondMarketId + 1);
assertEq(
aggregator.marketCounter(),
nextBondMarketId + 1,
"bond market id should be incremented"
);

// Check that the yieldRepo contract burned the OHM
assertEq(ohm.balanceOf(address(yieldRepo)), 0);
assertEq(ohm.balanceOf(address(yieldRepo)), 0, "OHM should be burned");

// Check that the treasury balance has changed by the amount of backing withdrawn for the burnt OHM
uint256 reserveFromBurnedOhm = 100e9 * yieldRepo.backingPerToken();
assertEq(
sReserve.balanceOf(address(TRSRY)),
trsryBalance - sReserve.previewWithdraw(reserveFromBurnedOhm)
trsryBalance - sReserve.previewWithdraw(reserveFromBurnedOhm),
"treasury balance should decrease by the amount of backing withdrawn for the burnt OHM"
);

// Check that the balance of the yieldRepo contract has changed correctly
Expand All @@ -545,10 +507,15 @@ contract YieldRepurchaseFacilityTest is Test {
reserveFromBurnedOhm) / 6;

// Check that the yieldRepo contract reserve balances have changed correctly
assertEq(reserve.balanceOf(address(yieldRepo)), expectedBidAmount);
assertEq(
reserve.balanceOf(address(yieldRepo)),
expectedBidAmount,
"reserve balance should increase by the bid amount"
);
assertGe(
sReserve.balanceOf(address(yieldRepo)),
yieldRepoWrappedReserveBalance - sReserve.previewWithdraw(expectedBidAmount)
yieldRepoWrappedReserveBalance - sReserve.previewWithdraw(expectedBidAmount),
"wrapped reserve balance should decrease by the bid amount"
);

// Confirm that the bond market has the correct configuration
Expand All @@ -569,19 +536,17 @@ contract YieldRepurchaseFacilityTest is Test {
uint256 scale
) = auctioneer.markets(nextBondMarketId);

assertEq(capacity, expectedBidAmount);
assertEq(maxPayout, capacity / 6);
assertEq(capacity, expectedBidAmount, "capacity should be the bid amount");
assertEq(maxPayout, capacity / 6, "max payout should be 1/6th of the capacity");

assertEq(scale, 10 ** uint8(36 + 18 - 9 + 0));
assertEq(scale, 10 ** uint8(36 + 18 - 9 + 0), "scale");
assertEq(
marketPrice,
((uint256(1e36) / ((10e18 * 97) / 100)) * 10 ** uint8(36 + 1)) / 10 ** uint8(18 + 1)
);
assertEq(
minPrice,
(((uint256(1e36) / ((10e18 * 120e16) / 1e18))) * 10 ** uint8(36 + 1)) /
10 ** uint8(18 + 1)
((uint256(1e36) / ((10e18 * 97) / 100)) * 10 ** uint8(36 + 1)) /
10 ** uint8(18 + 1),
"marketPrice"
);
assertEq(minPrice, 0, "minPrice");
}
}

Expand Down

0 comments on commit d53bfd5

Please sign in to comment.