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

Refactor/cancel to pause #113

Merged
merged 12 commits into from
May 24, 2024
Prev Previous commit
Next Next commit
refactor: say "recipientAmount" instead of sum in _withdrawableAmount…
…Of function

test: be more precise for caller test branches
test: remove unneeded test for pause function
docs: correct invariants
  • Loading branch information
andreivladbrg committed May 23, 2024
commit 886c5d20d422585cdbe40b048613ec4613acae9b
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ The refundable amount is calculated by subtracting the streamed amount from the
| streamedAmount | sa |
| debt | debt |
| withdrawableAmount | wa |
| refundableAmount | ra |
| refundableAmount | rfa |

### Issues:

Expand Down Expand Up @@ -147,11 +147,9 @@ _wa ≤ bal_

_if(debt = 0) then wa = sa + ra_

_if(debt > 0 && ra <= bal) then wa = ra_
_if(debt = 0 && isPaused = true) then wa = ra_

_if(debt > 0 && ra > bal) then wa = bal_

_ra ≤ sa(from create time to now)_
_if(debt > 0) then wa = bal_

_bal = sum of deposits - sum of withdrawals_

Expand Down
6 changes: 3 additions & 3 deletions src/SablierV2OpenEnded.sol
Original file line number Diff line number Diff line change
Expand Up @@ -379,13 +379,13 @@ contract SablierV2OpenEnded is
// Calculate the streamed amount since last update.
uint128 streamedAmount = _streamedAmountOf(streamId, time);

uint128 sum = streamedAmount + remainingAmount;
uint128 recipientAmount = streamedAmount + remainingAmount;

