Skip to content

Commit

Permalink
test: add Shared_Integration_Concrete_Test
Browse files Browse the repository at this point in the history
  • Loading branch information
smol-ninja committed Nov 11, 2024
1 parent 8b32598 commit d524cc8
Show file tree
Hide file tree
Showing 35 changed files with 248 additions and 216 deletions.
6 changes: 4 additions & 2 deletions tests/Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import { ERC20Mock } from "./mocks/ERC20Mock.sol";
import { Assertions } from "./utils/Assertions.sol";
import { Modifiers } from "./utils/Modifiers.sol";
import { Users } from "./utils/Types.sol";
import { Utils } from "./utils/Utils.sol";
import { Vars } from "./utils/Vars.sol";

abstract contract Base_Test is Assertions, Modifiers, Test, Utils {
abstract contract Base_Test is Assertions, Modifiers, Test {
/*//////////////////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -65,6 +64,9 @@ abstract contract Base_Test is Assertions, Modifiers, Test, Utils {
users.recipient = createUser("recipient");
users.sender = createUser("sender");

// Set the variables in Modifiers contract.
setVariables(users);

resetPrank(users.sender);

// Warp to May 1, 2024 at 00:00 GMT to provide a more realistic testing environment.
Expand Down
136 changes: 1 addition & 135 deletions tests/integration/Integration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,18 @@ pragma solidity >=0.8.22;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol";

import { Errors } from "src/libraries/Errors.sol";
import { Broker, Flow } from "src/types/DataTypes.sol";
import { Broker } from "src/types/DataTypes.sol";

import { Base_Test } from "../Base.t.sol";

/// @notice Common logic needed by all integration tests, both concrete and fuzz tests.
abstract contract Integration_Test is Base_Test {
/*//////////////////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////////////////*/

Broker internal defaultBroker;
uint256 internal defaultStreamId;
uint256 internal nullStreamId = 420;

/*//////////////////////////////////////////////////////////////////////////
SET-UP
//////////////////////////////////////////////////////////////////////////*/

function setUp() public virtual override {
Base_Test.setUp();

defaultBroker = broker();
defaultStreamId = createDefaultStream();

// Simulate one month of streaming.
vm.warp({ newTimestamp: WARP_ONE_MONTH });
}

/*//////////////////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////////////////*/

modifier givenBalanceNotZero() override {
// Deposit into the stream.
depositToDefaultStream();
_;
}

modifier whenCallerAdmin() override {
resetPrank({ msgSender: users.admin });
_;
}

/*//////////////////////////////////////////////////////////////////////////
Expand All @@ -56,10 +26,6 @@ abstract contract Integration_Test is Base_Test {
return Broker({ account: users.broker, fee: BROKER_FEE });
}

function createDefaultStream() internal returns (uint256) {
return createDefaultStream(usdc);
}

function createDefaultStream(IERC20 token_) internal returns (uint256) {
return createDefaultStream(RATE_PER_SECOND, token_);
}
Expand All @@ -86,26 +52,6 @@ abstract contract Integration_Test is Base_Test {
streamId = createDefaultStream(ratePerSecond, token);
}

function defaultStream() internal view returns (Flow.Stream memory) {
return Flow.Stream({
balance: 0,
snapshotTime: getBlockTimestamp(),
isStream: true,
isTransferable: TRANSFERABLE,
isVoided: false,
ratePerSecond: RATE_PER_SECOND,
snapshotDebtScaled: 0,
sender: users.sender,
token: usdc,
tokenDecimals: DECIMALS
});
}

function defaultStreamWithDeposit() internal view returns (Flow.Stream memory stream) {
stream = defaultStream();
stream.balance = DEPOSIT_AMOUNT_6D;
}

function deposit(uint256 streamId, uint128 amount) internal {
IERC20 token = flow.getToken(streamId);

Expand All @@ -122,10 +68,6 @@ abstract contract Integration_Test is Base_Test {
deposit(streamId, depositAmount);
}

function depositToDefaultStream() internal {
deposit(defaultStreamId, DEPOSIT_AMOUNT_6D);
}

/// @dev Update the snapshot using `adjustRatePerSecond` and then warp block timestamp to it.
function updateSnapshotTimeAndWarp(uint256 streamId) internal {
resetPrank(users.sender);
Expand All @@ -140,80 +82,4 @@ abstract contract Integration_Test is Base_Test {
// Warp to the snapshot time.
vm.warp({ newTimestamp: flow.getSnapshotTime(streamId) });
}

/*//////////////////////////////////////////////////////////////////////////
COMMON-REVERT-TESTS
//////////////////////////////////////////////////////////////////////////*/

function expectRevert_CallerMaliciousThirdParty(bytes memory callData) internal {
resetPrank({ msgSender: users.eve });
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "malicious call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_Unauthorized.selector, defaultStreamId, users.eve),
"malicious call return data"
);
}

function expectRevert_CallerRecipient(bytes memory callData) internal {
resetPrank({ msgSender: users.recipient });
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "recipient call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_Unauthorized.selector, defaultStreamId, users.recipient),
"recipient call return data"
);
}

