Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upfront interest #170

Closed
wants to merge 12 commits into from
3 changes: 3 additions & 0 deletions contracts/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ out/
/broadcast/*/1337/
/broadcast/**/dry-run/

# Created by `forge snapshot`
/.gas-snapshot

# Docs
docs/

Expand Down
46 changes: 32 additions & 14 deletions contracts/src/ActivePool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ contract ActivePool is Ownable, CheckContract, IActivePool {
*/
uint256 public aggWeightedDebtSum;

// Sum of recorded upfront interest. This is an upper bound on the total outstanding upfront interest.
// Some fraction of this will have already been cancelled out by accrued interest.
uint256 public aggRecordedUpfrontInterest;

// Last time at which the aggregate recorded debt and weighted sum were updated
uint256 public lastAggUpdateTime;

Expand Down Expand Up @@ -119,10 +123,14 @@ contract ActivePool is Ownable, CheckContract, IActivePool {
}

// Returns sum of agg.recorded debt plus agg. pending interest. Excludes pending redist. gains.
function getTotalActiveDebt() public view returns (uint256) {
function getBoldDebtLowerBound() external view returns (uint256) {
return aggRecordedDebt + calcPendingAggInterest();
}

function getBoldDebtUpperBound() external view returns (uint256) {
return aggRecordedDebt + calcPendingAggInterest() + aggRecordedUpfrontInterest;
}

// --- Pool functionality ---

function sendETH(address _account, uint256 _amount) external override {
Expand Down Expand Up @@ -181,41 +189,51 @@ contract ActivePool is Ownable, CheckContract, IActivePool {
// The net Trove debt change could be positive or negative in a repayment (depending on whether its redistribution gain or repayment amount is larger),
// so this function accepts both the increase and the decrease to avoid using (and converting to/from) signed ints.
function mintAggInterestAndAccountForTroveChange(
uint256 _troveDebtIncrease,
uint256 _troveDebtDecrease,
uint256 _newWeightedRecordedTroveDebt,
uint256 _oldWeightedRecordedTroveDebt
uint256 _appliedRedistBoldDebtGain,
uint256 _debtIncrease,
uint256 _debtDecrease,
uint256 _newWeightedRecordedDebt,
uint256 _oldWeightedRecordedDebt,
uint256 _newRecordedUpfrontInterest,
uint256 _oldRecordedUpfrontInterest,
uint256 _forgoneUpfrontInterest
) external {
_requireCallerIsBOorTroveM();

// Do the arithmetic in 2 steps here to avoid overflow from the decrease
uint256 newAggRecordedDebt = aggRecordedDebt; // 1 SLOAD
newAggRecordedDebt += _mintAggInterest();
newAggRecordedDebt += _troveDebtIncrease;
newAggRecordedDebt -= _troveDebtDecrease;
newAggRecordedDebt += _mintAggInterest(_forgoneUpfrontInterest); // adds minted agg. + forgone upfront interest
newAggRecordedDebt += _appliedRedistBoldDebtGain;
newAggRecordedDebt += _debtIncrease;
newAggRecordedDebt -= _debtDecrease;
aggRecordedDebt = newAggRecordedDebt; // 1 SSTORE

// assert(aggRecordedDebt >= 0) // This should never be negative. If all redistribution gians and all aggregate interest was applied
// and all Trove debts were repaid, it should become 0.

// Do the arithmetic in 2 steps here to avoid overflow from the decrease
uint256 newAggWeightedDebtSum = aggWeightedDebtSum; // 1 SLOAD
newAggWeightedDebtSum += _newWeightedRecordedTroveDebt;
newAggWeightedDebtSum -= _oldWeightedRecordedTroveDebt;
newAggWeightedDebtSum += _newWeightedRecordedDebt;
newAggWeightedDebtSum -= _oldWeightedRecordedDebt;
aggWeightedDebtSum = newAggWeightedDebtSum; // 1 SSTORE

uint256 newAggRecordedUpfrontInterest = aggRecordedUpfrontInterest;
newAggRecordedUpfrontInterest += _newRecordedUpfrontInterest;
newAggRecordedUpfrontInterest -= _oldRecordedUpfrontInterest;
aggRecordedUpfrontInterest = newAggRecordedUpfrontInterest; // 1 SSTORE
}

function mintAggInterest() external override {
_requireCallerIsSP();
aggRecordedDebt += _mintAggInterest();
aggRecordedDebt += _mintAggInterest(0);
}

function _mintAggInterest() internal returns (uint256 aggInterest) {
aggInterest = calcPendingAggInterest();
function _mintAggInterest(uint256 _forgoneUpfrontInterest) internal returns (uint256 aggDebtIncrease) {
aggDebtIncrease = calcPendingAggInterest() + _forgoneUpfrontInterest;

// Mint the new BOLD interest to a mock interest router that would split it and send it onward to SP, LP staking, etc.
// TODO: implement interest routing and SP Bold reward tracking
if (aggInterest > 0) boldToken.mint(address(interestRouter), aggInterest);
if (aggDebtIncrease > 0) boldToken.mint(address(interestRouter), aggDebtIncrease);

lastAggUpdateTime = block.timestamp;
}
Expand Down
Loading