From 72ee0cc78ca9bd87387d914d9fc58d133e86eea9 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 15 Dec 2022 14:51:12 -0500 Subject: [PATCH 01/34] Draft Dripper and Reserves --- contracts/contracts/vault/VaultCore.sol | 62 ++++++++++++++++++---- contracts/contracts/vault/VaultStorage.sol | 16 ++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 3ee58e96b4..ae631dd76f 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -387,29 +387,63 @@ contract VaultCore is VaultStorage { * portion of the yield to the trustee. */ function _rebase() internal whenNotRebasePaused { + // 1. Get data uint256 ousdSupply = oUSD.totalSupply(); if (ousdSupply == 0) { return; } uint256 vaultValue = _totalValue(); + uint256 _dripperReserve = dripperReserve; + Dripper memory _dripper = dripper; - // Yield fee collection + // Do not distribute funds unless assets > liabilities + if (vaultValue > ousdSupply) { + return; + } + + // 2. Distribute new yield to internal accounts + uint256 preValue = ousdSupply - protocolReserve - dripperReserve; + if (preValue > vaultValue) { + uint256 yield = vaultValue - preValue; + // 3. Allocate to protocol reserve + protocolReserve += (yield * protocolReserveBps) / 10000; + // 4. Remainder to dripper + _dripperReserve += yield - protocolReserve; + } + + // 3. Drip previous yield, and update dripper + uint256 available = _dripperAvailableFunds(_dripperReserve, _dripper); + _dripperReserve -= available; + dripperReserve = _dripperReserve; + dripper = Dripper({ + perBlock: uint128(_dripperReserve / _dripper.dripDuration), // TODO: use safe convert + lastCollect: uint64(block.timestamp), + dripDuration: _dripper.dripDuration + }); + + // 4. Post dripper, distribute OUSD yield fee + if (available == 0) { + return; + } address _trusteeAddress = trusteeAddress; // gas savings + uint256 fee = 0; if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) { - uint256 yield = vaultValue.sub(ousdSupply); - uint256 fee = yield.mul(trusteeFeeBps).div(10000); - require(yield > fee, "Fee must not be greater than yield"); + fee = (available * trusteeFeeBps) / 10000; + require(available > fee, "Fee must not be greater than yield"); if (fee > 0) { oUSD.mint(_trusteeAddress, fee); } - emit YieldDistribution(_trusteeAddress, yield, fee); } - // Only rachet OUSD supply upwards - ousdSupply = oUSD.totalSupply(); // Final check should use latest value - if (vaultValue > ousdSupply) { - oUSD.changeSupply(vaultValue); + // 4. Post dripper, distribute OUSD to users + ousdSupply = oUSD.totalSupply(); // Final check should use latest value. TODO: Is this reload really needed? + uint256 newSupply = ousdSupply + available - fee; + // Only rachet OUSD supply upwards, final solvancy check + if (newSupply > ousdSupply && vaultValue > newSupply) { + oUSD.changeSupply(newSupply); } + + emit YieldDistribution(_trusteeAddress, available, fee); } /** @@ -635,6 +669,16 @@ contract VaultCore is VaultStorage { } } + function _dripperAvailableFunds(uint256 _balance, Dripper memory _drip) + internal + view + returns (uint256) + { + uint256 elapsed = block.timestamp - _drip.lastCollect; + uint256 allowed = (elapsed * _drip.perBlock); + return (allowed > _balance) ? _balance : allowed; + } + /*************************************** Utils ****************************************/ diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index fef80b07b2..d48d3b8a10 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -120,6 +120,22 @@ contract VaultStorage is Initializable, Governable { // How much net total OUSD is allowed to be minted by all strategies uint256 public netOusdMintForStrategyThreshold = 0; + // Reserve funds held by the protocol + uint256 public protocolReserve; + + uint256 public protocolReserveBps; + + // Dripper funds held by the protocol + uint256 public dripperReserve; + + // Dripper config/state + struct Dripper { + uint64 lastCollect; + uint128 perBlock; + uint64 dripDuration; + } + Dripper public dripper; + /** * @dev set the implementation for the admin, this needs to be in a base class else we cannot set it * @param newImpl address of the implementation From c12b74ff3efd1d288440ab3686a4815483ad48cc Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 15 Dec 2022 14:59:32 -0500 Subject: [PATCH 02/34] handle zero drip rate --- contracts/contracts/vault/VaultCore.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index ae631dd76f..5e7d604df9 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -674,8 +674,12 @@ contract VaultCore is VaultStorage { view returns (uint256) { + uint256 dripPerBlock = _drip.perBlock; + if (dripPerBlock == 0) { + return _balance; + } uint256 elapsed = block.timestamp - _drip.lastCollect; - uint256 allowed = (elapsed * _drip.perBlock); + uint256 allowed = (elapsed * dripPerBlock); return (allowed > _balance) ? _balance : allowed; } From 07055b13502810e112ea47fd3527a6b6c3a2b684 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 15 Dec 2022 15:09:16 -0500 Subject: [PATCH 03/34] handle zero drip rate --- contracts/contracts/vault/VaultCore.sol | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 5e7d604df9..f0a2c7d58c 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -415,8 +415,12 @@ contract VaultCore is VaultStorage { uint256 available = _dripperAvailableFunds(_dripperReserve, _dripper); _dripperReserve -= available; dripperReserve = _dripperReserve; + uint256 dripDuration = _dripper.dripDuration; + if (dripDuration == 0) { + dripDuration = 1; + } dripper = Dripper({ - perBlock: uint128(_dripperReserve / _dripper.dripDuration), // TODO: use safe convert + perBlock: uint128(_dripperReserve / dripDuration), // TODO: use safe convert lastCollect: uint64(block.timestamp), dripDuration: _dripper.dripDuration }); From b0f92a4bbb6becf475d70a083a40652b8ff0abdb Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Tue, 27 Dec 2022 09:39:12 -0500 Subject: [PATCH 04/34] Progress on admin functions and testing --- contracts/contracts/interfaces/IVault.sol | 4 ++ contracts/contracts/vault/VaultAdmin.sol | 11 +++++ contracts/contracts/vault/VaultCore.sol | 35 ++++++++++---- contracts/contracts/vault/VaultStorage.sol | 1 + contracts/test/vault/rebase.js | 55 ++++++++++++++++++++++ 5 files changed, 98 insertions(+), 8 deletions(-) diff --git a/contracts/contracts/interfaces/IVault.sol b/contracts/contracts/interfaces/IVault.sol index 09492ca8a0..39718e1224 100644 --- a/contracts/contracts/interfaces/IVault.sol +++ b/contracts/contracts/interfaces/IVault.sol @@ -60,6 +60,10 @@ interface IVault { function maxSupplyDiff() external view returns (uint256); + function setProtocolReserveBps(uint256 _basis) external; + + function protocolReserve() external view returns (uint256); + function setTrusteeAddress(address _address) external; function trusteeAddress() external view returns (address); diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 0ac7094eb1..a4592fa2a5 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -276,6 +276,17 @@ contract VaultAdmin is VaultStorage { emit MaxSupplyDiffChanged(_maxSupplyDiff); } + /** + * @dev Sets the percent of top-line yield that should be + * set aside as a reserve. + * @param _basis yield reserved, in basis points + */ + function setProtocolReserveBps(uint256 _basis) external onlyGovernor { + require(_basis <= 5000, "basis cannot exceed 50%"); + protocolReserveBps = _basis; + emit ProtocolReserveBpsChanged(_basis); + } + /** * @dev Sets the trusteeAddress that can receive a portion of yield. * Setting to the zero address disables this feature. diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index f0a2c7d58c..dda11a9781 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -21,6 +21,8 @@ import { IVault } from "../interfaces/IVault.sol"; import { IBuyback } from "../interfaces/IBuyback.sol"; import "./VaultStorage.sol"; +import "hardhat/console.sol"; + contract VaultCore is VaultStorage { using SafeERC20 for IERC20; using StableMath for uint256; @@ -387,6 +389,7 @@ contract VaultCore is VaultStorage { * portion of the yield to the trustee. */ function _rebase() internal whenNotRebasePaused { + console.log("---Rebase---"); // 1. Get data uint256 ousdSupply = oUSD.totalSupply(); if (ousdSupply == 0) { @@ -396,14 +399,18 @@ contract VaultCore is VaultStorage { uint256 _dripperReserve = dripperReserve; Dripper memory _dripper = dripper; - // Do not distribute funds unless assets > liabilities - if (vaultValue > ousdSupply) { + console.log("vv, os", vaultValue, ousdSupply); + + // Do not distribute funds if assets < liabilities + if (vaultValue < ousdSupply) { return; } - // 2. Distribute new yield to internal accounts + console.log("pr, dr", protocolReserve, _dripperReserve); + + // 2. Distribute new yield to internal accounts #todo, temp values pr uint256 preValue = ousdSupply - protocolReserve - dripperReserve; - if (preValue > vaultValue) { + if (vaultValue > preValue) { uint256 yield = vaultValue - preValue; // 3. Allocate to protocol reserve protocolReserve += (yield * protocolReserveBps) / 10000; @@ -411,14 +418,23 @@ contract VaultCore is VaultStorage { _dripperReserve += yield - protocolReserve; } + console.log("pr, dr", protocolReserve, _dripperReserve); + // 3. Drip previous yield, and update dripper - uint256 available = _dripperAvailableFunds(_dripperReserve, _dripper); - _dripperReserve -= available; - dripperReserve = _dripperReserve; + uint256 available = 0; uint256 dripDuration = _dripper.dripDuration; if (dripDuration == 0) { dripDuration = 1; + available = _dripperReserve; + _dripperReserve = 0; + } else { + available = _dripperAvailableFunds(_dripperReserve, _dripper); + _dripperReserve -= available; } + + console.log("av, dr", available, _dripperReserve); + + dripperReserve = _dripperReserve; dripper = Dripper({ perBlock: uint128(_dripperReserve / dripDuration), // TODO: use safe convert lastCollect: uint64(block.timestamp), @@ -443,10 +459,13 @@ contract VaultCore is VaultStorage { ousdSupply = oUSD.totalSupply(); // Final check should use latest value. TODO: Is this reload really needed? uint256 newSupply = ousdSupply + available - fee; // Only rachet OUSD supply upwards, final solvancy check - if (newSupply > ousdSupply && vaultValue > newSupply) { + console.log("ns, os, vv", newSupply, ousdSupply, vaultValue); + if (newSupply > ousdSupply && vaultValue >= newSupply) { oUSD.changeSupply(newSupply); } + console.log("pr, dr", protocolReserve, _dripperReserve); + emit YieldDistribution(_trusteeAddress, available, fee); } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index d48d3b8a10..f7b19f3f24 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -45,6 +45,7 @@ contract VaultStorage is Initializable, Governable { event StrategistUpdated(address _address); event MaxSupplyDiffChanged(uint256 maxSupplyDiff); event YieldDistribution(address _to, uint256 _yield, uint256 _fee); + event ProtocolReserveBpsChanged(uint256 _basis); event TrusteeFeeBpsChanged(uint256 _basis); event TrusteeAddressChanged(address _address); event NetOusdMintForStrategyThresholdChanged(uint256 _threshold); diff --git a/contracts/test/vault/rebase.js b/contracts/test/vault/rebase.js index f203bd58e5..e1c5c67bca 100644 --- a/contracts/test/vault/rebase.js +++ b/contracts/test/vault/rebase.js @@ -252,3 +252,58 @@ describe("Vault yield accrual to OGN", async () => { }); }); }); + +describe("Vault protocol reserve accrual", async () => { + [ + { + _yield: "1000", + reserveBasis: 100, + expectedReserveIncrease: "10", + expectedRebase: "990", + }, + { + _yield: "1000", + reserveBasis: 1000, + expectedReserveIncrease: "100", + expectedRebase: "900", + }, + { + _yield: "10000", + reserveBasis: 5000, + expectedReserveIncrease: "5000", + expectedRebase: "5000", + }, + ].forEach((options) => { + const { _yield, reserveBasis, expectedReserveIncrease, expectedRebase } = + options; + it(`should collect ${expectedReserveIncrease} reserve from ${_yield} yield at ${reserveBasis}bp `, async function () { + const fixture = await loadFixture(defaultFixture); + const { matt, governor, ousd, usdt, vault, mockNonRebasing } = fixture; + // const trustee = mockNonRebasing; + + // Setup reserve rate + await vault.connect(governor).setProtocolReserveBps(reserveBasis); + + // Create yield for the vault + await usdt.connect(matt).mint(usdcUnits(_yield)); + await usdt.connect(matt).transfer(vault.address, usdcUnits(_yield)); + // Do rebase + const supplyBefore = await ousd.totalSupply(); + const protocolReserveBefore = await vault.protocolReserve(); + console.log(supplyBefore) + console.log(protocolReserveBefore) + await vault.rebase(); + // OUSD supply increases correctly + await expectApproxSupply( + ousd, + supplyBefore.add(ousdUnits(expectedRebase)) + ); + // Reserve increased + const protocolReserveAfter = await vault.protocolReserve(); + await expect(protocolReserveAfter).to.be.approxEqualTolerance( + protocolReserveBefore.add(ousdUnits(expectedReserveIncrease)), + 1 + ); + }); + }); +}); From 92612a25ea11e14786f3df06944706861e5c7080 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 6 Feb 2023 08:23:49 -0500 Subject: [PATCH 05/34] Added comments to warn us about doing a split accounting update --- contracts/contracts/token/OUSD.sol | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index bd64a35612..dfbc41a122 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -473,10 +473,16 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { // high resolution, and do not have to do any other bookkeeping nonRebasingCreditsPerToken[_account] = 1e27; } else { - // Migrate an existing account: - + // Migrate the existing account: + // It is important that balanceOf not be called inside updating + // account data, since it will give wrong answers if it does + // not have all an account's data in a consistent state. This + // isn't a problem in the current implimentation, since we only + // need to update nonRebasingCreditsPerToken. // Set fixed credits per token for this account nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; + + // Update global totals: // Update non rebasing supply nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); // Update credit tallies From 838d6a799af552a90b674e53bed98e9255899c9a Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 6 Feb 2023 08:55:27 -0500 Subject: [PATCH 06/34] Reorder and clarify rebaseOptOut and rebaseOptIn --- contracts/contracts/token/OUSD.sol | 33 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index dfbc41a122..a3ff8f19d6 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -501,24 +501,29 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function rebaseOptIn() public nonReentrant { require(_isNonRebasingAccount(msg.sender), "Account has not opted out"); + // Precalculate new credits, so that we avoid internal calls when + // atomicly updating account. // Convert balance into the same amount at the current exchange rate uint256 newCreditBalance = _creditBalances[msg.sender] .mul(_rebasingCreditsPerToken) .div(_creditsPerToken(msg.sender)); - // Decreasing non rebasing supply - nonRebasingSupply = nonRebasingSupply.sub(balanceOf(msg.sender)); - + // Atomicly update this account: + // Important that no internal calls happen during this. + // Remove pinned fixed credits per token + delete nonRebasingCreditsPerToken[msg.sender]; + // New credits _creditBalances[msg.sender] = newCreditBalance; + // Mark explicitly opted out of rebasing + rebaseState[msg.sender] = RebaseOptions.OptIn; + + // Update global totals: + // Decrease non rebasing supply + nonRebasingSupply = nonRebasingSupply.sub(balanceOf(msg.sender)); // Increase rebasing credits, totalSupply remains unchanged so no // adjustment necessary _rebasingCredits = _rebasingCredits.add(_creditBalances[msg.sender]); - - rebaseState[msg.sender] = RebaseOptions.OptIn; - - // Delete any fixed credits per token - delete nonRebasingCreditsPerToken[msg.sender]; } /** @@ -527,17 +532,19 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function rebaseOptOut() public nonReentrant { require(!_isNonRebasingAccount(msg.sender), "Account has not opted in"); - // Increase non rebasing supply - nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender)); + // Atomicly update this account + // Important that no internal calls happen during this. // Set fixed credits per token nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken; + // Mark explicitly opted out of rebasing + rebaseState[msg.sender] = RebaseOptions.OptOut; + // Update global totals: + // Increase non rebasing supply + nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender)); // Decrease rebasing credits, total supply remains unchanged so no // adjustment necessary _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]); - - // Mark explicitly opted out of rebasing - rebaseState[msg.sender] = RebaseOptions.OptOut; } /** From f5a55a30c7728c51ad61b8fb79e88ee444d723ea Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 16 Feb 2023 10:13:49 -0500 Subject: [PATCH 07/34] Use perfect rebasing --- contracts/contracts/token/OUSD.sol | 68 +++++++++++++----------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index a3ff8f19d6..429649a0ec 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -457,7 +457,7 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function _isNonRebasingAccount(address _account) internal returns (bool) { bool isContract = Address.isContract(_account); if (isContract && rebaseState[_account] == RebaseOptions.NotSet) { - _ensureRebasingMigration(_account); + _ensureMigrationToNonRebasing(_account); } return nonRebasingCreditsPerToken[_account] > 0; } @@ -466,30 +466,33 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { * @dev Ensures internal account for rebasing and non-rebasing credits and * supply is updated following deployment of frozen yield change. */ - function _ensureRebasingMigration(address _account) internal { - if (nonRebasingCreditsPerToken[_account] == 0) { - if (_creditBalances[_account] == 0) { - // Since there is no existing balance, we can directly set to - // high resolution, and do not have to do any other bookkeeping - nonRebasingCreditsPerToken[_account] = 1e27; - } else { - // Migrate the existing account: - // It is important that balanceOf not be called inside updating - // account data, since it will give wrong answers if it does - // not have all an account's data in a consistent state. This - // isn't a problem in the current implimentation, since we only - // need to update nonRebasingCreditsPerToken. - // Set fixed credits per token for this account - nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; - - // Update global totals: - // Update non rebasing supply - nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); - // Update credit tallies - _rebasingCredits = _rebasingCredits.sub( - _creditBalances[_account] - ); - } + function _ensureMigrationToNonRebasing(address _account) internal { + if (nonRebasingCreditsPerToken[_account] != 0) { + return; // Account already is non-rebasing + } + if (_creditBalances[_account] == 0) { + // Since there is no existing balance, we can directly set to + // high resolution, and do not have to do any other bookkeeping + nonRebasingCreditsPerToken[_account] = 1e27; + } else { + // Get old values, so we can use them unaffected by changes + uint256 oldBalance = balanceOf(_account); + uint256 oldCredits = _creditBalances[_account]; + + // Atomicly update account information: + // It is important that balanceOf not be called inside updating + // account data, since it will give wrong answers if it does + // not have all an account's data in a consistent state. + nonRebasingCreditsPerToken[_account] = 1e27; + // difference between the 1e18 balance and the new 1e27 resolution + _creditBalances[_account] = oldBalance * 1e9; + + // Verify perfect acccount accounting update + require(oldBalance == balanceOf(_account), "Balances do not match"); + + // Update global totals: + nonRebasingSupply = nonRebasingSupply.add(oldBalance); + _rebasingCredits = _rebasingCredits.sub(oldCredits); } } @@ -516,7 +519,6 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { _creditBalances[msg.sender] = newCreditBalance; // Mark explicitly opted out of rebasing rebaseState[msg.sender] = RebaseOptions.OptIn; - // Update global totals: // Decrease non rebasing supply @@ -532,19 +534,9 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function rebaseOptOut() public nonReentrant { require(!_isNonRebasingAccount(msg.sender), "Account has not opted in"); - // Atomicly update this account - // Important that no internal calls happen during this. - // Set fixed credits per token - nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken; - // Mark explicitly opted out of rebasing - rebaseState[msg.sender] = RebaseOptions.OptOut; + _ensureMigrationToNonRebasing(msg.sender); - // Update global totals: - // Increase non rebasing supply - nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender)); - // Decrease rebasing credits, total supply remains unchanged so no - // adjustment necessary - _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]); + rebaseState[msg.sender] = RebaseOptions.OptOut; } /** From 1b29fba85e130824084a4b45f912325b67bc61f0 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 16 Feb 2023 10:27:03 -0500 Subject: [PATCH 08/34] Switch back to old verison, since it will also be perfectly accurate --- contracts/contracts/token/OUSD.sol | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index 429649a0ec..e189e3a009 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -475,23 +475,22 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { // high resolution, and do not have to do any other bookkeeping nonRebasingCreditsPerToken[_account] = 1e27; } else { - // Get old values, so we can use them unaffected by changes - uint256 oldBalance = balanceOf(_account); + // This does not change, but if it did, we want want to + // use the before changes value. uint256 oldCredits = _creditBalances[_account]; // Atomicly update account information: // It is important that balanceOf not be called inside updating // account data, since it will give wrong answers if it does // not have all an account's data in a consistent state. - nonRebasingCreditsPerToken[_account] = 1e27; - // difference between the 1e18 balance and the new 1e27 resolution - _creditBalances[_account] = oldBalance * 1e9; - - // Verify perfect acccount accounting update - require(oldBalance == balanceOf(_account), "Balances do not match"); + // + // By setting a per account nonRebasingCreditsPerToken, + // this account will no longer follow with the global + // rebasing credits per token. + nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; // Update global totals: - nonRebasingSupply = nonRebasingSupply.add(oldBalance); + nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); _rebasingCredits = _rebasingCredits.sub(oldCredits); } } From ab9da6ab63a8d574354992d861b608245b7612bb Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 16 Feb 2023 10:31:55 -0500 Subject: [PATCH 09/34] Follow normal fast exit style, rather than nested ifs --- contracts/contracts/token/OUSD.sol | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index e189e3a009..d36c73e696 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -474,25 +474,26 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { // Since there is no existing balance, we can directly set to // high resolution, and do not have to do any other bookkeeping nonRebasingCreditsPerToken[_account] = 1e27; - } else { - // This does not change, but if it did, we want want to - // use the before changes value. - uint256 oldCredits = _creditBalances[_account]; - - // Atomicly update account information: - // It is important that balanceOf not be called inside updating - // account data, since it will give wrong answers if it does - // not have all an account's data in a consistent state. - // - // By setting a per account nonRebasingCreditsPerToken, - // this account will no longer follow with the global - // rebasing credits per token. - nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; - - // Update global totals: - nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); - _rebasingCredits = _rebasingCredits.sub(oldCredits); + return; } + + // This does not change, but if it did, we would want to + // use the value before changes. + uint256 oldCredits = _creditBalances[_account]; + + // Atomicly update account information: + // It is important that balanceOf not be called inside updating + // account data, since it will give wrong answers if it does + // not have all an account's data in a consistent state. + // + // By setting a per account nonRebasingCreditsPerToken, + // this account will no longer follow with the global + // rebasing credits per token and will become non-rebasing. + nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; + + // Update global totals + nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); + _rebasingCredits = _rebasingCredits.sub(oldCredits); } /** From 958070b76b62c27b94581f9d7075ba7e70a17a16 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 16 Feb 2023 10:38:34 -0500 Subject: [PATCH 10/34] Use before change balance, as before --- contracts/contracts/token/OUSD.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index d36c73e696..43da60d618 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -504,6 +504,8 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function rebaseOptIn() public nonReentrant { require(_isNonRebasingAccount(msg.sender), "Account has not opted out"); + uint256 oldBalance = balanceOf(msg.sender); + // Precalculate new credits, so that we avoid internal calls when // atomicly updating account. // Convert balance into the same amount at the current exchange rate @@ -522,7 +524,7 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { // Update global totals: // Decrease non rebasing supply - nonRebasingSupply = nonRebasingSupply.sub(balanceOf(msg.sender)); + nonRebasingSupply = nonRebasingSupply.sub(oldBalance); // Increase rebasing credits, totalSupply remains unchanged so no // adjustment necessary _rebasingCredits = _rebasingCredits.add(_creditBalances[msg.sender]); From 6964877c24c59ca5bc74fbc0f5a8b858b233c859 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 10:06:02 -0500 Subject: [PATCH 11/34] rev 1 --- contracts/contracts/vault/VaultCore.sol | 95 +++++++++++++------------ contracts/test/vault/rebase.js | 4 +- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index dda11a9781..5933be5706 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -384,89 +384,90 @@ contract VaultCore is VaultStorage { } /** - * @dev Calculate the total value of assets held by the Vault and all - * strategies and update the supply of OUSD, optionally sending a - * portion of the yield to the trustee. + * @dev Update the supply of ousd by + * + * 1. Calculate new gains, splitting them between the dripper and protocol reserve + * 2. Drip out from the driper and update the dripper storage + * 3. Send trustee fees using post dripper funds + * 4. Rebase remaining post dripper funds to users + * */ function _rebase() internal whenNotRebasePaused { - console.log("---Rebase---"); - // 1. Get data + // 1. Calculate new gains, splitting them between the dripper and protocol reserve + // -------------------------------- uint256 ousdSupply = oUSD.totalSupply(); if (ousdSupply == 0) { - return; + return; // If there is no OUSD supply, we will not rebase } uint256 vaultValue = _totalValue(); - uint256 _dripperReserve = dripperReserve; - Dripper memory _dripper = dripper; - - console.log("vv, os", vaultValue, ousdSupply); - - // Do not distribute funds if assets < liabilities if (vaultValue < ousdSupply) { - return; + return; // Do not distribute funds if assets < liabilities } + uint256 _dripperReserve = dripperReserve; // cached for gas savings + Dripper memory _dripper = dripper; // cached for gas savings - console.log("pr, dr", protocolReserve, _dripperReserve); - - // 2. Distribute new yield to internal accounts #todo, temp values pr - uint256 preValue = ousdSupply - protocolReserve - dripperReserve; + uint256 preValue = ousdSupply - protocolReserve - _dripperReserve; if (vaultValue > preValue) { - uint256 yield = vaultValue - preValue; + uint256 newYield = vaultValue - preValue; + uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; // 3. Allocate to protocol reserve - protocolReserve += (yield * protocolReserveBps) / 10000; + protocolReserve += toProtocolReserve; // 4. Remainder to dripper - _dripperReserve += yield - protocolReserve; - } - - console.log("pr, dr", protocolReserve, _dripperReserve); - - // 3. Drip previous yield, and update dripper - uint256 available = 0; - uint256 dripDuration = _dripper.dripDuration; - if (dripDuration == 0) { - dripDuration = 1; - available = _dripperReserve; + _dripperReserve += newYield - toProtocolReserve; + // TODO: emit yeild Event + } + + // 2. Drip out from the dripper and update the dripper storage + // ---------------------------------------------------------- + uint256 postDripperYield = 0; + uint256 _dripDuration = _dripper.dripDuration; + if (_dripDuration == 0) { + // If dripper disabled, distribute all immediately + _dripDuration = 1; + postDripperYield = _dripperReserve; _dripperReserve = 0; } else { - available = _dripperAvailableFunds(_dripperReserve, _dripper); - _dripperReserve -= available; + postDripperYield = _dripperAvailableFunds( + _dripperReserve, + _dripper + ); + _dripperReserve -= postDripperYield; } - - console.log("av, dr", available, _dripperReserve); - + // Write dripper state dripperReserve = _dripperReserve; dripper = Dripper({ - perBlock: uint128(_dripperReserve / dripDuration), // TODO: use safe convert + perBlock: uint128(_dripperReserve / _dripDuration), // TODO: use safe convert lastCollect: uint64(block.timestamp), dripDuration: _dripper.dripDuration }); - // 4. Post dripper, distribute OUSD yield fee - if (available == 0) { + // 3. Send trustee fees using post dripper funds + // --------------------------------------------- + if (postDripperYield == 0) { return; } address _trusteeAddress = trusteeAddress; // gas savings uint256 fee = 0; if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) { - fee = (available * trusteeFeeBps) / 10000; - require(available > fee, "Fee must not be greater than yield"); + fee = (postDripperYield * trusteeFeeBps) / 10000; + require( + postDripperYield > fee, + "Fee must not be greater than yield" + ); if (fee > 0) { oUSD.mint(_trusteeAddress, fee); } } - // 4. Post dripper, distribute OUSD to users - ousdSupply = oUSD.totalSupply(); // Final check should use latest value. TODO: Is this reload really needed? - uint256 newSupply = ousdSupply + available - fee; + // 4. Rebase remaining post dripper funds to users + // --------------------------------------------- + uint256 newSupply = ousdSupply + postDripperYield; // Only rachet OUSD supply upwards, final solvancy check - console.log("ns, os, vv", newSupply, ousdSupply, vaultValue); if (newSupply > ousdSupply && vaultValue >= newSupply) { oUSD.changeSupply(newSupply); } - console.log("pr, dr", protocolReserve, _dripperReserve); - - emit YieldDistribution(_trusteeAddress, available, fee); + emit YieldDistribution(_trusteeAddress, postDripperYield, fee); } /** diff --git a/contracts/test/vault/rebase.js b/contracts/test/vault/rebase.js index 120793fb96..be6134c1f2 100644 --- a/contracts/test/vault/rebase.js +++ b/contracts/test/vault/rebase.js @@ -290,8 +290,8 @@ describe("Vault protocol reserve accrual", async () => { // Do rebase const supplyBefore = await ousd.totalSupply(); const protocolReserveBefore = await vault.protocolReserve(); - console.log(supplyBefore) - console.log(protocolReserveBefore) + console.log(supplyBefore); + console.log(protocolReserveBefore); await vault.rebase(); // OUSD supply increases correctly await expectApproxSupply( From aa53257233139c67e270867116293fbc7f5dad89 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 11:03:27 -0500 Subject: [PATCH 12/34] rev 2 --- contracts/contracts/vault/VaultCore.sol | 38 ++++++++++++++-------- contracts/contracts/vault/VaultStorage.sol | 1 + 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 5933be5706..027e22a6d1 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -406,15 +406,17 @@ contract VaultCore is VaultStorage { uint256 _dripperReserve = dripperReserve; // cached for gas savings Dripper memory _dripper = dripper; // cached for gas savings - uint256 preValue = ousdSupply - protocolReserve - _dripperReserve; - if (vaultValue > preValue) { - uint256 newYield = vaultValue - preValue; + uint256 reserves = protocolReserve + _dripperReserve; + // Did we gain funds? + if (vaultValue > (ousdSupply + _reserves)) { + uint256 newYield = vaultValue - (ousdSupply + reserves); uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; - // 3. Allocate to protocol reserve + // Allocate to protocol reserve protocolReserve += toProtocolReserve; - // 4. Remainder to dripper + // Remainder to dripper _dripperReserve += newYield - toProtocolReserve; - // TODO: emit yeild Event + + emit YieldReceived(newYield); } // 2. Drip out from the dripper and update the dripper storage @@ -441,14 +443,27 @@ contract VaultCore is VaultStorage { dripDuration: _dripper.dripDuration }); - // 3. Send trustee fees using post dripper funds + // Post Dripper // --------------------------------------------- if (postDripperYield == 0) { + return; // If no yield to distribute + } + uint256 newSupply = ousdSupply + postDripperYield; + if ( + (newSupply <= ousdSupply) || (newSupply < vaultValue) // OUSD supply must increase // OUSD must be solvent + ) { + // if we have funds to distribute but don't meet the criteria + // save funds for later distribution. + dripperReserve += postDripperYield; return; } + + // 3. Send trustee fees using post dripper funds + // --------------------------------------------- + address _trusteeAddress = trusteeAddress; // gas savings uint256 fee = 0; - if (_trusteeAddress != address(0) && (vaultValue > ousdSupply)) { + if (_trusteeAddress != address(0)) { fee = (postDripperYield * trusteeFeeBps) / 10000; require( postDripperYield > fee, @@ -461,12 +476,9 @@ contract VaultCore is VaultStorage { // 4. Rebase remaining post dripper funds to users // --------------------------------------------- - uint256 newSupply = ousdSupply + postDripperYield; - // Only rachet OUSD supply upwards, final solvancy check - if (newSupply > ousdSupply && vaultValue >= newSupply) { - oUSD.changeSupply(newSupply); - } + oUSD.changeSupply(newSupply); + require(newSupply <= vaultValue, "Insolvency check"); emit YieldDistribution(_trusteeAddress, postDripperYield, fee); } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index f7b19f3f24..757f6aab1e 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -44,6 +44,7 @@ contract VaultStorage is Initializable, Governable { event RebaseThresholdUpdated(uint256 _threshold); event StrategistUpdated(address _address); event MaxSupplyDiffChanged(uint256 maxSupplyDiff); + event YieldReceived(uint256 _yield); event YieldDistribution(address _to, uint256 _yield, uint256 _fee); event ProtocolReserveBpsChanged(uint256 _basis); event TrusteeFeeBpsChanged(uint256 _basis); From 40a941f01ba891fead7a1a55d1239a4041168f6f Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 11:33:37 -0500 Subject: [PATCH 13/34] rev 3 --- contracts/contracts/vault/VaultCore.sol | 83 ++++++++++++++----------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 027e22a6d1..ba111125bd 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -391,24 +391,29 @@ contract VaultCore is VaultStorage { * 3. Send trustee fees using post dripper funds * 4. Rebase remaining post dripper funds to users * + * After running: + * - ousd supply + reserves should equal vault value + * - If we started solvent, we should end solvent */ function _rebase() internal whenNotRebasePaused { - // 1. Calculate new gains, splitting them between the dripper and protocol reserve + // Calculate new gains, splitting them between the dripper and protocol reserve // -------------------------------- + + // Load data used for rebasing uint256 ousdSupply = oUSD.totalSupply(); + uint256 vaultValue = _totalValue(); if (ousdSupply == 0) { return; // If there is no OUSD supply, we will not rebase } - uint256 vaultValue = _totalValue(); if (vaultValue < ousdSupply) { return; // Do not distribute funds if assets < liabilities } uint256 _dripperReserve = dripperReserve; // cached for gas savings Dripper memory _dripper = dripper; // cached for gas savings - uint256 reserves = protocolReserve + _dripperReserve; + // Did we gain funds? - if (vaultValue > (ousdSupply + _reserves)) { + if (vaultValue > (ousdSupply + reserves)) { uint256 newYield = vaultValue - (ousdSupply + reserves); uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; // Allocate to protocol reserve @@ -419,11 +424,12 @@ contract VaultCore is VaultStorage { emit YieldReceived(newYield); } - // 2. Drip out from the dripper and update the dripper storage + // Drip out from the dripper and update the dripper storage // ---------------------------------------------------------- uint256 postDripperYield = 0; uint256 _dripDuration = _dripper.dripDuration; if (_dripDuration == 0) { + // Will we need this? // If dripper disabled, distribute all immediately _dripDuration = 1; postDripperYield = _dripperReserve; @@ -445,43 +451,60 @@ contract VaultCore is VaultStorage { // Post Dripper // --------------------------------------------- - if (postDripperYield == 0) { - return; // If no yield to distribute + if (postDripperYield > 0) { + _distibuteYield(postDripperYield, ousdSupply, vaultValue); } + } + + function _distibuteYield( + uint256 postDripperYield, + uint256 ousdSupply, + uint256 vaultValue + ) { uint256 newSupply = ousdSupply + postDripperYield; - if ( - (newSupply <= ousdSupply) || (newSupply < vaultValue) // OUSD supply must increase // OUSD must be solvent - ) { - // if we have funds to distribute but don't meet the criteria + // OUSD supply must increase, OUSD must remain solvent + if ((newSupply <= ousdSupply) || (newSupply < vaultValue)) { + // if we have funds to distribute + // but don't meet the criteria // save funds for later distribution. dripperReserve += postDripperYield; return; } - // 3. Send trustee fees using post dripper funds + // Send trustee fees using post dripper funds // --------------------------------------------- - address _trusteeAddress = trusteeAddress; // gas savings uint256 fee = 0; if (_trusteeAddress != address(0)) { fee = (postDripperYield * trusteeFeeBps) / 10000; - require( - postDripperYield > fee, - "Fee must not be greater than yield" - ); - if (fee > 0) { - oUSD.mint(_trusteeAddress, fee); - } + require(fee < postDripperYield, "Fee must be less than yield"); + oUSD.mint(_trusteeAddress, fee); } - // 4. Rebase remaining post dripper funds to users + // Rebase remaining post dripper funds to users // --------------------------------------------- - oUSD.changeSupply(newSupply); - require(newSupply <= vaultValue, "Insolvency check"); emit YieldDistribution(_trusteeAddress, postDripperYield, fee); } + function dripperAvailableFunds() external returns (uint256) { + return _dripperAvailableFunds(dripperReserve, dripper); + } + + function _dripperAvailableFunds(uint256 _balance, Dripper memory _drip) + internal + view + returns (uint256) + { + uint256 dripPerBlock = _drip.perBlock; + if (dripPerBlock == 0) { + return _balance; + } + uint256 elapsed = block.timestamp - _drip.lastCollect; + uint256 allowed = (elapsed * dripPerBlock); + return (allowed > _balance) ? _balance : allowed; + } + /** * @dev Determine the total value of assets held by the vault and its * strategies. @@ -705,20 +728,6 @@ contract VaultCore is VaultStorage { } } - function _dripperAvailableFunds(uint256 _balance, Dripper memory _drip) - internal - view - returns (uint256) - { - uint256 dripPerBlock = _drip.perBlock; - if (dripPerBlock == 0) { - return _balance; - } - uint256 elapsed = block.timestamp - _drip.lastCollect; - uint256 allowed = (elapsed * dripPerBlock); - return (allowed > _balance) ? _balance : allowed; - } - /*************************************** Utils ****************************************/ From b5897475a46f23452203785fa1e63d021592d8b3 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 14:43:14 -0500 Subject: [PATCH 14/34] rev 4 --- contracts/contracts/vault/VaultCore.sol | 65 +++++++++++++------------ contracts/test/vault/rebase.js | 14 ++++-- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index ba111125bd..fb6843f44c 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -393,40 +393,39 @@ contract VaultCore is VaultStorage { * * After running: * - ousd supply + reserves should equal vault value - * - If we started solvent, we should end solvent + * - If the protocol started solvent, the protocol should end solvent */ function _rebase() internal whenNotRebasePaused { - // Calculate new gains, splitting them between the dripper and protocol reserve - // -------------------------------- - // Load data used for rebasing uint256 ousdSupply = oUSD.totalSupply(); uint256 vaultValue = _totalValue(); if (ousdSupply == 0) { + console.log("<< No OUSD supply"); return; // If there is no OUSD supply, we will not rebase } if (vaultValue < ousdSupply) { + console.log("<< vaultValue < ousdSupply"); return; // Do not distribute funds if assets < liabilities } uint256 _dripperReserve = dripperReserve; // cached for gas savings - Dripper memory _dripper = dripper; // cached for gas savings uint256 reserves = protocolReserve + _dripperReserve; - // Did we gain funds? + // Calculate new gains, then split them between the dripper and + // protocol reserve + console.log("(R) vv, s+r", vaultValue , (ousdSupply + reserves)); if (vaultValue > (ousdSupply + reserves)) { uint256 newYield = vaultValue - (ousdSupply + reserves); + console.log("(R) newYield", newYield); uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; - // Allocate to protocol reserve protocolReserve += toProtocolReserve; - // Remainder to dripper _dripperReserve += newYield - toProtocolReserve; emit YieldReceived(newYield); } // Drip out from the dripper and update the dripper storage - // ---------------------------------------------------------- uint256 postDripperYield = 0; + Dripper memory _dripper = dripper; // cached for gas savings uint256 _dripDuration = _dripper.dripDuration; if (_dripDuration == 0) { // Will we need this? @@ -441,50 +440,56 @@ contract VaultCore is VaultStorage { ); _dripperReserve -= postDripperYield; } + // Write dripper state dripperReserve = _dripperReserve; dripper = Dripper({ - perBlock: uint128(_dripperReserve / _dripDuration), // TODO: use safe convert + perBlock: uint128(_dripperReserve / _dripDuration), lastCollect: uint64(block.timestamp), dripDuration: _dripper.dripDuration }); - // Post Dripper - // --------------------------------------------- - if (postDripperYield > 0) { - _distibuteYield(postDripperYield, ousdSupply, vaultValue); - } + // Distribute + console.log("(R) postDripperYield", postDripperYield); + _distibuteYield(postDripperYield, ousdSupply, vaultValue); } function _distibuteYield( - uint256 postDripperYield, + uint256 yield, uint256 ousdSupply, uint256 vaultValue - ) { - uint256 newSupply = ousdSupply + postDripperYield; + ) internal { + if (yield == 0) { + console.log("<< No yield"); + return; + } + uint256 newSupply = ousdSupply + yield; // OUSD supply must increase, OUSD must remain solvent - if ((newSupply <= ousdSupply) || (newSupply < vaultValue)) { - // if we have funds to distribute - // but don't meet the criteria - // save funds for later distribution. - dripperReserve += postDripperYield; + console.log("(R) newSupply , ousdSupply", newSupply, ousdSupply); + console.log("(R) newSupply, vaultValue", newSupply, vaultValue); + console.log(newSupply <= ousdSupply); + console.log(newSupply > vaultValue); + if ((newSupply <= ousdSupply) || (newSupply > vaultValue)) { + // If we have funds to distribute but are not increasing supply or + // keeping the protocol solvant, then save funds for later + // distribution. + dripperReserve += yield; + console.log("<< back to reserve"); return; } - // Send trustee fees using post dripper funds - // --------------------------------------------- + // Mint trustee fees address _trusteeAddress = trusteeAddress; // gas savings uint256 fee = 0; if (_trusteeAddress != address(0)) { - fee = (postDripperYield * trusteeFeeBps) / 10000; - require(fee < postDripperYield, "Fee must be less than yield"); + fee = (yield * trusteeFeeBps) / 10000; + require(fee < yield, "Fee must be less than yield"); oUSD.mint(_trusteeAddress, fee); } - // Rebase remaining post dripper funds to users - // --------------------------------------------- + // Rebase remaining to users oUSD.changeSupply(newSupply); - emit YieldDistribution(_trusteeAddress, postDripperYield, fee); + emit YieldDistribution(_trusteeAddress, yield, fee); } function dripperAvailableFunds() external returns (uint256) { diff --git a/contracts/test/vault/rebase.js b/contracts/test/vault/rebase.js index be6134c1f2..26bab37521 100644 --- a/contracts/test/vault/rebase.js +++ b/contracts/test/vault/rebase.js @@ -219,7 +219,7 @@ describe("Vault rebasing", async () => { }); }); -describe("Vault yield accrual to OGN", async () => { +describe("Vault yield accrual to trustee", async () => { [ { _yield: "1000", basis: 100, expectedFee: "10" }, { _yield: "1000", basis: 5000, expectedFee: "500" }, @@ -253,7 +253,7 @@ describe("Vault yield accrual to OGN", async () => { }); }); -describe("Vault protocol reserve accrual", async () => { +describe.only("Vault protocol reserve accrual", async () => { [ { _yield: "1000", @@ -290,19 +290,23 @@ describe("Vault protocol reserve accrual", async () => { // Do rebase const supplyBefore = await ousd.totalSupply(); const protocolReserveBefore = await vault.protocolReserve(); - console.log(supplyBefore); console.log(protocolReserveBefore); + await vault.rebase(); + console.log("Supply Before", supplyBefore.toString()); + console.log("Supply After", supplyBefore.toString()); // OUSD supply increases correctly await expectApproxSupply( ousd, - supplyBefore.add(ousdUnits(expectedRebase)) + supplyBefore.add(ousdUnits(expectedRebase)), + "Supply" ); // Reserve increased const protocolReserveAfter = await vault.protocolReserve(); await expect(protocolReserveAfter).to.be.approxEqualTolerance( protocolReserveBefore.add(ousdUnits(expectedReserveIncrease)), - 1 + 1, + "Reserve" ); }); }); From c0f7eb589892b1bc5cdb3042ff0a1efc1b8906c4 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 15:55:52 -0500 Subject: [PATCH 15/34] Add spend reserve --- contracts/contracts/vault/VaultAdmin.sol | 13 +++++++++++++ contracts/contracts/vault/VaultCore.sol | 13 ------------- contracts/test/vault/rebase.js | 7 ++----- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 52d6a6cf34..e80b6a71a0 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -11,6 +11,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; +import { IVault } from "../interfaces/IVault.sol"; import "./VaultStorage.sol"; contract VaultAdmin is VaultStorage { @@ -448,6 +449,18 @@ contract VaultAdmin is VaultStorage { IERC20(_asset).safeTransfer(governor(), _amount); } + function spendReserve(address _asset, uint256 _amount) + external + onlyGovernor + { + protocolReserve -= _amount; + IERC20(_asset).safeTransfer(governor(), _amount); + require( + oUSD.totalSupply() < IVault(address(this)).totalValue(), + "Must be solvent" + ); + } + /*************************************** Pricing ****************************************/ diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index fb6843f44c..f810772064 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -21,8 +21,6 @@ import { IVault } from "../interfaces/IVault.sol"; import { IBuyback } from "../interfaces/IBuyback.sol"; import "./VaultStorage.sol"; -import "hardhat/console.sol"; - contract VaultCore is VaultStorage { using SafeERC20 for IERC20; using StableMath for uint256; @@ -400,11 +398,9 @@ contract VaultCore is VaultStorage { uint256 ousdSupply = oUSD.totalSupply(); uint256 vaultValue = _totalValue(); if (ousdSupply == 0) { - console.log("<< No OUSD supply"); return; // If there is no OUSD supply, we will not rebase } if (vaultValue < ousdSupply) { - console.log("<< vaultValue < ousdSupply"); return; // Do not distribute funds if assets < liabilities } uint256 _dripperReserve = dripperReserve; // cached for gas savings @@ -412,10 +408,8 @@ contract VaultCore is VaultStorage { // Calculate new gains, then split them between the dripper and // protocol reserve - console.log("(R) vv, s+r", vaultValue , (ousdSupply + reserves)); if (vaultValue > (ousdSupply + reserves)) { uint256 newYield = vaultValue - (ousdSupply + reserves); - console.log("(R) newYield", newYield); uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; protocolReserve += toProtocolReserve; _dripperReserve += newYield - toProtocolReserve; @@ -450,7 +444,6 @@ contract VaultCore is VaultStorage { }); // Distribute - console.log("(R) postDripperYield", postDripperYield); _distibuteYield(postDripperYield, ousdSupply, vaultValue); } @@ -460,21 +453,15 @@ contract VaultCore is VaultStorage { uint256 vaultValue ) internal { if (yield == 0) { - console.log("<< No yield"); return; } uint256 newSupply = ousdSupply + yield; // OUSD supply must increase, OUSD must remain solvent - console.log("(R) newSupply , ousdSupply", newSupply, ousdSupply); - console.log("(R) newSupply, vaultValue", newSupply, vaultValue); - console.log(newSupply <= ousdSupply); - console.log(newSupply > vaultValue); if ((newSupply <= ousdSupply) || (newSupply > vaultValue)) { // If we have funds to distribute but are not increasing supply or // keeping the protocol solvant, then save funds for later // distribution. dripperReserve += yield; - console.log("<< back to reserve"); return; } diff --git a/contracts/test/vault/rebase.js b/contracts/test/vault/rebase.js index 26bab37521..34d53fb982 100644 --- a/contracts/test/vault/rebase.js +++ b/contracts/test/vault/rebase.js @@ -253,7 +253,7 @@ describe("Vault yield accrual to trustee", async () => { }); }); -describe.only("Vault protocol reserve accrual", async () => { +describe("Vault protocol reserve accrual", async () => { [ { _yield: "1000", @@ -290,11 +290,8 @@ describe.only("Vault protocol reserve accrual", async () => { // Do rebase const supplyBefore = await ousd.totalSupply(); const protocolReserveBefore = await vault.protocolReserve(); - console.log(protocolReserveBefore); - + await vault.rebase(); - console.log("Supply Before", supplyBefore.toString()); - console.log("Supply After", supplyBefore.toString()); // OUSD supply increases correctly await expectApproxSupply( ousd, From 5a5c0a694960d138adb1842941f68e83c679c2a6 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 15:59:06 -0500 Subject: [PATCH 16/34] Remove inadvertant commit of OUSD WIP --- contracts/contracts/token/OUSD.sol | 79 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/contracts/contracts/token/OUSD.sol b/contracts/contracts/token/OUSD.sol index 43da60d618..bd64a35612 100644 --- a/contracts/contracts/token/OUSD.sol +++ b/contracts/contracts/token/OUSD.sol @@ -457,7 +457,7 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function _isNonRebasingAccount(address _account) internal returns (bool) { bool isContract = Address.isContract(_account); if (isContract && rebaseState[_account] == RebaseOptions.NotSet) { - _ensureMigrationToNonRebasing(_account); + _ensureRebasingMigration(_account); } return nonRebasingCreditsPerToken[_account] > 0; } @@ -466,34 +466,25 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { * @dev Ensures internal account for rebasing and non-rebasing credits and * supply is updated following deployment of frozen yield change. */ - function _ensureMigrationToNonRebasing(address _account) internal { - if (nonRebasingCreditsPerToken[_account] != 0) { - return; // Account already is non-rebasing - } - if (_creditBalances[_account] == 0) { - // Since there is no existing balance, we can directly set to - // high resolution, and do not have to do any other bookkeeping - nonRebasingCreditsPerToken[_account] = 1e27; - return; + function _ensureRebasingMigration(address _account) internal { + if (nonRebasingCreditsPerToken[_account] == 0) { + if (_creditBalances[_account] == 0) { + // Since there is no existing balance, we can directly set to + // high resolution, and do not have to do any other bookkeeping + nonRebasingCreditsPerToken[_account] = 1e27; + } else { + // Migrate an existing account: + + // Set fixed credits per token for this account + nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; + // Update non rebasing supply + nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); + // Update credit tallies + _rebasingCredits = _rebasingCredits.sub( + _creditBalances[_account] + ); + } } - - // This does not change, but if it did, we would want to - // use the value before changes. - uint256 oldCredits = _creditBalances[_account]; - - // Atomicly update account information: - // It is important that balanceOf not be called inside updating - // account data, since it will give wrong answers if it does - // not have all an account's data in a consistent state. - // - // By setting a per account nonRebasingCreditsPerToken, - // this account will no longer follow with the global - // rebasing credits per token and will become non-rebasing. - nonRebasingCreditsPerToken[_account] = _rebasingCreditsPerToken; - - // Update global totals - nonRebasingSupply = nonRebasingSupply.add(balanceOf(_account)); - _rebasingCredits = _rebasingCredits.sub(oldCredits); } /** @@ -504,30 +495,24 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function rebaseOptIn() public nonReentrant { require(_isNonRebasingAccount(msg.sender), "Account has not opted out"); - uint256 oldBalance = balanceOf(msg.sender); - - // Precalculate new credits, so that we avoid internal calls when - // atomicly updating account. // Convert balance into the same amount at the current exchange rate uint256 newCreditBalance = _creditBalances[msg.sender] .mul(_rebasingCreditsPerToken) .div(_creditsPerToken(msg.sender)); - // Atomicly update this account: - // Important that no internal calls happen during this. - // Remove pinned fixed credits per token - delete nonRebasingCreditsPerToken[msg.sender]; - // New credits + // Decreasing non rebasing supply + nonRebasingSupply = nonRebasingSupply.sub(balanceOf(msg.sender)); + _creditBalances[msg.sender] = newCreditBalance; - // Mark explicitly opted out of rebasing - rebaseState[msg.sender] = RebaseOptions.OptIn; - // Update global totals: - // Decrease non rebasing supply - nonRebasingSupply = nonRebasingSupply.sub(oldBalance); // Increase rebasing credits, totalSupply remains unchanged so no // adjustment necessary _rebasingCredits = _rebasingCredits.add(_creditBalances[msg.sender]); + + rebaseState[msg.sender] = RebaseOptions.OptIn; + + // Delete any fixed credits per token + delete nonRebasingCreditsPerToken[msg.sender]; } /** @@ -536,8 +521,16 @@ contract OUSD is Initializable, InitializableERC20Detailed, Governable { function rebaseOptOut() public nonReentrant { require(!_isNonRebasingAccount(msg.sender), "Account has not opted in"); - _ensureMigrationToNonRebasing(msg.sender); + // Increase non rebasing supply + nonRebasingSupply = nonRebasingSupply.add(balanceOf(msg.sender)); + // Set fixed credits per token + nonRebasingCreditsPerToken[msg.sender] = _rebasingCreditsPerToken; + + // Decrease rebasing credits, total supply remains unchanged so no + // adjustment necessary + _rebasingCredits = _rebasingCredits.sub(_creditBalances[msg.sender]); + // Mark explicitly opted out of rebasing rebaseState[msg.sender] = RebaseOptions.OptOut; } From b0686a711fa9dc40716f13ca4f864292e1ae1d33 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 3 Mar 2023 16:05:30 -0500 Subject: [PATCH 17/34] Add configuration of dripper duration --- contracts/contracts/vault/VaultAdmin.sol | 9 +++++++++ contracts/contracts/vault/VaultStorage.sol | 1 + 2 files changed, 10 insertions(+) diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index e80b6a71a0..eef418a287 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -364,6 +364,15 @@ contract VaultAdmin is VaultStorage { emit ProtocolReserveBpsChanged(_basis); } + /** + * @dev Sets the driper duration + * @param _durationSeconds length of time to drip out dripper reserves over + */ + function setDripDuration(uint64 _durationSeconds) external onlyGovernor { + dripper.dripDuration = _durationSeconds; + emit DriperDurationChanged(_durationSeconds); + } + /** * @dev Sets the trusteeAddress that can receive a portion of yield. * Setting to the zero address disables this feature. diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 757f6aab1e..fb5df2d87b 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -47,6 +47,7 @@ contract VaultStorage is Initializable, Governable { event YieldReceived(uint256 _yield); event YieldDistribution(address _to, uint256 _yield, uint256 _fee); event ProtocolReserveBpsChanged(uint256 _basis); + event DriperDurationChanged(uint256 _seconds); event TrusteeFeeBpsChanged(uint256 _basis); event TrusteeAddressChanged(address _address); event NetOusdMintForStrategyThresholdChanged(uint256 _threshold); From c675000971e30388e750b47e538ea76f5bc27da0 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 16 Mar 2023 09:56:20 -0400 Subject: [PATCH 18/34] Cleaner handling of partial dripper funds --- contracts/contracts/vault/VaultCore.sol | 30 +++++++++++++++---------- contracts/test/vault/rebase.js | 2 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index f810772064..88b24888cc 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -413,7 +413,6 @@ contract VaultCore is VaultStorage { uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; protocolReserve += toProtocolReserve; _dripperReserve += newYield - toProtocolReserve; - emit YieldReceived(newYield); } @@ -444,7 +443,11 @@ contract VaultCore is VaultStorage { }); // Distribute - _distibuteYield(postDripperYield, ousdSupply, vaultValue); + reserves = protocolReserve + _dripperReserve; + if (vaultValue > (ousdSupply + reserves)) { + uint256 excessValue = vaultValue - (ousdSupply + reserves); + _distibuteYield(excessValue, ousdSupply, vaultValue); + } } function _distibuteYield( @@ -455,15 +458,13 @@ contract VaultCore is VaultStorage { if (yield == 0) { return; } - uint256 newSupply = ousdSupply + yield; - // OUSD supply must increase, OUSD must remain solvent - if ((newSupply <= ousdSupply) || (newSupply > vaultValue)) { - // If we have funds to distribute but are not increasing supply or - // keeping the protocol solvant, then save funds for later - // distribution. - dripperReserve += yield; - return; - } + // This should never revert, because _distibuteYield should never be + // called unless there is excess supply. Neverless, we really care + // about this invarient, so we check it anyway. + require( + vaultValue >= ousdSupply + yield, + "No distribution if insolvent" + ); // Mint trustee fees address _trusteeAddress = trusteeAddress; // gas savings @@ -475,7 +476,12 @@ contract VaultCore is VaultStorage { } // Rebase remaining to users - oUSD.changeSupply(newSupply); + // Must only move up. (Invarient) + // Can only move up because: + // ousdSupply + yield >= ousdSupply + // also: + // fee (already minted) < yield + oUSD.changeSupply(ousdSupply + yield); emit YieldDistribution(_trusteeAddress, yield, fee); } diff --git a/contracts/test/vault/rebase.js b/contracts/test/vault/rebase.js index 34d53fb982..bed678da26 100644 --- a/contracts/test/vault/rebase.js +++ b/contracts/test/vault/rebase.js @@ -278,7 +278,7 @@ describe("Vault protocol reserve accrual", async () => { options; it(`should collect ${expectedReserveIncrease} reserve from ${_yield} yield at ${reserveBasis}bp `, async function () { const fixture = await loadFixture(defaultFixture); - const { matt, governor, ousd, usdt, vault, mockNonRebasing } = fixture; + const { matt, governor, ousd, usdt, vault } = fixture; // const trustee = mockNonRebasing; // Setup reserve rate From 2db4abe8801701421a3fb2d18933efe53af65caa Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 09:39:43 -0400 Subject: [PATCH 19/34] Moving back distrobution in allows us to lose some duplicate checks --- contracts/contracts/vault/VaultCore.sol | 78 +++++++++---------------- 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 88b24888cc..73ab32edc1 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -386,8 +386,8 @@ contract VaultCore is VaultStorage { * * 1. Calculate new gains, splitting them between the dripper and protocol reserve * 2. Drip out from the driper and update the dripper storage - * 3. Send trustee fees using post dripper funds - * 4. Rebase remaining post dripper funds to users + * 3. Distribute, splitting between trustee fees and rebasing remaining + * post dripper funds to users * * After running: * - ousd supply + reserves should equal vault value @@ -395,19 +395,19 @@ contract VaultCore is VaultStorage { */ function _rebase() internal whenNotRebasePaused { // Load data used for rebasing - uint256 ousdSupply = oUSD.totalSupply(); - uint256 vaultValue = _totalValue(); + uint256 ousdSupply = oUSD.totalSupply(); // gas savings + uint256 vaultValue = _totalValue(); // gas savings if (ousdSupply == 0) { return; // If there is no OUSD supply, we will not rebase } if (vaultValue < ousdSupply) { return; // Do not distribute funds if assets < liabilities } - uint256 _dripperReserve = dripperReserve; // cached for gas savings - uint256 reserves = protocolReserve + _dripperReserve; - - // Calculate new gains, then split them between the dripper and + uint256 _dripperReserve = dripperReserve; // gas savings + + // 1. Calculate new gains, then split them between the dripper and // protocol reserve + uint256 reserves = protocolReserve + _dripperReserve; if (vaultValue > (ousdSupply + reserves)) { uint256 newYield = vaultValue - (ousdSupply + reserves); uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; @@ -416,16 +416,14 @@ contract VaultCore is VaultStorage { emit YieldReceived(newYield); } - // Drip out from the dripper and update the dripper storage + // 2. Drip out from the dripper and update the dripper storage uint256 postDripperYield = 0; - Dripper memory _dripper = dripper; // cached for gas savings + Dripper memory _dripper = dripper; // gas savings uint256 _dripDuration = _dripper.dripDuration; if (_dripDuration == 0) { - // Will we need this? - // If dripper disabled, distribute all immediately _dripDuration = 1; postDripperYield = _dripperReserve; - _dripperReserve = 0; + _dripperReserve = 0; // dripper disabled, distribute all now } else { postDripperYield = _dripperAvailableFunds( _dripperReserve, @@ -442,47 +440,27 @@ contract VaultCore is VaultStorage { dripDuration: _dripper.dripDuration }); - // Distribute + // 5. Distribute reserves = protocolReserve + _dripperReserve; if (vaultValue > (ousdSupply + reserves)) { - uint256 excessValue = vaultValue - (ousdSupply + reserves); - _distibuteYield(excessValue, ousdSupply, vaultValue); - } - } - - function _distibuteYield( - uint256 yield, - uint256 ousdSupply, - uint256 vaultValue - ) internal { - if (yield == 0) { - return; - } - // This should never revert, because _distibuteYield should never be - // called unless there is excess supply. Neverless, we really care - // about this invarient, so we check it anyway. - require( - vaultValue >= ousdSupply + yield, - "No distribution if insolvent" - ); + uint256 yield = vaultValue - (ousdSupply + reserves); + + // Mint trustee fees + address _trusteeAddress = trusteeAddress; // gas savings + uint256 fee = 0; + if (_trusteeAddress != address(0)) { + fee = (yield * trusteeFeeBps) / 10000; + require(fee < yield, "Fee must be less than yield"); + oUSD.mint(_trusteeAddress, fee); + } - // Mint trustee fees - address _trusteeAddress = trusteeAddress; // gas savings - uint256 fee = 0; - if (_trusteeAddress != address(0)) { - fee = (yield * trusteeFeeBps) / 10000; - require(fee < yield, "Fee must be less than yield"); - oUSD.mint(_trusteeAddress, fee); + // Rebase remaining to users + // Invarient: must only increase OUSD supply. + // Can only increase because: + // ousdSupply + yield >= ousdSupply and yield > fee + oUSD.changeSupply(ousdSupply + yield); + emit YieldDistribution(_trusteeAddress, yield, fee); } - - // Rebase remaining to users - // Must only move up. (Invarient) - // Can only move up because: - // ousdSupply + yield >= ousdSupply - // also: - // fee (already minted) < yield - oUSD.changeSupply(ousdSupply + yield); - emit YieldDistribution(_trusteeAddress, yield, fee); } function dripperAvailableFunds() external returns (uint256) { From 24c9b9285f254c0e0e183eca029deff87ebeda05 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 09:43:02 -0400 Subject: [PATCH 20/34] Goodbye inaccurate postDripperYield --- contracts/contracts/vault/VaultCore.sol | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 73ab32edc1..36797dd760 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -417,19 +417,16 @@ contract VaultCore is VaultStorage { } // 2. Drip out from the dripper and update the dripper storage - uint256 postDripperYield = 0; Dripper memory _dripper = dripper; // gas savings - uint256 _dripDuration = _dripper.dripDuration; + uint256 _dripDuration = _dripper.dripDuration; // gas savings if (_dripDuration == 0) { _dripDuration = 1; - postDripperYield = _dripperReserve; _dripperReserve = 0; // dripper disabled, distribute all now } else { - postDripperYield = _dripperAvailableFunds( + _dripperReserve -= _dripperAvailableFunds( _dripperReserve, _dripper ); - _dripperReserve -= postDripperYield; } // Write dripper state From 2f47f4c27af5689718abc31cc09f4b5bbd68bb5e Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 10:18:47 -0400 Subject: [PATCH 21/34] Cleaner yield calculations --- contracts/contracts/vault/VaultCore.sol | 40 ++++++++++++++----------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 36797dd760..9a03cd1acf 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -382,16 +382,22 @@ contract VaultCore is VaultStorage { } /** - * @dev Update the supply of ousd by + * @dev Update the supply of ousd * - * 1. Calculate new gains, splitting them between the dripper and protocol reserve + * 1. Calculate new gains, splitting gains between the dripper and protocol reserve * 2. Drip out from the driper and update the dripper storage - * 3. Distribute, splitting between trustee fees and rebasing remaining - * post dripper funds to users + * 3. Distribute yield, splitting between trustee fees and rebasing + * the remaining post dripper funds to users * * After running: - * - ousd supply + reserves should equal vault value - * - If the protocol started solvent, the protocol should end solvent + * - If the protocol started solvent then: + * the protocol should end solvent + * - If the protocol started solvent and had yield then: + * ousd supply + reserves should equal vault value. + * - If the protocol started insolvent then: + * no funds should be distributed, or reserves changed + * - All cases: + * ending OUSD total supply should not be less than starting totalSupply */ function _rebase() internal whenNotRebasePaused { // Load data used for rebasing @@ -407,9 +413,9 @@ contract VaultCore is VaultStorage { // 1. Calculate new gains, then split them between the dripper and // protocol reserve - uint256 reserves = protocolReserve + _dripperReserve; - if (vaultValue > (ousdSupply + reserves)) { - uint256 newYield = vaultValue - (ousdSupply + reserves); + uint256 usedValue = ousdSupply + protocolReserve + _dripperReserve; + if (vaultValue > usedValue) { + uint256 newYield = vaultValue - usedValue; uint256 toProtocolReserve = (newYield * protocolReserveBps) / 10000; protocolReserve += toProtocolReserve; _dripperReserve += newYield - toProtocolReserve; @@ -418,10 +424,10 @@ contract VaultCore is VaultStorage { // 2. Drip out from the dripper and update the dripper storage Dripper memory _dripper = dripper; // gas savings - uint256 _dripDuration = _dripper.dripDuration; // gas savings + uint256 _dripDuration = _dripper.dripDuration; // gas, not written back if (_dripDuration == 0) { - _dripDuration = 1; - _dripperReserve = 0; // dripper disabled, distribute all now + _dripDuration = 1; // Prevent divide by zero later + _dripperReserve = 0; // Dripper disabled, distribute all now } else { _dripperReserve -= _dripperAvailableFunds( _dripperReserve, @@ -434,13 +440,13 @@ contract VaultCore is VaultStorage { dripper = Dripper({ perBlock: uint128(_dripperReserve / _dripDuration), lastCollect: uint64(block.timestamp), - dripDuration: _dripper.dripDuration + dripDuration: _dripper.dripDuration // must use stored value }); - // 5. Distribute - reserves = protocolReserve + _dripperReserve; - if (vaultValue > (ousdSupply + reserves)) { - uint256 yield = vaultValue - (ousdSupply + reserves); + // 3. Distribute fees then rebase to users + usedValue = ousdSupply + protocolReserve + _dripperReserve; + if (vaultValue > usedValue) { + uint256 yield = vaultValue - usedValue; // Mint trustee fees address _trusteeAddress = trusteeAddress; // gas savings From 8d4cb4244dcc9d4786bcf594a1e76c845e104b4c Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 10:29:29 -0400 Subject: [PATCH 22/34] make view --- contracts/contracts/vault/VaultCore.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 9a03cd1acf..36c31c27d1 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -466,7 +466,7 @@ contract VaultCore is VaultStorage { } } - function dripperAvailableFunds() external returns (uint256) { + function dripperAvailableFunds() external view returns (uint256) { return _dripperAvailableFunds(dripperReserve, dripper); } From caa0d042165b567dad11424809dc200d95e8dda9 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 10:42:00 -0400 Subject: [PATCH 23/34] OIP-5 --- contracts/contracts/vault/VaultCore.sol | 3 +++ contracts/contracts/vault/VaultStorage.sol | 2 ++ 2 files changed, 5 insertions(+) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 36c31c27d1..69002abefa 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -30,6 +30,8 @@ contract VaultCore is VaultStorage { // max un-signed int uint256 constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; + // impl contract address + address immutable SELF = address(this); /** * @dev Verifies that the rebasing is not paused. @@ -749,6 +751,7 @@ contract VaultCore is VaultStorage { */ // solhint-disable-next-line no-complex-fallback fallback() external payable { + require(SELF != address(this), "Must be proxied"); bytes32 slot = adminImplPosition; // solhint-disable-next-line no-inline-assembly assembly { diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index fb5df2d87b..f9ae5ff968 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -126,6 +126,7 @@ contract VaultStorage is Initializable, Governable { // Reserve funds held by the protocol uint256 public protocolReserve; + // Amount of reserve collected in Bps uint256 public protocolReserveBps; // Dripper funds held by the protocol @@ -139,6 +140,7 @@ contract VaultStorage is Initializable, Governable { } Dripper public dripper; + /** * @dev set the implementation for the admin, this needs to be in a base class else we cannot set it * @param newImpl address of the implementation From 3309fe6bc26a750b1d8fe1deac3b6eb989ee4848 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 10:53:47 -0400 Subject: [PATCH 24/34] Refactoring in _dripperAvailableFunds --- contracts/contracts/vault/VaultCore.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 69002abefa..7abfa48da8 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -472,18 +472,18 @@ contract VaultCore is VaultStorage { return _dripperAvailableFunds(dripperReserve, dripper); } - function _dripperAvailableFunds(uint256 _balance, Dripper memory _drip) + function _dripperAvailableFunds(uint256 _reserve, Dripper memory _drip) internal view returns (uint256) { - uint256 dripPerBlock = _drip.perBlock; - if (dripPerBlock == 0) { - return _balance; + uint256 _dripPerBlock = _drip.perBlock; // gas savings + if (_dripPerBlock == 0) { // Prevents forever dripper dust + return _reserve; } uint256 elapsed = block.timestamp - _drip.lastCollect; - uint256 allowed = (elapsed * dripPerBlock); - return (allowed > _balance) ? _balance : allowed; + uint256 allowed = (elapsed * _dripPerBlock); + return (allowed > _reserve) ? _reserve : allowed; } /** From f144ea2c78900e003477d31ddcee7791d9c0bdaa Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Fri, 17 Mar 2023 11:15:33 -0400 Subject: [PATCH 25/34] Set bps to make slither happy --- contracts/contracts/vault/VaultStorage.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index f9ae5ff968..6f8a43f45e 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -124,13 +124,13 @@ contract VaultStorage is Initializable, Governable { uint256 public netOusdMintForStrategyThreshold = 0; // Reserve funds held by the protocol - uint256 public protocolReserve; + uint256 public protocolReserve = 0; // Amount of reserve collected in Bps - uint256 public protocolReserveBps; + uint256 public protocolReserveBps = 0; // Dripper funds held by the protocol - uint256 public dripperReserve; + uint256 public dripperReserve = 0; // Dripper config/state struct Dripper { From 23b375767473e34098cb42d3939b88950c93c670 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Sat, 18 Mar 2023 13:15:17 -0400 Subject: [PATCH 26/34] Dust will be cleared if dripper disabled --- contracts/contracts/vault/VaultCore.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 7abfa48da8..2cc697becb 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -478,9 +478,6 @@ contract VaultCore is VaultStorage { returns (uint256) { uint256 _dripPerBlock = _drip.perBlock; // gas savings - if (_dripPerBlock == 0) { // Prevents forever dripper dust - return _reserve; - } uint256 elapsed = block.timestamp - _drip.lastCollect; uint256 allowed = (elapsed * _dripPerBlock); return (allowed > _reserve) ? _reserve : allowed; From fffaf386671b9150a54ad9962ebc19c086460c35 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Sat, 18 Mar 2023 13:26:50 -0400 Subject: [PATCH 27/34] Only supported assets are a part of reserve calculations --- contracts/contracts/vault/VaultAdmin.sol | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index eef418a287..9b0d6e051d 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -11,7 +11,6 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; -import { IVault } from "../interfaces/IVault.sol"; import "./VaultStorage.sol"; contract VaultAdmin is VaultStorage { @@ -462,12 +461,9 @@ contract VaultAdmin is VaultStorage { external onlyGovernor { + require(assets[_asset].isSupported, "Only supported assets"); protocolReserve -= _amount; IERC20(_asset).safeTransfer(governor(), _amount); - require( - oUSD.totalSupply() < IVault(address(this)).totalValue(), - "Must be solvent" - ); } /*************************************** From 281852b229b5055f7ef57c2429e7810f47b16563 Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Sat, 18 Mar 2023 13:44:45 -0400 Subject: [PATCH 28/34] Without the if, no need to cache on stack --- contracts/contracts/vault/VaultCore.sol | 7 +++---- contracts/contracts/vault/VaultStorage.sol | 1 - 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 2cc697becb..6943de2966 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -412,7 +412,7 @@ contract VaultCore is VaultStorage { return; // Do not distribute funds if assets < liabilities } uint256 _dripperReserve = dripperReserve; // gas savings - + // 1. Calculate new gains, then split them between the dripper and // protocol reserve uint256 usedValue = ousdSupply + protocolReserve + _dripperReserve; @@ -449,7 +449,7 @@ contract VaultCore is VaultStorage { usedValue = ousdSupply + protocolReserve + _dripperReserve; if (vaultValue > usedValue) { uint256 yield = vaultValue - usedValue; - + // Mint trustee fees address _trusteeAddress = trusteeAddress; // gas savings uint256 fee = 0; @@ -477,9 +477,8 @@ contract VaultCore is VaultStorage { view returns (uint256) { - uint256 _dripPerBlock = _drip.perBlock; // gas savings uint256 elapsed = block.timestamp - _drip.lastCollect; - uint256 allowed = (elapsed * _dripPerBlock); + uint256 allowed = (elapsed * _drip.perBlock); return (allowed > _reserve) ? _reserve : allowed; } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 6f8a43f45e..3942a923ab 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -140,7 +140,6 @@ contract VaultStorage is Initializable, Governable { } Dripper public dripper; - /** * @dev set the implementation for the admin, this needs to be in a base class else we cannot set it * @param newImpl address of the implementation From bd6e0cfe206995318d34a12dc0fab6bda59db14d Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Thu, 6 Apr 2023 06:17:30 -0400 Subject: [PATCH 29/34] Flipper N-14 Unused import (#1289) --- contracts/contracts/vault/VaultCore.sol | 2 -- 1 file changed, 2 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 6943de2966..e910a49e9f 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -13,11 +13,9 @@ pragma solidity ^0.8.0; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; -import "@openzeppelin/contracts/utils/Strings.sol"; import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; -import { IVault } from "../interfaces/IVault.sol"; import { IBuyback } from "../interfaces/IBuyback.sol"; import "./VaultStorage.sol"; From 1b92b30f02c29459a5ca998b6ef75faf54c291aa Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 17 Apr 2023 10:22:55 -0400 Subject: [PATCH 30/34] Dripper N-07 better variable name (#1285) --- contracts/contracts/vault/VaultCore.sol | 4 ++-- contracts/contracts/vault/VaultStorage.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index e910a49e9f..f20918b5fd 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -438,7 +438,7 @@ contract VaultCore is VaultStorage { // Write dripper state dripperReserve = _dripperReserve; dripper = Dripper({ - perBlock: uint128(_dripperReserve / _dripDuration), + perSecond: uint128(_dripperReserve / _dripDuration), lastCollect: uint64(block.timestamp), dripDuration: _dripper.dripDuration // must use stored value }); @@ -476,7 +476,7 @@ contract VaultCore is VaultStorage { returns (uint256) { uint256 elapsed = block.timestamp - _drip.lastCollect; - uint256 allowed = (elapsed * _drip.perBlock); + uint256 allowed = (elapsed * _drip.perSecond); return (allowed > _reserve) ? _reserve : allowed; } diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 3942a923ab..0a12c0f564 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -135,7 +135,7 @@ contract VaultStorage is Initializable, Governable { // Dripper config/state struct Dripper { uint64 lastCollect; - uint128 perBlock; + uint128 perSecond; uint64 dripDuration; } Dripper public dripper; From 68efe83722336a69570c50b15d3b22b516b8ab1c Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 17 Apr 2023 10:23:23 -0400 Subject: [PATCH 31/34] Dripper N-10 explicit visibilitiy (#1286) --- contracts/contracts/vault/VaultCore.sol | 6 +++--- contracts/contracts/vault/VaultStorage.sol | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index f20918b5fd..2649a1d89f 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -24,12 +24,12 @@ contract VaultCore is VaultStorage { using StableMath for uint256; using SafeMath for uint256; // max signed int - uint256 constant MAX_INT = 2**255 - 1; + uint256 internal constant MAX_INT = 2**255 - 1; // max un-signed int - uint256 constant MAX_UINT = + uint256 internal constant MAX_UINT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; // impl contract address - address immutable SELF = address(this); + address internal immutable SELF = address(this); /** * @dev Verifies that the rebasing is not paused. diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 0a12c0f564..15fe685f65 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -112,7 +112,7 @@ contract VaultStorage is Initializable, Governable { // Deprecated: Tokens that should be swapped for stablecoins address[] private _deprecated_swapTokens; - uint256 constant MINT_MINIMUM_ORACLE = 99800000; + uint256 internal constant MINT_MINIMUM_ORACLE = 99800000; // Meta strategy that is allowed to mint/burn OUSD without changing collateral address public ousdMetaStrategy = address(0); From 195235172f6fae8d58f655509001e66d3c17034d Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 17 Apr 2023 10:24:54 -0400 Subject: [PATCH 32/34] Flipper N-13 Unused functions (#1288) --- contracts/contracts/vault/VaultCore.sol | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 2649a1d89f..d39d7ef8a4 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -575,19 +575,6 @@ contract VaultCore is VaultStorage { } } - /** - * @notice Get the balance of all assets held in Vault and all strategies. - * @return balance Balance of all assets (1e18) - */ - function _checkBalance() internal view returns (uint256 balance) { - for (uint256 i = 0; i < allAssets.length; i++) { - uint256 assetDecimals = Helpers.getDecimals(allAssets[i]); - balance = balance.add( - _checkBalance(allAssets[i]).scaleBy(18, assetDecimals) - ); - } - } - /** * @notice Calculate the outputs for a redeem function, i.e. the mix of * coins that will be returned From 6d9474965face279b5473ea91881ce11e6f669af Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 17 Apr 2023 10:25:27 -0400 Subject: [PATCH 33/34] Dripper N-14 Imports (#1332) * Flipper N-14 Unused import * Moving imports down to the lowest used level --- contracts/contracts/vault/VaultAdmin.sol | 1 + contracts/contracts/vault/VaultCore.sol | 2 ++ contracts/contracts/vault/VaultStorage.sol | 2 -- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 9b0d6e051d..76bdc0bd1d 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -11,6 +11,7 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; +import { IStrategy } from "../interfaces/IStrategy.sol"; import "./VaultStorage.sol"; contract VaultAdmin is VaultStorage { diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index d39d7ef8a4..48c63c0eba 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -17,6 +17,8 @@ import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import { StableMath } from "../utils/StableMath.sol"; import { IOracle } from "../interfaces/IOracle.sol"; import { IBuyback } from "../interfaces/IBuyback.sol"; +import { IStrategy } from "../interfaces/IStrategy.sol"; +import "../utils/Helpers.sol"; import "./VaultStorage.sol"; contract VaultCore is VaultStorage { diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index 15fe685f65..f4dfeb6e52 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -12,11 +12,9 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { IStrategy } from "../interfaces/IStrategy.sol"; import { Governable } from "../governance/Governable.sol"; import { OUSD } from "../token/OUSD.sol"; import { Initializable } from "../utils/Initializable.sol"; -import "../utils/Helpers.sol"; import { StableMath } from "../utils/StableMath.sol"; contract VaultStorage is Initializable, Governable { From e8136bb47a650ceeae3747dd8ee3e65c5fba075b Mon Sep 17 00:00:00 2001 From: Daniel Von Fange Date: Mon, 17 Apr 2023 10:26:23 -0400 Subject: [PATCH 34/34] Dripper N-12 typos (#1287) * Flipper N-10 explicit visibilitiy * Flipper N-12 typos --- contracts/contracts/vault/VaultAdmin.sol | 2 +- contracts/contracts/vault/VaultCore.sol | 8 ++++---- contracts/contracts/vault/VaultStorage.sol | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/contracts/vault/VaultAdmin.sol b/contracts/contracts/vault/VaultAdmin.sol index 76bdc0bd1d..1dd29341eb 100644 --- a/contracts/contracts/vault/VaultAdmin.sol +++ b/contracts/contracts/vault/VaultAdmin.sol @@ -370,7 +370,7 @@ contract VaultAdmin is VaultStorage { */ function setDripDuration(uint64 _durationSeconds) external onlyGovernor { dripper.dripDuration = _durationSeconds; - emit DriperDurationChanged(_durationSeconds); + emit DripperDurationChanged(_durationSeconds); } /** diff --git a/contracts/contracts/vault/VaultCore.sol b/contracts/contracts/vault/VaultCore.sol index 48c63c0eba..4075a51553 100644 --- a/contracts/contracts/vault/VaultCore.sol +++ b/contracts/contracts/vault/VaultCore.sol @@ -387,7 +387,7 @@ contract VaultCore is VaultStorage { * @dev Update the supply of ousd * * 1. Calculate new gains, splitting gains between the dripper and protocol reserve - * 2. Drip out from the driper and update the dripper storage + * 2. Drip out from the dripper and update the dripper storage * 3. Distribute yield, splitting between trustee fees and rebasing * the remaining post dripper funds to users * @@ -460,7 +460,7 @@ contract VaultCore is VaultStorage { } // Rebase remaining to users - // Invarient: must only increase OUSD supply. + // Invariant: must only increase OUSD supply. // Can only increase because: // ousdSupply + yield >= ousdSupply and yield > fee oUSD.changeSupply(ousdSupply + yield); @@ -502,7 +502,7 @@ contract VaultCore is VaultStorage { /** * @dev Internal to calculate total value of all assets held in Vault. - * @return value Total value in ETH (1e18) + * @return value Total value in USD (1e18) */ function _totalValueInVault() internal view returns (uint256 value) { for (uint256 y = 0; y < allAssets.length; y++) { @@ -517,7 +517,7 @@ contract VaultCore is VaultStorage { /** * @dev Internal to calculate total value of all assets held in Strategies. - * @return value Total value in ETH (1e18) + * @return value Total value in USD (1e18) */ function _totalValueInStrategies() internal view returns (uint256 value) { for (uint256 i = 0; i < allStrategies.length; i++) { diff --git a/contracts/contracts/vault/VaultStorage.sol b/contracts/contracts/vault/VaultStorage.sol index f4dfeb6e52..979706016f 100644 --- a/contracts/contracts/vault/VaultStorage.sol +++ b/contracts/contracts/vault/VaultStorage.sol @@ -45,7 +45,7 @@ contract VaultStorage is Initializable, Governable { event YieldReceived(uint256 _yield); event YieldDistribution(address _to, uint256 _yield, uint256 _fee); event ProtocolReserveBpsChanged(uint256 _basis); - event DriperDurationChanged(uint256 _seconds); + event DripperDurationChanged(uint256 _seconds); event TrusteeFeeBpsChanged(uint256 _basis); event TrusteeAddressChanged(address _address); event NetOusdMintForStrategyThresholdChanged(uint256 _threshold);