function expectRevert_CallerSender(bytes memory callData) internal {
resetPrank({ msgSender: users.sender });
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "sender call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_Unauthorized.selector, defaultStreamId, users.sender),
"sender call return data"
);
}

function expectRevert_DelegateCall(bytes memory callData) internal {
(bool success, bytes memory returnData) = address(flow).delegatecall(callData);
assertFalse(success, "delegatecall success");
assertEq(returnData, abi.encodeWithSelector(Errors.DelegateCall.selector), "delegatecall return data");
}

function expectRevert_Null(bytes memory callData) internal {
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "null call success");
assertEq(
returnData, abi.encodeWithSelector(Errors.SablierFlow_Null.selector, nullStreamId), "null call return data"
);
}

function expectRevert_Voided(bytes memory callData) internal {
// Simulate the passage of time to accumulate uncovered debt for one month.
vm.warp({ newTimestamp: WARP_SOLVENCY_PERIOD + ONE_MONTH });
flow.void(defaultStreamId);

(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "voided call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_StreamVoided.selector, defaultStreamId),
"voided call return data"
);
}

function expectRevert_Paused(bytes memory callData) internal {
flow.pause(defaultStreamId);
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "paused call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_StreamPaused.selector, defaultStreamId),
"paused call return data"
);
}
}
149 changes: 149 additions & 0 deletions tests/integration/concrete/Concrete.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.22;

import { Errors } from "src/libraries/Errors.sol";
import { Broker, Flow } from "src/types/DataTypes.sol";

import { Integration_Test } from "../Integration.t.sol";

abstract contract Shared_Integration_Concrete_Test is Integration_Test {
/*//////////////////////////////////////////////////////////////////////////
VARIABLES
//////////////////////////////////////////////////////////////////////////*/

Broker internal defaultBroker;
uint256 internal defaultStreamId;
uint256 internal nullStreamId = 420;

/*//////////////////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////////////////*/

modifier givenBalanceNotZero() override {
// Deposit into the stream.
depositToDefaultStream();
_;
}

/*//////////////////////////////////////////////////////////////////////////
SET-UP
//////////////////////////////////////////////////////////////////////////*/

function setUp() public virtual override {
Integration_Test.setUp();

defaultBroker = broker();
defaultStreamId = createDefaultStream();

// Simulate one month of streaming.
vm.warp({ newTimestamp: WARP_ONE_MONTH });
}

/*//////////////////////////////////////////////////////////////////////////
HELPERS
//////////////////////////////////////////////////////////////////////////*/

function createDefaultStream() internal returns (uint256) {
return createDefaultStream(usdc);
}

function defaultStream() internal view returns (Flow.Stream memory) {
return Flow.Stream({
balance: 0,
snapshotTime: getBlockTimestamp(),
isStream: true,
isTransferable: TRANSFERABLE,
isVoided: false,
ratePerSecond: RATE_PER_SECOND,
snapshotDebtScaled: 0,
sender: users.sender,
token: usdc,
tokenDecimals: DECIMALS
});
}

function defaultStreamWithDeposit() internal view returns (Flow.Stream memory stream) {
stream = defaultStream();
stream.balance = DEPOSIT_AMOUNT_6D;
}

function depositToDefaultStream() internal {
deposit(defaultStreamId, DEPOSIT_AMOUNT_6D);
}

/*//////////////////////////////////////////////////////////////////////////
COMMON-REVERT-TESTS
//////////////////////////////////////////////////////////////////////////*/

function expectRevert_CallerMaliciousThirdParty(bytes memory callData) internal {
resetPrank({ msgSender: users.eve });
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "malicious call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_Unauthorized.selector, defaultStreamId, users.eve),
"malicious call return data"
);
}