// If there has been streamed more than how much is available, return the stream balance.
if (sum > balance) {
if (recipientAmount > balance) {
return balance;
} else {
return sum;
return recipientAmount;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract AdjustRatePerSecond_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.recipient });
vm.expectRevert(
Expand All @@ -46,7 +46,7 @@ contract AdjustRatePerSecond_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.eve });
vm.expectRevert(
Expand All @@ -60,7 +60,7 @@ contract AdjustRatePerSecond_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
whenCallerIsTheSender
{
vm.expectRevert(Errors.SablierV2OpenEnded_RatePerSecondZero.selector);
openEnded.adjustRatePerSecond({ streamId: defaultStreamId, newRatePerSecond: 0 });
Expand All @@ -71,7 +71,7 @@ contract AdjustRatePerSecond_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
whenCallerIsTheSender
whenRatePerSecondNonZero
{
vm.expectRevert(
Expand All @@ -85,7 +85,7 @@ contract AdjustRatePerSecond_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
whenCallerIsTheSender
whenRatePerSecondNonZero
whenRatePerSecondNotDifferent
{
Expand Down Expand Up @@ -131,7 +131,7 @@ contract AdjustRatePerSecond_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
whenCallerIsTheSender
{
openEnded.deposit(defaultStreamId, DEPOSIT_AMOUNT);
vm.warp({ newTimestamp: WARP_ONE_MONTH });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ adjustRatePerSecond.t.sol
├── given the id references a paused stream
│ └── it should revert
└── given the id does not reference a paused stream
├── when the caller is unauthorized
├── when the caller is not the sender
│ ├── when the caller is the recipient
│ │ └── it should revert
│ └── when the caller is a malicious third party
│ └── it should revert
└── when the caller is authorized
└── when the caller is the sender
├── when the provided rate per second is zero
│ └── it should revert
└── when the provided rate per second is not zero
Expand Down
42 changes: 7 additions & 35 deletions test/integration/pause/pause.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ contract Pause_Integration_Test is Integration_Test {
openEnded.pause(defaultStreamId);
}

function test_RevertWhen_CallerUnauthorized_Recipient()
function test_RevertWhen_CallerRecipient()
external
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.recipient });
vm.expectRevert(
Expand All @@ -42,12 +42,12 @@ contract Pause_Integration_Test is Integration_Test {
openEnded.pause(defaultStreamId);
}

function test_RevertWhen_CallerUnauthorized_MaliciousThirdParty()
function test_RevertWhen_CallerMaliciousThirdParty()
external
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.eve });
vm.expectRevert(
Expand All @@ -56,12 +56,12 @@ contract Pause_Integration_Test is Integration_Test {
openEnded.pause(defaultStreamId);
}

function test_Pause_WithdrawableAmountZero()
function test_Pause_StreamHasDebt()
external
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
whenCallerIsTheSender
{
assertEq(openEnded.refundableAmountOf(defaultStreamId), 0, "refundable amount before pause");
assertEq(openEnded.withdrawableAmountOf(defaultStreamId), 0, "withdrawable amount before pause");
Expand All @@ -81,40 +81,12 @@ contract Pause_Integration_Test is Integration_Test {
assertEq(actualStreamBalance, 0, "stream balance");
}

function test_Pause_RefundableAmountZero()
external
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
givenWithdrawableAmountNotZero
{
openEnded.deposit(defaultStreamId, WITHDRAW_AMOUNT);

assertEq(openEnded.getBalance(defaultStreamId), WITHDRAW_AMOUNT, "balance before");
assertEq(openEnded.withdrawableAmountOf(defaultStreamId), WITHDRAW_AMOUNT, "withdrawable amount before pause");

openEnded.pause(defaultStreamId);

assertTrue(openEnded.isPaused(defaultStreamId), "is paused");

uint128 actualRatePerSecond = openEnded.getRatePerSecond(defaultStreamId);
assertEq(actualRatePerSecond, 0, "rate per second");

uint128 actualRemainingAmount = openEnded.getRemainingAmount(defaultStreamId);
uint128 expectedRemainingAmount = ONE_MONTH_STREAMED_AMOUNT;
assertEq(actualRemainingAmount, expectedRemainingAmount, "remaining amount");

uint128 actualStreamBalance = openEnded.getBalance(defaultStreamId);
assertEq(actualStreamBalance, WITHDRAW_AMOUNT, "stream balance");
}

function test_Pause()
external
whenNotDelegateCalled
givenNotNull
givenNotPaused
whenCallerAuthorized
whenCallerIsTheSender
givenWithdrawableAmountNotZero
givenRefundableAmountNotZero
{
Expand Down
26 changes: 11 additions & 15 deletions test/integration/pause/pause.tree
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,19 @@ pause.t.sol
├── given the id references a paused stream
│ └── it should revert
└── given the id does not reference a paused stream
├── when the caller is unauthorized
├── when the caller is not the sender
│ ├── when the caller is the recipient
│ │ └── it should revert
│ └── when the caller is a malicious third party
│ └── it should revert
└── when the caller is authorized
├── given the withdrawable amount is zero
└── when the caller is the sender
├── given the stream has debt
│ ├── it should pause the stream
│ └── it should set the rate per second to zero
└── given the withdrawable amount is not zero
├── given the refundable amount is zero
│ ├── it should pause the stream
│ ├── it should set the rate per second to zero
│ └── it should update the remaining amount
└── given thet refundable amount is not zero
├── it should pause the stream
├── it should set the rate per second to zero
├── it should update the remaining amount
├── it should emit a {PauseOpenEndedStream} event
└── it should emit a {MetadataUpdate} event
│ ├── it should set the rate per second to zero
│ └── it should update the remaining amount
└── given the stream does not have debt
├── it should pause the stream
├── it should set the rate per second to zero
├── it should update the remaining amount
├── it should emit a {PauseOpenEndedStream} event
└── it should emit a {MetadataUpdate} event
14 changes: 7 additions & 7 deletions test/integration/refund-from-stream/refundFromStream.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
external
whenNotDelegateCalled
givenNotNull
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.recipient });
vm.expectRevert(
Expand All @@ -44,7 +44,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
external
whenNotDelegateCalled
givenNotNull
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.eve });
vm.expectRevert(
Expand All @@ -53,7 +53,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
openEnded.refundFromStream({ streamId: defaultStreamId, amount: REFUND_AMOUNT });
}

function test_RevertWhen_RefundAmountZero() external whenNotDelegateCalled givenNotNull whenCallerAuthorized {
function test_RevertWhen_RefundAmountZero() external whenNotDelegateCalled givenNotNull whenCallerIsTheSender {
vm.expectRevert(Errors.SablierV2OpenEnded_RefundAmountZero.selector);
openEnded.refundFromStream({ streamId: defaultStreamId, amount: 0 });
}
Expand All @@ -62,7 +62,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
external
whenNotDelegateCalled
givenNotNull
whenCallerAuthorized
whenCallerIsTheSender
whenRefundAmountNotZero
{
vm.expectRevert(
Expand All @@ -76,7 +76,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
openEnded.refundFromStream({ streamId: defaultStreamId, amount: DEPOSIT_AMOUNT });
}

function test_RefundFromStream_PausedStream() external whenNotDelegateCalled givenNotNull whenCallerAuthorized {
function test_RefundFromStream_PausedStream() external whenNotDelegateCalled givenNotNull whenCallerIsTheSender {
openEnded.pause(defaultStreamId);

expectCallToTransfer({ asset: dai, to: users.sender, amount: REFUND_AMOUNT });
Expand All @@ -91,7 +91,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
external
whenNotDelegateCalled
givenNotNull
whenCallerAuthorized
whenCallerIsTheSender
whenRefundAmountNotZero
whenNoOverrefund
{
Expand All @@ -108,7 +108,7 @@ contract RefundFromStream_Integration_Test is Integration_Test {
external
whenNotDelegateCalled
givenNotNull
whenCallerAuthorized
whenCallerIsTheSender
whenRefundAmountNotZero
whenNoOverrefund
{
Expand Down
4 changes: 2 additions & 2 deletions test/integration/refund-from-stream/refundFromStream.tree
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ refundFromStream.t.sol
├── given the id references a null stream
│ └── it should revert
└── given the id does not reference a null stream
├── when the caller is unauthorized
├── when the caller is not the sender
│ ├── when the caller is the recipient
│ │ └── it should revert
│ └── when the caller is a malicious third party
│ └── it should revert
└── when the caller is authorized
└── when the caller is the sender
├── when the refund amount is zero
│ └── it should revert
└── when the refund amount is not zero
Expand Down
8 changes: 4 additions & 4 deletions test/integration/restart-stream/restartStream.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ contract RestartStream_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenPaused
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.recipient });
vm.expectRevert(
Expand All @@ -48,7 +48,7 @@ contract RestartStream_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenPaused
whenCallerUnauthorized
whenCallerIsNotTheSender
{
resetPrank({ msgSender: users.eve });
vm.expectRevert(
Expand All @@ -62,7 +62,7 @@ contract RestartStream_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenPaused
whenCallerAuthorized
whenCallerIsTheSender
{
vm.expectRevert(Errors.SablierV2OpenEnded_RatePerSecondZero.selector);
openEnded.restartStream({ streamId: defaultStreamId, ratePerSecond: 0 });
Expand All @@ -73,7 +73,7 @@ contract RestartStream_Integration_Test is Integration_Test {
whenNotDelegateCalled
givenNotNull
givenPaused
whenCallerAuthorized
whenCallerIsTheSender
whenRatePerSecondNonZero
{
vm.expectEmit({ emitter: address(openEnded) });
Expand Down
4 changes: 2 additions & 2 deletions test/integration/restart-stream/restartStream.tree
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ restartStream.t.sol
├── given the id does not references a paused stream
│ └── it should revert
└── given the id reference a paused stream
├── when the caller is unauthorized
├── when the caller is not the sender
│ ├── when the caller is the sender
│ │ └── it should revert
│ └── when the caller is a malicious third party
│ └── it should revert
└── when the caller is authorized
└── when the caller is the sender
├── when the provided rate per second is zero
│ └── it should revert
└── when the provided rate per second is not zero
Expand Down
4 changes: 2 additions & 2 deletions test/invariant/handlers/OpenEndedCreateHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ contract OpenEndedCreateHandler is BaseHandler {
openEnded.create(params.sender, params.recipient, params.ratePerSecond, asset, params.isTransferable);

// Store the stream id.
openEndedStore.pushStreamId(streamId, params.sender, params.recipient, openEnded.getLastTimeUpdate(streamId));
openEndedStore.pushStreamId(streamId, params.sender, params.recipient);
}

function createAndDeposit(
Expand Down Expand Up @@ -104,7 +104,7 @@ contract OpenEndedCreateHandler is BaseHandler {
);

// Store the stream id.
openEndedStore.pushStreamId(streamId, params.sender, params.recipient, openEnded.getLastTimeUpdate(streamId));
openEndedStore.pushStreamId(streamId, params.sender, params.recipient);

// Store the deposited amount.
openEndedStore.updateStreamDepositedAmountsSum(streamId, depositAmount);
Expand Down
Loading