diff --git a/src/SablierFlow.sol b/src/SablierFlow.sol index f3eef3ae..1a880a59 100644 --- a/src/SablierFlow.sol +++ b/src/SablierFlow.sol @@ -482,9 +482,8 @@ contract SablierFlow is return _streams[streamId].balance - _coveredDebtOf(streamId); } - /// @notice Calculates the total debt. - /// @dev The total debt is the sum of the snapshot debt and the ongoing debt. This value is independent of the - /// stream's balance. + /// @dev The total debt is the sum of the snapshot debt and the ongoing debt descaled to token's decimal. This + /// value is independent of the stream's balance. function _totalDebtOf(uint256 streamId) internal view returns (uint256) { uint256 scaledTotalDebt = _ongoingDebtScaledOf(streamId) + _streams[streamId].snapshotDebtScaled; return Helpers.descaleAmount({ amount: scaledTotalDebt, decimals: _streams[streamId].tokenDecimals }); diff --git a/src/interfaces/ISablierFlow.sol b/src/interfaces/ISablierFlow.sol index 91d37184..19bf521a 100644 --- a/src/interfaces/ISablierFlow.sol +++ b/src/interfaces/ISablierFlow.sol @@ -121,7 +121,8 @@ interface ISablierFlow is /// @param streamId The stream ID for the query. function depletionTimeOf(uint256 streamId) external view returns (uint256 depletionTime); - /// @notice Returns the amount of debt accrued since the snapshot time until now, denoted in token's decimals. + /// @notice Returns the amount of debt accrued since the snapshot time until now, denoted as a fixed-point number + /// where 1e18 is 1 token. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. function ongoingDebtScaledOf(uint256 streamId) external view returns (uint256 ongoingDebtScaled); diff --git a/tests/fork/Flow.t.sol b/tests/fork/Flow.t.sol index b935f94b..6f40cbf9 100644 --- a/tests/fork/Flow.t.sol +++ b/tests/fork/Flow.t.sol @@ -250,9 +250,9 @@ contract Flow_Fork_Test is Fork_Test { flow.adjustRatePerSecond({ streamId: streamId, newRatePerSecond: newRatePerSecond }); // It should update snapshot debt. - vars.actualSnapshotDebt = flow.getSnapshotDebtScaled(streamId); - vars.expectedSnapshotDebt = ongoingDebtScaled + beforeSnapshotAmount; - assertEq(vars.actualSnapshotDebt, vars.expectedSnapshotDebt, "AdjustRatePerSecond: snapshot debt"); + vars.actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(streamId); + vars.expectedSnapshotDebtScaled = ongoingDebtScaled + beforeSnapshotAmount; + assertEq(vars.actualSnapshotDebtScaled, vars.expectedSnapshotDebtScaled, "AdjustRatePerSecond: snapshot debt"); // It should set the new rate per second vars.actualRatePerSecond = flow.getRatePerSecond(streamId); diff --git a/tests/integration/concrete/adjust-rate-per-second/adjustRatePerSecond.t.sol b/tests/integration/concrete/adjust-rate-per-second/adjustRatePerSecond.t.sol index dbd5f58d..e9c21635 100644 --- a/tests/integration/concrete/adjust-rate-per-second/adjustRatePerSecond.t.sol +++ b/tests/integration/concrete/adjust-rate-per-second/adjustRatePerSecond.t.sol @@ -95,9 +95,9 @@ contract AdjustRatePerSecond_Integration_Concrete_Test is Integration_Test { uint40 expectedSnapshotTime = getBlockTimestamp() - ONE_MONTH; assertEq(actualSnapshotTime, expectedSnapshotTime, "snapshot time"); - uint256 actualSnapshotDebt = flow.getSnapshotDebtScaled(defaultStreamId); - uint128 expectedSnapshotDebt = 0; - assertEq(actualSnapshotDebt, expectedSnapshotDebt, "snapshot debt"); + uint256 actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); + uint128 expectedSnapshotDebtScaled = 0; + assertEq(actualSnapshotDebtScaled, expectedSnapshotDebtScaled, "snapshot debt"); UD21x18 newRatePerSecond = ud21x18(RATE_PER_SECOND.unwrap() / 2); @@ -118,9 +118,9 @@ contract AdjustRatePerSecond_Integration_Concrete_Test is Integration_Test { assertEq(uint8(flow.statusOf(defaultStreamId)), uint8(Flow.Status.STREAMING_SOLVENT), "status not streaming"); // It should update snapshot debt. - actualSnapshotDebt = flow.getSnapshotDebtScaled(defaultStreamId); - expectedSnapshotDebt = ONE_MONTH_DEBT_18D; - assertEq(actualSnapshotDebt, expectedSnapshotDebt, "snapshot debt"); + actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); + expectedSnapshotDebtScaled = ONE_MONTH_DEBT_18D; + assertEq(actualSnapshotDebtScaled, expectedSnapshotDebtScaled, "snapshot debt"); // It should set the new rate per second actualRatePerSecond = flow.getRatePerSecond(defaultStreamId); diff --git a/tests/integration/concrete/deposit-and-pause/depositAndPause.t.sol b/tests/integration/concrete/deposit-and-pause/depositAndPause.t.sol index e4812346..19c4bfb6 100644 --- a/tests/integration/concrete/deposit-and-pause/depositAndPause.t.sol +++ b/tests/integration/concrete/deposit-and-pause/depositAndPause.t.sol @@ -56,7 +56,8 @@ contract DepositAndPause_Integration_Concrete_Test is Integration_Test { function test_WhenCallerSender() external whenNoDelegateCall givenNotNull givenNotPaused { uint128 previousStreamBalance = flow.getBalance(defaultStreamId); - uint256 expectedSnapshotDebt = flow.ongoingDebtScaledOf(defaultStreamId); + uint256 expectedSnapshotDebtScaled = + flow.getSnapshotDebtScaled(defaultStreamId) + flow.ongoingDebtScaledOf(defaultStreamId); // It should emit 1 {Transfer}, 1 {DepositFlowStream}, 1 {PauseFlowStream}, 1 {MetadataUpdate} events vm.expectEmit({ emitter: address(usdc) }); @@ -98,7 +99,7 @@ contract DepositAndPause_Integration_Concrete_Test is Integration_Test { assertEq(actualRatePerSecond, 0, "rate per second"); // It should update the snapshot debt - uint256 actualSnapshotDebt = flow.getSnapshotDebtScaled(defaultStreamId); - assertEq(actualSnapshotDebt, expectedSnapshotDebt, "snapshot debt"); + uint256 actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); + assertEq(actualSnapshotDebtScaled, expectedSnapshotDebtScaled, "snapshot debt"); } } diff --git a/tests/integration/concrete/pause/pause.t.sol b/tests/integration/concrete/pause/pause.t.sol index 431b53f2..51588df6 100644 --- a/tests/integration/concrete/pause/pause.t.sol +++ b/tests/integration/concrete/pause/pause.t.sol @@ -66,8 +66,6 @@ contract Pause_Integration_Concrete_Test is Integration_Test { } function _test_Pause() private { - uint256 expectedSnapshotDebt = flow.ongoingDebtScaledOf(defaultStreamId); - // It should emit 1 {PauseFlowStream}, 1 {MetadataUpdate} events. vm.expectEmit({ emitter: address(flow) }); emit ISablierFlow.PauseFlowStream({ @@ -90,7 +88,7 @@ contract Pause_Integration_Concrete_Test is Integration_Test { assertEq(actualRatePerSecond, 0, "rate per second"); // It should update the snapshot debt. - uint256 actualSnapshotDebt = flow.getSnapshotDebtScaled(defaultStreamId); - assertEq(actualSnapshotDebt, expectedSnapshotDebt, "snapshot debt"); + uint256 actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); + assertEq(actualSnapshotDebtScaled, ONE_MONTH_DEBT_18D, "snapshot debt"); } } diff --git a/tests/integration/concrete/refund-and-pause/refundAndPause.t.sol b/tests/integration/concrete/refund-and-pause/refundAndPause.t.sol index bd8fb078..b7d25a32 100644 --- a/tests/integration/concrete/refund-and-pause/refundAndPause.t.sol +++ b/tests/integration/concrete/refund-and-pause/refundAndPause.t.sol @@ -54,8 +54,6 @@ contract RefundAndPause_Integration_Concrete_Test is Integration_Test { } function test_WhenCallerSender() external whenNoDelegateCall givenNotNull givenNotPaused { - uint256 expectedSnapshotDebt = flow.ongoingDebtScaledOf(defaultStreamId); - // It should emit 1 {Transfer}, 1 {RefundFromFlowStream}, 1 {PauseFlowStream}, 1 {MetadataUpdate} events vm.expectEmit({ emitter: address(usdc) }); emit IERC20.Transfer({ from: address(flow), to: users.sender, value: REFUND_AMOUNT_6D }); @@ -96,7 +94,7 @@ contract RefundAndPause_Integration_Concrete_Test is Integration_Test { assertEq(actualRatePerSecond, 0, "rate per second"); // It should update the snapshot debt - uint256 actualSnapshotDebt = flow.getSnapshotDebtScaled(defaultStreamId); - assertEq(actualSnapshotDebt, expectedSnapshotDebt, "snapshot debt"); + uint256 actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); + assertEq(actualSnapshotDebtScaled, ONE_MONTH_DEBT_18D, "snapshot debt"); } } diff --git a/tests/integration/concrete/total-debt-of/totalDebtOf.t.sol b/tests/integration/concrete/total-debt-of/totalDebtOf.t.sol index fa0f7943..cb8a5071 100644 --- a/tests/integration/concrete/total-debt-of/totalDebtOf.t.sol +++ b/tests/integration/concrete/total-debt-of/totalDebtOf.t.sol @@ -14,24 +14,30 @@ contract TotalDebtOf_Integration_Concrete_Test is Integration_Test { function test_GivenPaused() external givenNotNull { flow.pause(defaultStreamId); - uint256 snapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); - - assertEq(ONE_MONTH_DEBT_18D, snapshotDebtScaled, "total debt"); + assertEq( + flow.totalDebtOf(defaultStreamId), + getDescaledAmount(flow.getSnapshotDebtScaled(defaultStreamId), 6), + "total debt" + ); } function test_WhenCurrentTimeEqualsSnapshotTime() external givenNotNull givenNotPaused { // Set the snapshot time to the current time by changing rate per second. flow.adjustRatePerSecond(defaultStreamId, ud21x18(RATE_PER_SECOND_U128 * 2)); - uint256 snapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); - - assertEq(ONE_MONTH_DEBT_18D, snapshotDebtScaled, "total debt"); + assertEq( + flow.totalDebtOf(defaultStreamId), + getDescaledAmount(flow.getSnapshotDebtScaled(defaultStreamId), 6), + "total debt" + ); } function test_WhenCurrentTimeGreaterThanSnapshotTime() external view givenNotNull givenNotPaused { - uint256 snapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); - uint256 ongoingDebtScaled = flow.ongoingDebtScaledOf(defaultStreamId); + uint256 actualTotalDebt = flow.totalDebtOf(defaultStreamId); + uint256 expectedTotalDebt = getDescaledAmount( + flow.getSnapshotDebtScaled(defaultStreamId) + flow.ongoingDebtScaledOf(defaultStreamId), 6 + ); - assertEq(snapshotDebtScaled + ongoingDebtScaled, ONE_MONTH_DEBT_18D, "total debt"); + assertEq(actualTotalDebt, expectedTotalDebt, "total debt"); } } diff --git a/tests/integration/concrete/total-debt-of/totalDebtOf.tree b/tests/integration/concrete/total-debt-of/totalDebtOf.tree index 68f1c7f9..95baf368 100644 --- a/tests/integration/concrete/total-debt-of/totalDebtOf.tree +++ b/tests/integration/concrete/total-debt-of/totalDebtOf.tree @@ -3,7 +3,7 @@ TotalDebtOf_Integration_Concrete_Test │ └── it should revert └── given not null ├── given paused - │ └── it should return snapshot debt + │ └── it should return the └── given not paused ├── when current time equals snapshot time │ └── it should return snapshot debt diff --git a/tests/integration/concrete/withdraw-max/withdrawMax.t.sol b/tests/integration/concrete/withdraw-max/withdrawMax.t.sol index 3a4a9f01..74ce0824 100644 --- a/tests/integration/concrete/withdraw-max/withdrawMax.t.sol +++ b/tests/integration/concrete/withdraw-max/withdrawMax.t.sol @@ -71,8 +71,8 @@ contract WithdrawMax_Integration_Concrete_Test is Integration_Test { assertEq(vars.actualStreamBalance, vars.expectedStreamBalance, "stream balance"); // It should set the snapshot debt to zero. - vars.actualSnapshotDebt = flow.getSnapshotDebtScaled(defaultStreamId); - assertEq(vars.actualSnapshotDebt, 0, "snapshot debt"); + vars.actualSnapshotDebtScaled = flow.getSnapshotDebtScaled(defaultStreamId); + assertEq(vars.actualSnapshotDebtScaled, 0, "snapshot debt"); if (flow.getRatePerSecond(defaultStreamId).unwrap() > 0) { // It should update snapshot time. diff --git a/tests/utils/Vars.sol b/tests/utils/Vars.sol index 0298dad1..cb4ef013 100644 --- a/tests/utils/Vars.sol +++ b/tests/utils/Vars.sol @@ -20,7 +20,7 @@ struct Vars { uint128 actualProtocolFeeAmount; uint128 actualProtocolRevenue; UD21x18 actualRatePerSecond; - uint256 actualSnapshotDebt; + uint256 actualSnapshotDebtScaled; uint40 actualSnapshotTime; uint128 actualStreamBalance; uint256 actualStreamId; @@ -32,7 +32,7 @@ struct Vars { uint128 expectedProtocolFeeAmount; uint128 expectedProtocolRevenue; UD21x18 expectedRatePerSecond; - uint256 expectedSnapshotDebt; + uint256 expectedSnapshotDebtScaled; uint40 expectedSnapshotTime; uint128 expectedStreamBalance; uint256 expectedStreamId;