function expectRevert_CallerRecipient(bytes memory callData) internal {
resetPrank({ msgSender: users.recipient });
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "recipient call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_Unauthorized.selector, defaultStreamId, users.recipient),
"recipient call return data"
);
}

function expectRevert_CallerSender(bytes memory callData) internal {
resetPrank({ msgSender: users.sender });
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "sender call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_Unauthorized.selector, defaultStreamId, users.sender),
"sender call return data"
);
}

function expectRevert_DelegateCall(bytes memory callData) internal {
(bool success, bytes memory returnData) = address(flow).delegatecall(callData);
assertFalse(success, "delegatecall success");
assertEq(returnData, abi.encodeWithSelector(Errors.DelegateCall.selector), "delegatecall return data");
}

function expectRevert_Null(bytes memory callData) internal {
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "null call success");
assertEq(
returnData, abi.encodeWithSelector(Errors.SablierFlow_Null.selector, nullStreamId), "null call return data"
);
}

function expectRevert_Voided(bytes memory callData) internal {
// Simulate the passage of time to accumulate uncovered debt for one month.
vm.warp({ newTimestamp: WARP_SOLVENCY_PERIOD + ONE_MONTH });
flow.void(defaultStreamId);

(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "voided call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_StreamVoided.selector, defaultStreamId),
"voided call return data"
);
}

function expectRevert_Paused(bytes memory callData) internal {
flow.pause(defaultStreamId);
(bool success, bytes memory returnData) = address(flow).call(callData);
assertFalse(success, "paused call success");
assertEq(
returnData,
abi.encodeWithSelector(Errors.SablierFlow_StreamPaused.selector, defaultStreamId),
"paused call return data"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { ISablierFlow } from "src/interfaces/ISablierFlow.sol";
import { Errors } from "src/libraries/Errors.sol";
import { Flow } from "src/types/DataTypes.sol";

import { Integration_Test } from "./../../Integration.t.sol";
import { Shared_Integration_Concrete_Test } from "./../Concrete.t.sol";

contract AdjustRatePerSecond_Integration_Concrete_Test is Integration_Test {
contract AdjustRatePerSecond_Integration_Concrete_Test is Shared_Integration_Concrete_Test {
function test_RevertWhen_DelegateCall() external {
bytes memory callData = abi.encodeCall(flow.adjustRatePerSecond, (defaultStreamId, RATE_PER_SECOND));
expectRevert_DelegateCall(callData);
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/concrete/batch/batch.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ud21x18, UD21x18 } from "@prb/math/src/UD21x18.sol";
import { ISablierFlow } from "src/interfaces/ISablierFlow.sol";
import { Errors } from "src/libraries/Errors.sol";
import { Integration_Test } from "./../../Integration.t.sol";
import { Shared_Integration_Concrete_Test } from "./../Concrete.t.sol";

contract Batch_Integration_Concrete_Test is Integration_Test {
contract Batch_Integration_Concrete_Test is Shared_Integration_Concrete_Test {
uint256[] internal defaultStreamIds;

function setUp() public override {
Integration_Test.setUp();
Shared_Integration_Concrete_Test.setUp();
defaultStreamIds.push(defaultStreamId);

// Create a second stream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ISablierFlowBase } from "src/interfaces/ISablierFlowBase.sol";
import { Errors } from "src/libraries/Errors.sol";

import { Integration_Test } from "./../../Integration.t.sol";
import { Shared_Integration_Concrete_Test } from "./../Concrete.t.sol";

contract CollectProtocolRevenue_Integration_Concrete_Test is Integration_Test {
contract CollectProtocolRevenue_Integration_Concrete_Test is Shared_Integration_Concrete_Test {
uint256 internal streamIdWithProtocolFee;

function setUp() public override {
Integration_Test.setUp();
Shared_Integration_Concrete_Test.setUp();

// Go back in time to create a stream with a protocol fee.
vm.warp({ newTimestamp: OCT_1_2024 });
Expand Down
Loading

0 comments on commit d524cc8

Please sign in to comment.