From 9c8ff1ff1af90f08f488ddb048aaaef89bf35c1e Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 12 Aug 2024 16:13:36 +0530 Subject: [PATCH] test: dry-ify the merkle tests (#1009) test: polish shared tests --- test/periphery/Periphery.t.sol | 4 + test/periphery/fork/Fork.t.sol | 2 +- .../createWithDurationsLD.t.sol | 2 +- .../createWithDurationsLL.t.sol | 2 +- .../createWithDurationsLT.t.sol | 2 +- .../createWithTimestampsLD.t.sol | 2 +- .../createWithTimestamps.t.sol | 2 +- .../createWithTimestampsLT.t.sol | 2 +- .../merkle-campaign/MerkleCampaign.t.sol | 6 +- .../instant/MerkleInstant.t.sol | 90 +++++++++++++++++++ .../merkle-campaign/instant/claim/claim.t.sol | 2 +- .../instant/clawback/clawback.t.sol | 80 ----------------- .../{constructor => }/constructor.t.sol | 2 +- .../getFirstClaimTime.t.sol | 22 ----- .../instant/has-claimed/hasClaimed.t.sol | 28 ------ .../instant/has-expired/hasExpired.t.sol | 31 ------- .../merkle-campaign/ll/MerkleLL.t.sol | 81 +++++++++++++++++ .../merkle-campaign/ll/claim/claim.t.sol | 2 +- .../ll/clawback/clawback.t.sol | 80 ----------------- .../merkle-campaign/ll/clawback/clawback.tree | 17 ---- .../ll/{constructor => }/constructor.t.sol | 2 +- .../getFirstClaimTime.t.sol | 22 ----- .../getFirstClaimTime.tree | 5 -- .../ll/has-claimed/hasClaimed.t.sol | 28 ------ .../ll/has-claimed/hasClaimed.tree | 8 -- .../ll/has-expired/hasExpired.t.sol | 31 ------- .../ll/has-expired/hasExpired.tree | 10 --- .../merkle-campaign/lt/MerkleLT.t.sol | 81 +++++++++++++++++ .../merkle-campaign/lt/claim/claim.t.sol | 2 +- .../merkle-campaign/lt/clawback/clawback.tree | 17 ---- .../lt/{constructor => }/constructor.t.sol | 2 +- .../getFirstClaimTime.t.sol | 22 ----- .../getFirstClaimTime.tree | 5 -- .../lt/has-claimed/hasClaimed.t.sol | 28 ------ .../lt/has-claimed/hasClaimed.tree | 8 -- .../lt/has-expired/hasExpired.t.sol | 31 ------- .../lt/has-expired/hasExpired.tree | 10 --- .../shared/MerkleCampaign.t.sol | 56 ++++++++++++ .../{lt => shared}/clawback/clawback.t.sol | 38 +++----- .../clawback/clawback.tree | 0 .../getFirstClaimTime.t.sol | 20 +++++ .../getFirstClaimTime.tree | 0 .../shared/has-claimed/hasClaimed.t.sol | 23 +++++ .../has-claimed/hasClaimed.tree | 0 .../shared/has-expired/hasExpired.t.sol | 32 +++++++ .../has-expired/hasExpired.tree | 0 46 files changed, 416 insertions(+), 524 deletions(-) create mode 100644 test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol rename test/periphery/integration/merkle-campaign/instant/{constructor => }/constructor.t.sol (96%) delete mode 100644 test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol create mode 100644 test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree rename test/periphery/integration/merkle-campaign/ll/{constructor => }/constructor.t.sol (97%) delete mode 100644 test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree create mode 100644 test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree rename test/periphery/integration/merkle-campaign/lt/{constructor => }/constructor.t.sol (98%) delete mode 100644 test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree create mode 100644 test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol rename test/periphery/integration/merkle-campaign/{lt => shared}/clawback/clawback.t.sol (69%) rename test/periphery/integration/merkle-campaign/{instant => shared}/clawback/clawback.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol rename test/periphery/integration/merkle-campaign/{instant => shared}/get-first-claim-time/getFirstClaimTime.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol rename test/periphery/integration/merkle-campaign/{instant => shared}/has-claimed/hasClaimed.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol rename test/periphery/integration/merkle-campaign/{instant => shared}/has-expired/hasExpired.tree (100%) diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index e6049aa55..b2845469a 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -10,6 +10,10 @@ import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { Base_Test } from "../Base.t.sol"; contract Periphery_Test is Base_Test { + function setUp() public virtual override { + Base_Test.setUp(); + } + /*////////////////////////////////////////////////////////////////////////// MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index 9a821184d..437a3d6d9 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -35,7 +35,7 @@ abstract contract Fork_Test is Periphery_Test, Merkle { vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); // Set up the parent test contract. - super.setUp(); + Periphery_Test.setUp(); // Load the external dependencies. loadDependencies(); diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol index 6013113ab..19472c0ce 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol index 6029463c0..40748e402 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol index 0deafcad4..5939ad99d 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol index eca730f65..9af9272e5 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol index 1bcc4b8f6..3c56008a6 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol index 9844b7cc4..2de773919 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 633a06b5a..52f66f022 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -8,8 +8,12 @@ import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol" import { Periphery_Test } from "../../Periphery.t.sol"; abstract contract MerkleCampaign_Integration_Test is Periphery_Test { + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); // Make Alice the caller. resetPrank(users.alice); diff --git a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol new file mode 100644 index 000000000..51e1fcd73 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +abstract contract MerkleInstant_Integration_Shared_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Cast the {merkleInstant} contract as {ISablierMerkleBase} + merkleBase = ISablierMerkleBase(merkleInstant); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Clawback_MerkleLInstant_Integration_Test is + Clawback_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function setUp() public override(Clawback_Integration_Test, MerkleInstant_Integration_Shared_Test) { + Clawback_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} + +contract GetFirstClaimTime_MerkleLInstant_Integration_Test is + GetFirstClaimTime_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleInstant_Integration_Shared_Test) { + GetFirstClaimTime_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} + +contract HasClaimed_MerkleLInstant_Integration_Test is + HasClaimed_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier givenRecipientHasClaimed() override { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function setUp() public override(HasClaimed_Integration_Test, MerkleInstant_Integration_Shared_Test) { + HasClaimed_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} + +contract HasExpired_MerkleLInstant_Integration_Test is + HasExpired_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier createMerkleCampaignWithZeroExpiry() override { + campaignWithZeroExpiry = ISablierMerkleBase(createMerkleInstant({ expiration: 0 })); + _; + } + + function setUp() public override(HasExpired_Integration_Test, MerkleInstant_Integration_Shared_Test) { + HasExpired_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol index 14b356092..d4d1202d9 100644 --- a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol @@ -5,7 +5,7 @@ import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is MerkleCampaign_Integration_Test { +contract Claim_MerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); uint256 warpTime = expiration + 1 seconds; diff --git a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol deleted file mode 100644 index b448c7148..000000000 --- a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { - function test_RevertWhen_CallerNotAdmin() external { - resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleInstant.clawback({ to: users.eve, amount: 1 }); - } - - modifier whenCallerAdmin() { - resetPrank({ msgSender: users.admin }); - _; - } - - function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { - test_Clawback(users.admin); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - - function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { - vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); - test_Clawback(users.admin); - } - - modifier postGracePeriod() { - vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); - _; - } - - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierMerkleBase_ClawbackNotAllowed.selector, - getBlockTimestamp(), - defaults.EXPIRATION(), - defaults.FIRST_CLAIM_TIME() - ) - ); - merkleInstant.clawback({ to: users.admin, amount: 1 }); - } - - modifier givenCampaignExpired() { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - _; - } - - function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { - test_Clawback(users.admin); - } - - function testFuzz_Clawback(address to) - external - whenCallerAdmin - afterFirstClaim - postGracePeriod - givenCampaignExpired - { - vm.assume(to != address(0)); - test_Clawback(to); - } - - function test_Clawback(address to) internal { - uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleInstant))); - expectCallToTransfer({ to: to, value: clawbackAmount }); - vm.expectEmit({ emitter: address(merkleInstant) }); - emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); - merkleInstant.clawback({ to: to, amount: clawbackAmount }); - } -} diff --git a/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol similarity index 96% rename from test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/instant/constructor.t.sol index 83cbc61ac..535dba4c0 100644 --- a/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierMerkleInstant } from "src/periphery/SablierMerkleInstant.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error diff --git a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol deleted file mode 100644 index e595feeda..000000000 --- a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { - function test_GetFirstClaimTime_BeforeFirstClaim() external view { - uint256 firstClaimTime = merkleInstant.getFirstClaimTime(); - assertEq(firstClaimTime, 0); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - - function test_GetFirstClaimTime() external afterFirstClaim { - uint256 firstClaimTime = merkleInstant.getFirstClaimTime(); - assertEq(firstClaimTime, getBlockTimestamp()); - } -} diff --git a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol deleted file mode 100644 index a6174e239..000000000 --- a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasClaimed_IndexNotInTree() external { - uint256 indexNotInTree = 1337e18; - assertFalse(merkleInstant.hasClaimed(indexNotInTree), "claimed"); - } - - modifier whenIndexInTree() { - _; - } - - function test_HasClaimed_NotClaimed() external whenIndexInTree { - assertFalse(merkleInstant.hasClaimed(defaults.INDEX1()), "claimed"); - } - - modifier givenRecipientHasClaimed() { - claimInstant(); - _; - } - - function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { - assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); - } -} diff --git a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol deleted file mode 100644 index 1e36520f9..000000000 --- a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasExpired_ExpirationZero() external { - ISablierMerkleInstant testLockup = createMerkleInstant({ expiration: 0 }); - assertFalse(testLockup.hasExpired(), "campaign expired"); - } - - modifier givenExpirationNotZero() { - _; - } - - function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { - assertFalse(merkleInstant.hasExpired(), "campaign expired"); - } - - function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() }); - assertTrue(merkleInstant.hasExpired(), "campaign not expired"); - } - - function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - assertTrue(merkleInstant.hasExpired(), "campaign not expired"); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol new file mode 100644 index 000000000..7a06ee63c --- /dev/null +++ b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +abstract contract MerkleLL_Integration_Shared_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Cast the {MerkleLL} contract as {ISablierMerkleBase} + merkleBase = ISablierMerkleBase(merkleLL); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Clawback_MerkleLL_Integration_Test is Clawback_Integration_Test, MerkleLL_Integration_Shared_Test { + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function setUp() public override(Clawback_Integration_Test, MerkleLL_Integration_Shared_Test) { + Clawback_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} + +contract GetFirstClaimTime_MerkleLL_Integration_Test is + GetFirstClaimTime_Integration_Test, + MerkleLL_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleLL_Integration_Shared_Test) { + GetFirstClaimTime_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} + +contract HasClaimed_MerkleLL_Integration_Test is HasClaimed_Integration_Test, MerkleLL_Integration_Shared_Test { + modifier givenRecipientHasClaimed() override { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function setUp() public override(HasClaimed_Integration_Test, MerkleLL_Integration_Shared_Test) { + HasClaimed_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} + +contract HasExpired_MerkleLL_Integration_Test is HasExpired_Integration_Test, MerkleLL_Integration_Shared_Test { + modifier createMerkleCampaignWithZeroExpiry() override { + campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLL({ expiration: 0 })); + _; + } + + function setUp() public override(HasExpired_Integration_Test, MerkleLL_Integration_Shared_Test) { + HasExpired_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index dd5af7b2d..26d7d5b13 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -6,7 +6,7 @@ import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is MerkleCampaign_Integration_Test { +contract Claim_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); uint256 warpTime = expiration + 1 seconds; diff --git a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol deleted file mode 100644 index 4bca20011..000000000 --- a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { - function test_RevertWhen_CallerNotAdmin() external { - resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleLL.clawback({ to: users.eve, amount: 1 }); - } - - modifier whenCallerAdmin() { - resetPrank({ msgSender: users.admin }); - _; - } - - function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { - test_Clawback(users.admin); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - - function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { - vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); - test_Clawback(users.admin); - } - - modifier postGracePeriod() { - vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); - _; - } - - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierMerkleBase_ClawbackNotAllowed.selector, - getBlockTimestamp(), - defaults.EXPIRATION(), - defaults.FIRST_CLAIM_TIME() - ) - ); - merkleLL.clawback({ to: users.admin, amount: 1 }); - } - - modifier givenCampaignExpired() { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - _; - } - - function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { - test_Clawback(users.admin); - } - - function testFuzz_Clawback(address to) - external - whenCallerAdmin - afterFirstClaim - postGracePeriod - givenCampaignExpired - { - vm.assume(to != address(0)); - test_Clawback(to); - } - - function test_Clawback(address to) internal { - uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLL))); - expectCallToTransfer({ to: to, value: clawbackAmount }); - vm.expectEmit({ emitter: address(merkleLL) }); - emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); - merkleLL.clawback({ to: to, amount: clawbackAmount }); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree deleted file mode 100644 index b961e8883..000000000 --- a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree +++ /dev/null @@ -1,17 +0,0 @@ -clawback.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the first claim has not been made - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── when the first claim has been made - ├── given the current time is not more than 7 days after the first claim - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── given the current time is more than 7 days after the first claim - ├── given the campaign has not expired - │ └── it should revert - └── given the campaign has expired - ├── it should perform the ERC-20 transfer - └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol similarity index 97% rename from test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/ll/constructor.t.sol index f6398616d..ef83d82f8 100644 --- a/test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "src/core/types/DataTypes.sol"; import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error diff --git a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol deleted file mode 100644 index b62284e2d..000000000 --- a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { - function test_GetFirstClaimTime_BeforeFirstClaim() external view { - uint256 firstClaimTime = merkleLL.getFirstClaimTime(); - assertEq(firstClaimTime, 0); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - - function test_GetFirstClaimTime() external afterFirstClaim { - uint256 firstClaimTime = merkleLL.getFirstClaimTime(); - assertEq(firstClaimTime, getBlockTimestamp()); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree deleted file mode 100644 index cab778426..000000000 --- a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree +++ /dev/null @@ -1,5 +0,0 @@ -getFirstClaimTime.t.sol -├── when the first claim has not been made -│ └── it should return 0 -└── when the first claim has been made - └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol deleted file mode 100644 index 31d2edca2..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasClaimed_IndexNotInTree() external { - uint256 indexNotInTree = 1337e18; - assertFalse(merkleLL.hasClaimed(indexNotInTree), "claimed"); - } - - modifier whenIndexInTree() { - _; - } - - function test_HasClaimed_NotClaimed() external whenIndexInTree { - assertFalse(merkleLL.hasClaimed(defaults.INDEX1()), "claimed"); - } - - modifier givenRecipientHasClaimed() { - claimLL(); - _; - } - - function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { - assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree deleted file mode 100644 index dcbcafe7a..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree +++ /dev/null @@ -1,8 +0,0 @@ -hasClaimed.t.sol -├── when the index is not in the Merkle tree -│ └── it should return false -└── when the index is in the Merkle tree - ├── given the recipient has not claimed - │ └── it should return false - └── given the recipient has claimed - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol deleted file mode 100644 index c336351dd..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasExpired_ExpirationZero() external { - ISablierMerkleLL testLockup = createMerkleLL({ expiration: 0 }); - assertFalse(testLockup.hasExpired(), "campaign expired"); - } - - modifier givenExpirationNotZero() { - _; - } - - function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { - assertFalse(merkleLL.hasExpired(), "campaign expired"); - } - - function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() }); - assertTrue(merkleLL.hasExpired(), "campaign not expired"); - } - - function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - assertTrue(merkleLL.hasExpired(), "campaign not expired"); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree deleted file mode 100644 index 5fd22925e..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree +++ /dev/null @@ -1,10 +0,0 @@ -hasExpired.t.sol -├── when the expiration is zero -│ └── it should return false -└── when the expiration is not zero - ├── when the expiration is less than the block timestamp - │ └── it should return false - ├── when the expiration is equal to the block timestamp - │ └── it should return true - └── when the expiration is greater than the block timestamp - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol new file mode 100644 index 000000000..92181fe9b --- /dev/null +++ b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +abstract contract MerkleLT_Integration_Shared_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Cast the {MerkleLT} contract as {ISablierMerkleBase} + merkleBase = ISablierMerkleBase(merkleLT); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Clawback_MerkleLT_Integration_Test is Clawback_Integration_Test, MerkleLT_Integration_Shared_Test { + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function setUp() public override(Clawback_Integration_Test, MerkleLT_Integration_Shared_Test) { + Clawback_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} + +contract GetFirstClaimTime_MerkleLT_Integration_Test is + GetFirstClaimTime_Integration_Test, + MerkleLT_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleLT_Integration_Shared_Test) { + GetFirstClaimTime_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} + +contract HasClaimed_MerkleLT_Integration_Test is HasClaimed_Integration_Test, MerkleLT_Integration_Shared_Test { + modifier givenRecipientHasClaimed() override { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function setUp() public override(HasClaimed_Integration_Test, MerkleLT_Integration_Shared_Test) { + HasClaimed_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} + +contract HasExpired_MerkleLT_Integration_Test is HasExpired_Integration_Test, MerkleLT_Integration_Shared_Test { + modifier createMerkleCampaignWithZeroExpiry() override { + campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLT({ expiration: 0 })); + _; + } + + function setUp() public override(HasExpired_Integration_Test, MerkleLT_Integration_Shared_Test) { + HasExpired_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index bdf326a35..05285864a 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -14,7 +14,7 @@ import { Merkle } from "test/utils/Murky.sol"; import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is Merkle, MerkleCampaign_Integration_Test { +contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_Test { using MerkleBuilder for uint256[]; modifier whenTotalPercentageNotOneHundred() { diff --git a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree deleted file mode 100644 index b961e8883..000000000 --- a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree +++ /dev/null @@ -1,17 +0,0 @@ -clawback.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the first claim has not been made - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── when the first claim has been made - ├── given the current time is not more than 7 days after the first claim - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── given the current time is more than 7 days after the first claim - ├── given the campaign has not expired - │ └── it should revert - └── given the campaign has expired - ├── it should perform the ERC-20 transfer - └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol similarity index 98% rename from test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/lt/constructor.t.sol index f53c915b5..01c5a0ee5 100644 --- a/test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error diff --git a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol deleted file mode 100644 index 440ae386e..000000000 --- a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { - function test_GetFirstClaimTime_BeforeFirstClaim() external view { - uint256 firstClaimTime = merkleLT.getFirstClaimTime(); - assertEq(firstClaimTime, 0); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimLT(); - _; - } - - function test_GetFirstClaimTime() external afterFirstClaim { - uint256 firstClaimTime = merkleLT.getFirstClaimTime(); - assertEq(firstClaimTime, getBlockTimestamp()); - } -} diff --git a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree deleted file mode 100644 index cab778426..000000000 --- a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree +++ /dev/null @@ -1,5 +0,0 @@ -getFirstClaimTime.t.sol -├── when the first claim has not been made -│ └── it should return 0 -└── when the first claim has been made - └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol deleted file mode 100644 index fae6f42cf..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasClaimed_IndexNotInTree() external { - uint256 indexNotInTree = 1337e18; - assertFalse(merkleLT.hasClaimed(indexNotInTree), "claimed"); - } - - modifier whenIndexInTree() { - _; - } - - function test_HasClaimed_NotClaimed() external whenIndexInTree { - assertFalse(merkleLT.hasClaimed(defaults.INDEX1()), "claimed"); - } - - modifier givenRecipientHasClaimed() { - claimLT(); - _; - } - - function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { - assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); - } -} diff --git a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree deleted file mode 100644 index dcbcafe7a..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree +++ /dev/null @@ -1,8 +0,0 @@ -hasClaimed.t.sol -├── when the index is not in the Merkle tree -│ └── it should return false -└── when the index is in the Merkle tree - ├── given the recipient has not claimed - │ └── it should return false - └── given the recipient has claimed - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol deleted file mode 100644 index 51896c39f..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasExpired_ExpirationZero() external { - ISablierMerkleLT testLockup = createMerkleLT({ expiration: 0 }); - assertFalse(testLockup.hasExpired(), "campaign expired"); - } - - modifier givenExpirationNotZero() { - _; - } - - function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { - assertFalse(merkleLT.hasExpired(), "campaign expired"); - } - - function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() }); - assertTrue(merkleLT.hasExpired(), "campaign not expired"); - } - - function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - assertTrue(merkleLT.hasExpired(), "campaign not expired"); - } -} diff --git a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree deleted file mode 100644 index 2a359a81e..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree +++ /dev/null @@ -1,10 +0,0 @@ -hasExpired.t.sol -├── given the expiration is zero -│ └── it should return false -└── given the expiration is not zero - ├── given the expiration is less than the block timestamp - │ └── it should return false - ├── given the expiration is equal to the block timestamp - │ └── it should return true - └── given the expiration is greater than the block timestamp - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol new file mode 100644 index 000000000..24684a6e8 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; + +abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integration_Test { + /// @dev A test contract meant to be overridden by the implementing contract, which will be either + /// {SablierMerkleLL}, {SablierMerkleLT} or {SablierMerkleInstant}. + ISablierMerkleBase internal merkleBase; + + function setUp() public virtual override { + MerkleCampaign_Integration_Test.setUp(); + } + + /*////////////////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev A shared modifier meant to be overridden by the implementing test contracts. + modifier afterFirstClaim() virtual { + _; + } + + modifier createMerkleCampaignWithZeroExpiry() virtual { + _; + } + + modifier givenCampaignExpired() { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + _; + } + + modifier givenExpirationNotZero() { + _; + } + + modifier givenRecipientHasClaimed() virtual { + _; + } + + modifier postGracePeriod() { + vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); + _; + } + + modifier whenCallerAdmin() { + resetPrank({ msgSender: users.admin }); + _; + } + + modifier whenIndexInTree() { + _; + } +} diff --git a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol similarity index 69% rename from test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol rename to test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol index 0e9a7eae6..64d4ba322 100644 --- a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol @@ -4,39 +4,28 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract Clawback_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } -contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_CallerNotAdmin() external { resetPrank({ msgSender: users.eve }); vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleLT.clawback({ to: users.eve, amount: 1 }); - } - - modifier whenCallerAdmin() { - resetPrank({ msgSender: users.admin }); - _; + merkleBase.clawback({ to: users.eve, amount: 1 }); } function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { test_Clawback(users.admin); } - modifier afterFirstClaim() { - claimLT(); - _; - } - function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); test_Clawback(users.admin); } - modifier postGracePeriod() { - vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); - _; - } - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { vm.expectRevert( abi.encodeWithSelector( @@ -46,12 +35,7 @@ contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { defaults.FIRST_CLAIM_TIME() ) ); - merkleLT.clawback({ to: users.admin, amount: 1 }); - } - - modifier givenCampaignExpired() { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - _; + merkleBase.clawback({ to: users.admin, amount: 1 }); } function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { @@ -70,10 +54,10 @@ contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { } function test_Clawback(address to) internal { - uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLT))); + uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleBase))); expectCallToTransfer({ to: to, value: clawbackAmount }); - vm.expectEmit({ emitter: address(merkleLT) }); + vm.expectEmit({ emitter: address(merkleBase) }); emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); - merkleLT.clawback({ to: to, amount: clawbackAmount }); + merkleBase.clawback({ to: to, amount: clawbackAmount }); } } diff --git a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/clawback/clawback.tree rename to test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree diff --git a/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol new file mode 100644 index 000000000..332eeaced --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + function test_GetFirstClaimTime_BeforeFirstClaim() external view { + uint256 firstClaimTime = merkleBase.getFirstClaimTime(); + assertEq(firstClaimTime, 0); + } + + function test_GetFirstClaimTime() external view afterFirstClaim { + uint256 firstClaimTime = merkleBase.getFirstClaimTime(); + assertEq(firstClaimTime, getBlockTimestamp()); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.tree rename to test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.tree diff --git a/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol new file mode 100644 index 000000000..3719ed9e9 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + function test_HasClaimed_IndexNotInTree() external { + uint256 indexNotInTree = 1337e18; + assertFalse(merkleBase.hasClaimed(indexNotInTree), "claimed"); + } + + function test_HasClaimed_NotClaimed() external whenIndexInTree { + assertFalse(merkleBase.hasClaimed(defaults.INDEX1()), "claimed"); + } + + function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { + assertTrue(merkleBase.hasClaimed(defaults.INDEX1()), "not claimed"); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.tree rename to test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.tree diff --git a/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol new file mode 100644 index 000000000..c7480442b --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract HasExpired_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + ISablierMerkleBase internal campaignWithZeroExpiry; + + function test_HasExpired_ExpirationZero() external view createMerkleCampaignWithZeroExpiry { + assertFalse(campaignWithZeroExpiry.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { + assertFalse(merkleBase.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() }); + assertTrue(merkleBase.hasExpired(), "campaign not expired"); + } + + function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + assertTrue(merkleBase.hasExpired(), "campaign not expired"); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.tree rename to test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.tree