From 6cb5e1ce23d433deac7df4fa5273cd3055fe7c87 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 15 Jan 2024 20:39:06 +0530 Subject: [PATCH 1/9] feat: add `name` string parameter in MerkleStreamer contract constructor refactor: use struct `CreateWithLockupLinear` in Merkle streamer constructor --- script/CreateMerkleStreamerLL.s.sol | 25 ++-------- src/SablierV2MerkleStreamerFactory.sol | 50 ++++++++----------- src/SablierV2MerkleStreamerLL.sol | 26 +++++----- src/abstracts/SablierV2MerkleStreamer.sol | 18 +++++++ src/interfaces/ISablierV2MerkleStreamer.sol | 3 ++ .../ISablierV2MerkleStreamerFactory.sol | 21 ++------ src/libraries/Errors.sol | 3 ++ src/types/DataTypes.sol | 28 +++++++++++ test/Base.t.sol | 35 +++++++++---- .../merkle-streamer/MerkleStreamerLL.t.sol | 11 +++- .../merkle-streamer/MerkleStreamer.t.sol | 16 +++--- .../createMerkleStreamerLL.t.sol | 15 +----- .../ll/constructor/constructor.t.sol | 17 +++---- test/utils/Defaults.sol | 2 + test/utils/Events.sol | 1 + 15 files changed, 148 insertions(+), 123 deletions(-) diff --git a/script/CreateMerkleStreamerLL.s.sol b/script/CreateMerkleStreamerLL.s.sol index fb8612c0..9109d05a 100644 --- a/script/CreateMerkleStreamerLL.s.sol +++ b/script/CreateMerkleStreamerLL.s.sol @@ -1,24 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; -import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { BaseScript } from "./Base.s.sol"; import { ISablierV2MerkleStreamerFactory } from "../src/interfaces/ISablierV2MerkleStreamerFactory.sol"; import { ISablierV2MerkleStreamerLL } from "../src/interfaces/ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "../src/types/DataTypes.sol"; contract CreateMerkleStreamerLL is BaseScript { struct Params { - address initialAdmin; - ISablierV2LockupLinear lockupLinear; - IERC20 asset; - bytes32 merkleRoot; - uint40 expiration; - LockupLinear.Durations streamDurations; - bool cancelable; - bool transferable; + MerkleStreamer.CreateWithLockupLinear createLLParams; string ipfsCID; uint256 campaignTotalAmount; uint256 recipientsCount; @@ -33,17 +24,7 @@ contract CreateMerkleStreamerLL is BaseScript { returns (ISablierV2MerkleStreamerLL merkleStreamerLL) { merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL( - params.initialAdmin, - params.lockupLinear, - params.asset, - params.merkleRoot, - params.expiration, - params.streamDurations, - params.cancelable, - params.transferable, - params.ipfsCID, - params.campaignTotalAmount, - params.recipientsCount + params.createLLParams, params.ipfsCID, params.campaignTotalAmount, params.recipientsCount ); } } diff --git a/src/SablierV2MerkleStreamerFactory.sol b/src/SablierV2MerkleStreamerFactory.sol index 9efdd7a5..d5f3c700 100644 --- a/src/SablierV2MerkleStreamerFactory.sol +++ b/src/SablierV2MerkleStreamerFactory.sol @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { ISablierV2MerkleStreamerFactory } from "./interfaces/ISablierV2MerkleStreamerFactory.sol"; import { ISablierV2MerkleStreamerLL } from "./interfaces/ISablierV2MerkleStreamerLL.sol"; import { SablierV2MerkleStreamerLL } from "./SablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "./types/DataTypes.sol"; /// @title SablierV2MerkleStreamerFactory /// @notice See the documentation in {ISablierV2MerkleStreamerFactory}. @@ -18,14 +17,7 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { /// @notice inheritdoc ISablierV2MerkleStreamerFactory function createMerkleStreamerLL( - address initialAdmin, - ISablierV2LockupLinear lockupLinear, - IERC20 asset, - bytes32 merkleRoot, - uint40 expiration, - LockupLinear.Durations memory streamDurations, - bool cancelable, - bool transferable, + MerkleStreamer.CreateWithLockupLinear memory createLLParams, string memory ipfsCID, uint256 aggregateAmount, uint256 recipientsCount @@ -36,33 +28,33 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { // Hash the parameters to generate a salt. bytes32 salt = keccak256( abi.encodePacked( - initialAdmin, - lockupLinear, - asset, - merkleRoot, - expiration, - abi.encode(streamDurations), - cancelable, - transferable + createLLParams.initialAdmin, + createLLParams.lockupLinear, + createLLParams.asset, + bytes32(abi.encodePacked(createLLParams.name)), + createLLParams.merkleRoot, + createLLParams.expiration, + abi.encode(createLLParams.streamDurations), + createLLParams.cancelable, + createLLParams.transferable ) ); // Deploy the Merkle streamer with CREATE2. - merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }( - initialAdmin, lockupLinear, asset, merkleRoot, expiration, streamDurations, cancelable, transferable - ); + merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }(createLLParams); // Log the creation of the Merkle streamer, including some metadata that is not stored on-chain. emit CreateMerkleStreamerLL( merkleStreamerLL, - initialAdmin, - lockupLinear, - asset, - merkleRoot, - expiration, - streamDurations, - cancelable, - transferable, + createLLParams.initialAdmin, + createLLParams.lockupLinear, + createLLParams.asset, + createLLParams.name, + createLLParams.merkleRoot, + createLLParams.expiration, + createLLParams.streamDurations, + createLLParams.cancelable, + createLLParams.transferable, ipfsCID, aggregateAmount, recipientsCount diff --git a/src/SablierV2MerkleStreamerLL.sol b/src/SablierV2MerkleStreamerLL.sol index a3a451c0..26c198e0 100644 --- a/src/SablierV2MerkleStreamerLL.sol +++ b/src/SablierV2MerkleStreamerLL.sol @@ -10,6 +10,7 @@ import { ud } from "@prb/math/src/UD60x18.sol"; import { SablierV2MerkleStreamer } from "./abstracts/SablierV2MerkleStreamer.sol"; import { ISablierV2MerkleStreamerLL } from "./interfaces/ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "./types/DataTypes.sol"; /// @title SablierV2MerkleStreamerLL /// @notice See the documentation in {ISablierV2MerkleStreamerLL}. @@ -40,20 +41,19 @@ contract SablierV2MerkleStreamerLL is /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier /// contract. - constructor( - address initialAdmin, - ISablierV2LockupLinear lockupLinear, - IERC20 asset, - bytes32 merkleRoot, - uint40 expiration, - LockupLinear.Durations memory streamDurations_, - bool cancelable, - bool transferable - ) - SablierV2MerkleStreamer(initialAdmin, asset, merkleRoot, expiration, cancelable, transferable) + constructor(MerkleStreamer.CreateWithLockupLinear memory createParams) + SablierV2MerkleStreamer( + createParams.initialAdmin, + createParams.asset, + createParams.name, + createParams.merkleRoot, + createParams.expiration, + createParams.cancelable, + createParams.transferable + ) { - LOCKUP_LINEAR = lockupLinear; - streamDurations = streamDurations_; + LOCKUP_LINEAR = createParams.lockupLinear; + streamDurations = createParams.streamDurations; // Max approve the Sablier contract to spend funds from the Merkle streamer. ASSET.forceApprove(address(LOCKUP_LINEAR), type(uint256).max); diff --git a/src/abstracts/SablierV2MerkleStreamer.sol b/src/abstracts/SablierV2MerkleStreamer.sol index 75b50101..d671b729 100644 --- a/src/abstracts/SablierV2MerkleStreamer.sol +++ b/src/abstracts/SablierV2MerkleStreamer.sol @@ -38,6 +38,13 @@ abstract contract SablierV2MerkleStreamer is /// @inheritdoc ISablierV2MerkleStreamer bool public immutable override TRANSFERABLE; + /*////////////////////////////////////////////////////////////////////////// + PRIVATE CONSTANT + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev The name of the campaign stored as bytes32. + bytes32 private immutable _NAME; + /*////////////////////////////////////////////////////////////////////////// INTERNAL STORAGE //////////////////////////////////////////////////////////////////////////*/ @@ -53,13 +60,19 @@ abstract contract SablierV2MerkleStreamer is constructor( address initialAdmin, IERC20 asset, + string memory name, bytes32 merkleRoot, uint40 expiration, bool cancelable, bool transferable ) { + if (bytes(name).length > 32) { + revert Errors.SablierV2MerkleStreamer_NameTooLong(); + } + admin = initialAdmin; ASSET = asset; + _NAME = bytes32(abi.encodePacked(name)); MERKLE_ROOT = merkleRoot; EXPIRATION = expiration; CANCELABLE = cancelable; @@ -80,6 +93,11 @@ abstract contract SablierV2MerkleStreamer is return EXPIRATION > 0 && EXPIRATION <= block.timestamp; } + /// @inheritdoc ISablierV2MerkleStreamer + function NAME() external view override returns (string memory) { + return string(abi.encodePacked(_NAME)); + } + /*////////////////////////////////////////////////////////////////////////// USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/interfaces/ISablierV2MerkleStreamer.sol b/src/interfaces/ISablierV2MerkleStreamer.sol index 94c5d7de..2c5376a5 100644 --- a/src/interfaces/ISablierV2MerkleStreamer.sol +++ b/src/interfaces/ISablierV2MerkleStreamer.sol @@ -29,6 +29,9 @@ interface ISablierV2MerkleStreamer is IAdminable { /// @dev This is an immutable state variable. function ASSET() external returns (IERC20); + /// @notice The name of the Merkle streamer contract. + function NAME() external returns (string memory); + /// @notice A flag indicating whether the streams can be canceled. /// @dev This is an immutable state variable. function CANCELABLE() external returns (bool); diff --git a/src/interfaces/ISablierV2MerkleStreamerFactory.sol b/src/interfaces/ISablierV2MerkleStreamerFactory.sol index 504db123..9faf6d78 100644 --- a/src/interfaces/ISablierV2MerkleStreamerFactory.sol +++ b/src/interfaces/ISablierV2MerkleStreamerFactory.sol @@ -6,6 +6,7 @@ import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablier import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { ISablierV2MerkleStreamerLL } from "./ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "../types/DataTypes.sol"; /// @title ISablierV2MerkleStreamerFactory /// @notice Deploys new Lockup Linear Merkle streamers via CREATE2. @@ -20,6 +21,7 @@ interface ISablierV2MerkleStreamerFactory { address indexed admin, ISablierV2LockupLinear indexed lockupLinear, IERC20 indexed asset, + string name, bytes32 merkleRoot, uint40 expiration, LockupLinear.Durations streamDurations, @@ -36,27 +38,14 @@ interface ISablierV2MerkleStreamerFactory { /// @notice Creates a new Merkle streamer that uses Lockup Linear. /// @dev Emits a {CreateMerkleStreamerLL} event. - /// @param initialAdmin The initial admin of the Merkle streamer contract. - /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. - /// @param asset The address of the streamed ERC-20 asset. - /// @param merkleRoot The Merkle root of the claim data. - /// @param expiration The expiration of the streaming campaign, as a Unix timestamp. - /// @param streamDurations The durations for each stream due to the recipient. - /// @param cancelable Indicates if each stream will be cancelable. - /// @param transferable Indicates if each stream NFT will be transferable. + /// @param createLLParams Struct encapsulating the {SablierV2MerkleStreamerLL} parameters, which are documented in + /// {DataTypes}. /// @param ipfsCID Metadata parameter emitted for indexing purposes. /// @param aggregateAmount Total amount of ERC-20 assets to be streamed to all recipients. /// @param recipientsCount Total number of recipients eligible to claim. /// @return merkleStreamerLL The address of the newly created Merkle streamer contract. function createMerkleStreamerLL( - address initialAdmin, - ISablierV2LockupLinear lockupLinear, - IERC20 asset, - bytes32 merkleRoot, - uint40 expiration, - LockupLinear.Durations memory streamDurations, - bool cancelable, - bool transferable, + MerkleStreamer.CreateWithLockupLinear memory createLLParams, string memory ipfsCID, uint256 aggregateAmount, uint256 recipientsCount diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index 382e716a..c250455e 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -25,4 +25,7 @@ library Errors { /// @notice Thrown when trying to claim the same stream more than once. error SablierV2MerkleStreamer_StreamClaimed(uint256 index); + + /// @notice Thrown when name of the Merkle Streamer contract is longer than 32 bytes. + error SablierV2MerkleStreamer_NameTooLong(); } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index ca2d63ec..98612fd0 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2Lockup } from "@sablier/v2-core/src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { Broker, LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; library Batch { @@ -60,3 +62,29 @@ library Batch { Broker broker; } } + +library MerkleStreamer { + /// @notice Struct encapsulating the {SablierV2MerkleStreamerLL} parameters for the + /// {SablierV2MerkleStreamerFactory.createMerkleStreamerLL} + /// function. + /// @param initialAdmin The initial admin of the Merkle streamer contract. + /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param asset The address of the streamed ERC-20 asset. + /// @param name The name of the Merkle streamer contract. + /// @param merkleRoot The Merkle root of the claim data. + /// @param expiration The expiration of the streaming campaign, as a Unix timestamp. + /// @param streamDurations The durations for each stream due to the recipient. + /// @param cancelable Indicates if each stream will be cancelable. + /// @param transferable Indicates if each stream NFT will be transferable. + struct CreateWithLockupLinear { + address initialAdmin; + ISablierV2LockupLinear lockupLinear; + IERC20 asset; + string name; + bytes32 merkleRoot; + uint40 expiration; + LockupLinear.Durations streamDurations; + bool cancelable; + bool transferable; + } +} diff --git a/test/Base.t.sol b/test/Base.t.sol index 164b60c5..8f0fd0fe 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -19,6 +19,7 @@ import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStrea import { SablierV2Batch } from "src/SablierV2Batch.sol"; import { SablierV2MerkleStreamerFactory } from "src/SablierV2MerkleStreamerFactory.sol"; import { SablierV2MerkleStreamerLL } from "src/SablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "src/types/DataTypes.sol"; import { Defaults } from "./utils/Defaults.sol"; import { DeployOptimized } from "./utils/DeployOptimized.sol"; @@ -250,6 +251,28 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions MERKLE-STREAMER //////////////////////////////////////////////////////////////////////////*/ + function createWithLockupLinear( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (MerkleStreamer.CreateWithLockupLinear memory) + { + return MerkleStreamer.CreateWithLockupLinear({ + initialAdmin: admin, + lockupLinear: lockupLinear, + asset: asset, + name: defaults.NAME_STRING(), + merkleRoot: merkleRoot, + expiration: expiration, + streamDurations: defaults.durations(), + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE() + }); + } + function computeMerkleStreamerLLAddress( address admin, bytes32 merkleRoot, @@ -263,6 +286,7 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions admin, lockupLinear, asset, + defaults.NAME(), merkleRoot, expiration, abi.encode(defaults.durations()), @@ -286,16 +310,7 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions internal returns (bytes memory) { - bytes memory constructorArgs = abi.encode( - admin, - lockupLinear, - asset, - merkleRoot, - expiration, - defaults.durations(), - defaults.CANCELABLE(), - defaults.TRANSFERABLE() - ); + bytes memory constructorArgs = abi.encode(createWithLockupLinear(admin, merkleRoot, expiration)); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierV2MerkleStreamerLL).creationCode, constructorArgs); } else { diff --git a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol index 0b8038aa..842b15b6 100644 --- a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol +++ b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol @@ -6,6 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "src/types/DataTypes.sol"; import { MerkleBuilder } from "../../utils/MerkleBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; @@ -96,6 +97,7 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { admin: params.admin, lockupLinear: lockupLinear, asset: asset, + name: defaults.NAME_STRING(), merkleRoot: vars.merkleRoot, expiration: params.expiration, streamDurations: defaults.durations(), @@ -106,15 +108,20 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { recipientsCount: vars.recipientsCount }); - vars.merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL({ + MerkleStreamer.CreateWithLockupLinear memory createLLParams = MerkleStreamer.CreateWithLockupLinear({ initialAdmin: params.admin, lockupLinear: lockupLinear, asset: asset, + name: defaults.NAME_STRING(), merkleRoot: vars.merkleRoot, expiration: params.expiration, streamDurations: defaults.durations(), cancelable: defaults.CANCELABLE(), - transferable: defaults.TRANSFERABLE(), + transferable: defaults.TRANSFERABLE() + }); + + vars.merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL({ + createLLParams: createLLParams, ipfsCID: defaults.IPFS_CID(), aggregateAmount: vars.aggregateAmount, recipientsCount: vars.recipientsCount diff --git a/test/integration/merkle-streamer/MerkleStreamer.t.sol b/test/integration/merkle-streamer/MerkleStreamer.t.sol index 3f244cef..b1a86504 100644 --- a/test/integration/merkle-streamer/MerkleStreamer.t.sol +++ b/test/integration/merkle-streamer/MerkleStreamer.t.sol @@ -3,12 +3,19 @@ pragma solidity >=0.8.22; import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "src/types/DataTypes.sol"; + import { Integration_Test } from "../Integration.t.sol"; abstract contract MerkleStreamer_Integration_Test is Integration_Test { + MerkleStreamer.CreateWithLockupLinear internal defaultCreateLLParams; + function setUp() public virtual override { Integration_Test.setUp(); + // Create the default Merkle streamer constructor parameters. + defaultCreateLLParams = createWithLockupLinear(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + // Create the default Merkle streamer. merkleStreamerLL = createMerkleStreamerLL(); @@ -55,14 +62,7 @@ abstract contract MerkleStreamer_Integration_Test is Integration_Test { function createMerkleStreamerLL(address admin, uint40 expiration) internal returns (ISablierV2MerkleStreamerLL) { return merkleStreamerFactory.createMerkleStreamerLL({ - initialAdmin: admin, - lockupLinear: lockupLinear, - asset: asset, - merkleRoot: defaults.MERKLE_ROOT(), - expiration: expiration, - cancelable: defaults.CANCELABLE(), - transferable: defaults.TRANSFERABLE(), - streamDurations: defaults.durations(), + createLLParams: createWithLockupLinear(admin, defaults.MERKLE_ROOT(), expiration), ipfsCID: defaults.IPFS_CID(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientsCount: defaults.RECIPIENTS_COUNT() diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index 0c17b93a..60818d3f 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -14,25 +14,13 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T /// @dev This test works because a default Merkle streamer is deployed in {Integration_Test.setUp} function test_RevertGiven_AlreadyDeployed() external { - bytes32 merkleRoot = defaults.MERKLE_ROOT(); - uint40 expiration = defaults.EXPIRATION(); - bool cancelable = defaults.CANCELABLE(); - bool transferable = defaults.TRANSFERABLE(); - LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientsCount = defaults.RECIPIENTS_COUNT(); vm.expectRevert(); merkleStreamerFactory.createMerkleStreamerLL({ - initialAdmin: users.admin, - lockupLinear: lockupLinear, - asset: asset, - merkleRoot: merkleRoot, - expiration: expiration, - cancelable: cancelable, - transferable: transferable, - streamDurations: streamDurations, + createLLParams: defaultCreateLLParams, ipfsCID: ipfsCID, aggregateAmount: aggregateAmount, recipientsCount: recipientsCount @@ -53,6 +41,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T admin: admin, lockupLinear: lockupLinear, asset: asset, + name: defaults.NAME_STRING(), merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration, streamDurations: defaults.durations(), diff --git a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol index 0837554e..088817bc 100644 --- a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol +++ b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol @@ -13,6 +13,7 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra address actualAdmin; uint256 actualAllowance; address actualAsset; + string actualName; bool actualCancelable; bool actualTransferable; LockupLinear.Durations actualDurations; @@ -22,6 +23,7 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra address expectedAdmin; uint256 expectedAllowance; address expectedAsset; + bytes32 expectedName; bool expectedCancelable; bool expectedTransferable; LockupLinear.Durations expectedDurations; @@ -31,16 +33,7 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra } function test_Constructor() external { - SablierV2MerkleStreamerLL constructedStreamerLL = new SablierV2MerkleStreamerLL( - users.admin, - lockupLinear, - asset, - defaults.MERKLE_ROOT(), - defaults.EXPIRATION(), - defaults.durations(), - defaults.CANCELABLE(), - defaults.TRANSFERABLE() - ); + SablierV2MerkleStreamerLL constructedStreamerLL = new SablierV2MerkleStreamerLL(defaultCreateLLParams); Vars memory vars; @@ -52,6 +45,10 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra vars.expectedAsset = address(asset); assertEq(vars.actualAsset, vars.expectedAsset, "asset"); + vars.actualName = constructedStreamerLL.NAME(); + vars.expectedName = defaults.NAME(); + assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); + vars.actualMerkleRoot = constructedStreamerLL.MERKLE_ROOT(); vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); assertEq(vars.actualMerkleRoot, vars.expectedMerkleRoot, "merkleRoot"); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 66297b86..88829cff 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -55,6 +55,8 @@ contract Defaults is Merkle { bool public constant TRANSFERABLE = false; uint256[] public LEAVES = new uint256[](RECIPIENTS_COUNT); bytes32 public immutable MERKLE_ROOT; + string public constant NAME_STRING = "Airdrop Campaign"; + bytes32 public constant NAME = 0x41697264726f702043616d706169676e00000000000000000000000000000000; /*////////////////////////////////////////////////////////////////////////// VARIABLES diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 5977a16c..20d9625f 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -16,6 +16,7 @@ abstract contract Events { address indexed admin, ISablierV2LockupLinear indexed lockupLinear, IERC20 indexed asset, + string name, bytes32 merkleRoot, uint40 expiration, LockupLinear.Durations streamDurations, From 23a0efa767ead192bc699f78d1d2398d706cb468 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 15 Jan 2024 21:44:31 +0530 Subject: [PATCH 2/9] test: name should not exceed 32 bytes --- .../merkle-streamer/MerkleStreamerLL.t.sol | 13 ++------ .../createMerkleStreamerLL.t.sol | 32 +++++++++++++++++-- .../createMerkleStreamerLL.tree | 13 +++++--- 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol index 842b15b6..eca4f79b 100644 --- a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol +++ b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol @@ -108,17 +108,8 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { recipientsCount: vars.recipientsCount }); - MerkleStreamer.CreateWithLockupLinear memory createLLParams = MerkleStreamer.CreateWithLockupLinear({ - initialAdmin: params.admin, - lockupLinear: lockupLinear, - asset: asset, - name: defaults.NAME_STRING(), - merkleRoot: vars.merkleRoot, - expiration: params.expiration, - streamDurations: defaults.durations(), - cancelable: defaults.CANCELABLE(), - transferable: defaults.TRANSFERABLE() - }); + MerkleStreamer.CreateWithLockupLinear memory createLLParams = + createWithLockupLinear({ admin: params.admin, merkleRoot: vars.merkleRoot, expiration: params.expiration }); vars.merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL({ createLLParams: createLLParams, diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index 60818d3f..1388e7e4 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; +import { Errors } from "src/libraries/Errors.sol"; import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStreamerLL.sol"; import { MerkleStreamer_Integration_Test } from "../../MerkleStreamer.t.sol"; @@ -12,8 +13,28 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T MerkleStreamer_Integration_Test.setUp(); } + function test_RevertWhen_NameTooLong() external { + string memory ipfsCID = defaults.IPFS_CID(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientsCount = defaults.RECIPIENTS_COUNT(); + + defaultCreateLLParams.name = "this string is longer than 32 characters"; + + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleStreamer_NameTooLong.selector)); + merkleStreamerFactory.createMerkleStreamerLL({ + createLLParams: defaultCreateLLParams, + ipfsCID: ipfsCID, + aggregateAmount: aggregateAmount, + recipientsCount: recipientsCount + }); + } + + modifier whenNameIsNotTooLong() { + _; + } + /// @dev This test works because a default Merkle streamer is deployed in {Integration_Test.setUp} - function test_RevertGiven_AlreadyDeployed() external { + function test_RevertGiven_AlreadyDeployed() external whenNameIsNotTooLong { string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientsCount = defaults.RECIPIENTS_COUNT(); @@ -31,7 +52,14 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T _; } - function testFuzz_CreateMerkleStreamerLL(address admin, uint40 expiration) external givenNotAlreadyDeployed { + function testFuzz_CreateMerkleStreamerLL( + address admin, + uint40 expiration + ) + external + givenNotAlreadyDeployed + whenNameIsNotTooLong + { vm.assume(admin != users.admin); address expectedStreamerLL = computeMerkleStreamerLLAddress(admin, expiration); diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree index 48eeaea2..e9c8f8ea 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree @@ -1,6 +1,9 @@ createMerkleStreamerLL.t.sol -├── given the Merkle streamer has been deployed with CREATE2 -│ └── it should revert -└── given the Merkle streamer has not been deployed - ├── it should deploy the Merkle streamer - └── it should emit an {CreateMerkleStreamerLL} event +├── when the campaign name is longer than 32 characters +│ └── it should revert +└── when the campaign name is within 32 characters + ├── given the Merkle streamer has been deployed with CREATE2 + │ └── it should revert + └── given the Merkle streamer has not been deployed + ├── it should deploy the Merkle streamer + └── it should emit an {CreateMerkleStreamerLL} event From a848ce9e11eeb57789e0b7f6c4878490c772dc81 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 19 Jan 2024 00:18:49 +0530 Subject: [PATCH 3/9] refactor: use an struct for MerkleStreamer constructor parameters --- script/CreateMerkleStreamerLL.s.sol | 14 ++++- src/SablierV2MerkleStreamerFactory.sol | 63 +++++++++++++------ src/SablierV2MerkleStreamerLL.sol | 20 +++--- src/abstracts/SablierV2MerkleStreamer.sol | 35 +++++------ src/interfaces/ISablierV2MerkleStreamer.sol | 6 +- .../ISablierV2MerkleStreamerFactory.sol | 12 ++-- src/libraries/Errors.sol | 4 +- src/types/DataTypes.sol | 11 +--- test/Base.t.sol | 34 +++------- .../merkle-streamer/MerkleStreamerLL.t.sol | 17 +++-- .../merkle-streamer/MerkleStreamer.t.sol | 11 +--- .../createMerkleStreamerLL.t.sol | 35 +++++++---- .../createMerkleStreamerLL.tree | 4 +- .../ll/constructor/constructor.t.sol | 7 ++- test/utils/Defaults.sol | 30 ++++++++- test/utils/Events.sol | 4 +- 16 files changed, 174 insertions(+), 133 deletions(-) diff --git a/script/CreateMerkleStreamerLL.s.sol b/script/CreateMerkleStreamerLL.s.sol index 9109d05a..c1ec6f69 100644 --- a/script/CreateMerkleStreamerLL.s.sol +++ b/script/CreateMerkleStreamerLL.s.sol @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; +import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; +import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; + import { BaseScript } from "./Base.s.sol"; import { ISablierV2MerkleStreamerFactory } from "../src/interfaces/ISablierV2MerkleStreamerFactory.sol"; @@ -9,7 +12,9 @@ import { MerkleStreamer } from "../src/types/DataTypes.sol"; contract CreateMerkleStreamerLL is BaseScript { struct Params { - MerkleStreamer.CreateWithLockupLinear createLLParams; + MerkleStreamer.ConstructorParams constructorParams; + ISablierV2LockupLinear lockupLinear; + LockupLinear.Durations streamDurations; string ipfsCID; uint256 campaignTotalAmount; uint256 recipientsCount; @@ -24,7 +29,12 @@ contract CreateMerkleStreamerLL is BaseScript { returns (ISablierV2MerkleStreamerLL merkleStreamerLL) { merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL( - params.createLLParams, params.ipfsCID, params.campaignTotalAmount, params.recipientsCount + params.constructorParams, + params.lockupLinear, + params.streamDurations, + params.ipfsCID, + params.campaignTotalAmount, + params.recipientsCount ); } } diff --git a/src/SablierV2MerkleStreamerFactory.sol b/src/SablierV2MerkleStreamerFactory.sol index d5f3c700..1451a16b 100644 --- a/src/SablierV2MerkleStreamerFactory.sol +++ b/src/SablierV2MerkleStreamerFactory.sol @@ -2,6 +2,7 @@ pragma solidity >=0.8.22; import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2MerkleStreamerFactory } from "./interfaces/ISablierV2MerkleStreamerFactory.sol"; import { ISablierV2MerkleStreamerLL } from "./interfaces/ISablierV2MerkleStreamerLL.sol"; @@ -17,7 +18,9 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { /// @notice inheritdoc ISablierV2MerkleStreamerFactory function createMerkleStreamerLL( - MerkleStreamer.CreateWithLockupLinear memory createLLParams, + MerkleStreamer.ConstructorParams memory params, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations, string memory ipfsCID, uint256 aggregateAmount, uint256 recipientsCount @@ -28,33 +31,53 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { // Hash the parameters to generate a salt. bytes32 salt = keccak256( abi.encodePacked( - createLLParams.initialAdmin, - createLLParams.lockupLinear, - createLLParams.asset, - bytes32(abi.encodePacked(createLLParams.name)), - createLLParams.merkleRoot, - createLLParams.expiration, - abi.encode(createLLParams.streamDurations), - createLLParams.cancelable, - createLLParams.transferable + params.initialAdmin, + params.asset, + bytes32(abi.encodePacked(params.name)), + params.merkleRoot, + params.expiration, + params.cancelable, + params.transferable, + lockupLinear, + abi.encode(streamDurations) ) ); // Deploy the Merkle streamer with CREATE2. - merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }(createLLParams); + merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }(params, lockupLinear, streamDurations); + // Using a different function to emit the event to avoid stack too deep error. + _emitLLEvent(merkleStreamerLL, params, lockupLinear, streamDurations, ipfsCID, aggregateAmount, recipientsCount); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Helper function to emit the {CreateMerkleStreamerLL} event. + function _emitLLEvent( + ISablierV2MerkleStreamerLL merkleStreamerLL, + MerkleStreamer.ConstructorParams memory params, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations, + string memory ipfsCID, + uint256 aggregateAmount, + uint256 recipientsCount + ) + internal + { // Log the creation of the Merkle streamer, including some metadata that is not stored on-chain. emit CreateMerkleStreamerLL( merkleStreamerLL, - createLLParams.initialAdmin, - createLLParams.lockupLinear, - createLLParams.asset, - createLLParams.name, - createLLParams.merkleRoot, - createLLParams.expiration, - createLLParams.streamDurations, - createLLParams.cancelable, - createLLParams.transferable, + params.initialAdmin, + params.asset, + params.name, + params.merkleRoot, + params.expiration, + params.cancelable, + params.transferable, + lockupLinear, + streamDurations, ipfsCID, aggregateAmount, recipientsCount diff --git a/src/SablierV2MerkleStreamerLL.sol b/src/SablierV2MerkleStreamerLL.sol index 26c198e0..4b5473c7 100644 --- a/src/SablierV2MerkleStreamerLL.sol +++ b/src/SablierV2MerkleStreamerLL.sol @@ -41,19 +41,15 @@ contract SablierV2MerkleStreamerLL is /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier /// contract. - constructor(MerkleStreamer.CreateWithLockupLinear memory createParams) - SablierV2MerkleStreamer( - createParams.initialAdmin, - createParams.asset, - createParams.name, - createParams.merkleRoot, - createParams.expiration, - createParams.cancelable, - createParams.transferable - ) + constructor( + MerkleStreamer.ConstructorParams memory params, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations_ + ) + SablierV2MerkleStreamer(params) { - LOCKUP_LINEAR = createParams.lockupLinear; - streamDurations = createParams.streamDurations; + LOCKUP_LINEAR = lockupLinear; + streamDurations = streamDurations_; // Max approve the Sablier contract to spend funds from the Merkle streamer. ASSET.forceApprove(address(LOCKUP_LINEAR), type(uint256).max); diff --git a/src/abstracts/SablierV2MerkleStreamer.sol b/src/abstracts/SablierV2MerkleStreamer.sol index d671b729..d5edd760 100644 --- a/src/abstracts/SablierV2MerkleStreamer.sol +++ b/src/abstracts/SablierV2MerkleStreamer.sol @@ -8,6 +8,7 @@ import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { Adminable } from "@sablier/v2-core/src/abstracts/Adminable.sol"; import { ISablierV2MerkleStreamer } from "../interfaces/ISablierV2MerkleStreamer.sol"; +import { MerkleStreamer } from "../types/DataTypes.sol"; import { Errors } from "../libraries/Errors.sol"; /// @title SablierV2MerkleStreamer @@ -57,26 +58,22 @@ abstract contract SablierV2MerkleStreamer is //////////////////////////////////////////////////////////////////////////*/ /// @dev Constructs the contract by initializing the immutable state variables. - constructor( - address initialAdmin, - IERC20 asset, - string memory name, - bytes32 merkleRoot, - uint40 expiration, - bool cancelable, - bool transferable - ) { - if (bytes(name).length > 32) { - revert Errors.SablierV2MerkleStreamer_NameTooLong(); + constructor(MerkleStreamer.ConstructorParams memory params) { + // Checks: the campaign name is not greater than 32 bytes + if (bytes(params.name).length > 32) { + revert Errors.SablierV2MerkleStreamerFactory_CampaignNameTooLong({ + nameLength: bytes(params.name).length, + maxLength: 32 + }); } - admin = initialAdmin; - ASSET = asset; - _NAME = bytes32(abi.encodePacked(name)); - MERKLE_ROOT = merkleRoot; - EXPIRATION = expiration; - CANCELABLE = cancelable; - TRANSFERABLE = transferable; + admin = params.initialAdmin; + ASSET = params.asset; + _NAME = bytes32(abi.encodePacked(params.name)); + MERKLE_ROOT = params.merkleRoot; + EXPIRATION = params.expiration; + CANCELABLE = params.cancelable; + TRANSFERABLE = params.transferable; } /*////////////////////////////////////////////////////////////////////////// @@ -94,7 +91,7 @@ abstract contract SablierV2MerkleStreamer is } /// @inheritdoc ISablierV2MerkleStreamer - function NAME() external view override returns (string memory) { + function name() external view override returns (string memory) { return string(abi.encodePacked(_NAME)); } diff --git a/src/interfaces/ISablierV2MerkleStreamer.sol b/src/interfaces/ISablierV2MerkleStreamer.sol index 2c5376a5..0079e149 100644 --- a/src/interfaces/ISablierV2MerkleStreamer.sol +++ b/src/interfaces/ISablierV2MerkleStreamer.sol @@ -29,9 +29,6 @@ interface ISablierV2MerkleStreamer is IAdminable { /// @dev This is an immutable state variable. function ASSET() external returns (IERC20); - /// @notice The name of the Merkle streamer contract. - function NAME() external returns (string memory); - /// @notice A flag indicating whether the streams can be canceled. /// @dev This is an immutable state variable. function CANCELABLE() external returns (bool); @@ -41,6 +38,9 @@ interface ISablierV2MerkleStreamer is IAdminable { /// @dev This is an immutable state variable. function EXPIRATION() external returns (uint40); + /// @notice Retrieves the name of the campaign. + function name() external returns (string memory); + /// @notice Returns a flag indicating whether a claim has been made for a given index. /// @dev Uses a bitmap to save gas. /// @param index The index of the recipient to check. diff --git a/src/interfaces/ISablierV2MerkleStreamerFactory.sol b/src/interfaces/ISablierV2MerkleStreamerFactory.sol index 9faf6d78..3c0ef8d3 100644 --- a/src/interfaces/ISablierV2MerkleStreamerFactory.sol +++ b/src/interfaces/ISablierV2MerkleStreamerFactory.sol @@ -19,14 +19,14 @@ interface ISablierV2MerkleStreamerFactory { event CreateMerkleStreamerLL( ISablierV2MerkleStreamerLL merkleStreamer, address indexed admin, - ISablierV2LockupLinear indexed lockupLinear, IERC20 indexed asset, string name, bytes32 merkleRoot, uint40 expiration, - LockupLinear.Durations streamDurations, bool cancelable, bool transferable, + ISablierV2LockupLinear indexed lockupLinear, + LockupLinear.Durations streamDurations, string ipfsCID, uint256 aggregateAmount, uint256 recipientsCount @@ -38,14 +38,18 @@ interface ISablierV2MerkleStreamerFactory { /// @notice Creates a new Merkle streamer that uses Lockup Linear. /// @dev Emits a {CreateMerkleStreamerLL} event. - /// @param createLLParams Struct encapsulating the {SablierV2MerkleStreamerLL} parameters, which are documented in + /// @param params Struct encapsulating the {SablierV2MerkleStreamer} parameters, which are documented in /// {DataTypes}. + /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param streamDurations The durations for each stream due to the recipient. /// @param ipfsCID Metadata parameter emitted for indexing purposes. /// @param aggregateAmount Total amount of ERC-20 assets to be streamed to all recipients. /// @param recipientsCount Total number of recipients eligible to claim. /// @return merkleStreamerLL The address of the newly created Merkle streamer contract. function createMerkleStreamerLL( - MerkleStreamer.CreateWithLockupLinear memory createLLParams, + MerkleStreamer.ConstructorParams memory params, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations, string memory ipfsCID, uint256 aggregateAmount, uint256 recipientsCount diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index c250455e..ea2c884c 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -26,6 +26,6 @@ library Errors { /// @notice Thrown when trying to claim the same stream more than once. error SablierV2MerkleStreamer_StreamClaimed(uint256 index); - /// @notice Thrown when name of the Merkle Streamer contract is longer than 32 bytes. - error SablierV2MerkleStreamer_NameTooLong(); + /// @notice Thrown when trying to create a campaign with a name that is too long. + error SablierV2MerkleStreamerFactory_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 98612fd0..659dac88 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2Lockup } from "@sablier/v2-core/src/interfaces/ISablierV2Lockup.sol"; -import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { Broker, LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; library Batch { @@ -64,26 +63,20 @@ library Batch { } library MerkleStreamer { - /// @notice Struct encapsulating the {SablierV2MerkleStreamerLL} parameters for the - /// {SablierV2MerkleStreamerFactory.createMerkleStreamerLL} - /// function. + /// @notice Struct encapsulating all constructor parameters of {SablierV2MerkleStreamer}. /// @param initialAdmin The initial admin of the Merkle streamer contract. - /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. /// @param asset The address of the streamed ERC-20 asset. /// @param name The name of the Merkle streamer contract. /// @param merkleRoot The Merkle root of the claim data. /// @param expiration The expiration of the streaming campaign, as a Unix timestamp. - /// @param streamDurations The durations for each stream due to the recipient. /// @param cancelable Indicates if each stream will be cancelable. /// @param transferable Indicates if each stream NFT will be transferable. - struct CreateWithLockupLinear { + struct ConstructorParams { address initialAdmin; - ISablierV2LockupLinear lockupLinear; IERC20 asset; string name; bytes32 merkleRoot; uint40 expiration; - LockupLinear.Durations streamDurations; bool cancelable; bool transferable; } diff --git a/test/Base.t.sol b/test/Base.t.sol index 8f0fd0fe..6b14b7fa 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -251,28 +251,6 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions MERKLE-STREAMER //////////////////////////////////////////////////////////////////////////*/ - function createWithLockupLinear( - address admin, - bytes32 merkleRoot, - uint40 expiration - ) - internal - view - returns (MerkleStreamer.CreateWithLockupLinear memory) - { - return MerkleStreamer.CreateWithLockupLinear({ - initialAdmin: admin, - lockupLinear: lockupLinear, - asset: asset, - name: defaults.NAME_STRING(), - merkleRoot: merkleRoot, - expiration: expiration, - streamDurations: defaults.durations(), - cancelable: defaults.CANCELABLE(), - transferable: defaults.TRANSFERABLE() - }); - } - function computeMerkleStreamerLLAddress( address admin, bytes32 merkleRoot, @@ -284,14 +262,14 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions bytes32 salt = keccak256( abi.encodePacked( admin, - lockupLinear, asset, - defaults.NAME(), + defaults.NAME_BYTES32(), merkleRoot, expiration, - abi.encode(defaults.durations()), defaults.CANCELABLE(), - defaults.TRANSFERABLE() + defaults.TRANSFERABLE(), + lockupLinear, + abi.encode(defaults.durations()) ) ); bytes32 creationBytecodeHash = keccak256(getMerkleStreamerLLBytecode(admin, merkleRoot, expiration)); @@ -310,7 +288,9 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions internal returns (bytes memory) { - bytes memory constructorArgs = abi.encode(createWithLockupLinear(admin, merkleRoot, expiration)); + bytes memory constructorArgs = abi.encode( + defaults.createConstructorParams(admin, merkleRoot, expiration), lockupLinear, defaults.durations() + ); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierV2MerkleStreamerLL).creationCode, constructorArgs); } else { diff --git a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol index eca4f79b..27afd46b 100644 --- a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol +++ b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol @@ -95,24 +95,29 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { emit CreateMerkleStreamerLL({ merkleStreamer: ISablierV2MerkleStreamerLL(vars.expectedStreamerLL), admin: params.admin, - lockupLinear: lockupLinear, asset: asset, - name: defaults.NAME_STRING(), + name: defaults.NAME(), merkleRoot: vars.merkleRoot, expiration: params.expiration, - streamDurations: defaults.durations(), cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), aggregateAmount: vars.aggregateAmount, recipientsCount: vars.recipientsCount }); - MerkleStreamer.CreateWithLockupLinear memory createLLParams = - createWithLockupLinear({ admin: params.admin, merkleRoot: vars.merkleRoot, expiration: params.expiration }); + MerkleStreamer.ConstructorParams memory constructorParams = defaults.createConstructorParams({ + admin: params.admin, + merkleRoot: vars.merkleRoot, + expiration: params.expiration + }); vars.merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL({ - createLLParams: createLLParams, + params: constructorParams, + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), aggregateAmount: vars.aggregateAmount, recipientsCount: vars.recipientsCount diff --git a/test/integration/merkle-streamer/MerkleStreamer.t.sol b/test/integration/merkle-streamer/MerkleStreamer.t.sol index b1a86504..71af3222 100644 --- a/test/integration/merkle-streamer/MerkleStreamer.t.sol +++ b/test/integration/merkle-streamer/MerkleStreamer.t.sol @@ -3,19 +3,12 @@ pragma solidity >=0.8.22; import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStreamerLL.sol"; -import { MerkleStreamer } from "src/types/DataTypes.sol"; - import { Integration_Test } from "../Integration.t.sol"; abstract contract MerkleStreamer_Integration_Test is Integration_Test { - MerkleStreamer.CreateWithLockupLinear internal defaultCreateLLParams; - function setUp() public virtual override { Integration_Test.setUp(); - // Create the default Merkle streamer constructor parameters. - defaultCreateLLParams = createWithLockupLinear(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); - // Create the default Merkle streamer. merkleStreamerLL = createMerkleStreamerLL(); @@ -62,7 +55,9 @@ abstract contract MerkleStreamer_Integration_Test is Integration_Test { function createMerkleStreamerLL(address admin, uint40 expiration) internal returns (ISablierV2MerkleStreamerLL) { return merkleStreamerFactory.createMerkleStreamerLL({ - createLLParams: createWithLockupLinear(admin, defaults.MERKLE_ROOT(), expiration), + params: defaults.createConstructorParams(admin, defaults.MERKLE_ROOT(), expiration), + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientsCount: defaults.RECIPIENTS_COUNT() diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index 1388e7e4..2b67335e 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -5,6 +5,7 @@ import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { Errors } from "src/libraries/Errors.sol"; import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "src/types/DataTypes.sol"; import { MerkleStreamer_Integration_Test } from "../../MerkleStreamer.t.sol"; @@ -13,35 +14,47 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T MerkleStreamer_Integration_Test.setUp(); } - function test_RevertWhen_NameTooLong() external { + function test_RevertWhen_CampaignNameTooLong() external { + MerkleStreamer.ConstructorParams memory params = defaults.createConstructorParams(); + LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientsCount = defaults.RECIPIENTS_COUNT(); - defaultCreateLLParams.name = "this string is longer than 32 characters"; + params.name = "this string is longer than 32 characters"; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleStreamer_NameTooLong.selector)); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2MerkleStreamerFactory_CampaignNameTooLong.selector, bytes(params.name).length, 32 + ) + ); merkleStreamerFactory.createMerkleStreamerLL({ - createLLParams: defaultCreateLLParams, + params: params, + lockupLinear: lockupLinear, + streamDurations: streamDurations, ipfsCID: ipfsCID, aggregateAmount: aggregateAmount, recipientsCount: recipientsCount }); } - modifier whenNameIsNotTooLong() { + modifier whenCampaignNameIsNotTooLong() { _; } /// @dev This test works because a default Merkle streamer is deployed in {Integration_Test.setUp} - function test_RevertGiven_AlreadyDeployed() external whenNameIsNotTooLong { + function test_RevertGiven_AlreadyDeployed() external whenCampaignNameIsNotTooLong { + MerkleStreamer.ConstructorParams memory params = defaults.createConstructorParams(); + LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientsCount = defaults.RECIPIENTS_COUNT(); vm.expectRevert(); merkleStreamerFactory.createMerkleStreamerLL({ - createLLParams: defaultCreateLLParams, + params: params, + lockupLinear: lockupLinear, + streamDurations: streamDurations, ipfsCID: ipfsCID, aggregateAmount: aggregateAmount, recipientsCount: recipientsCount @@ -58,7 +71,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T ) external givenNotAlreadyDeployed - whenNameIsNotTooLong + whenCampaignNameIsNotTooLong { vm.assume(admin != users.admin); address expectedStreamerLL = computeMerkleStreamerLLAddress(admin, expiration); @@ -67,14 +80,14 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T emit CreateMerkleStreamerLL({ merkleStreamer: ISablierV2MerkleStreamerLL(expectedStreamerLL), admin: admin, - lockupLinear: lockupLinear, asset: asset, - name: defaults.NAME_STRING(), + name: defaults.NAME(), merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration, - streamDurations: defaults.durations(), cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientsCount: defaults.RECIPIENTS_COUNT() diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree index e9c8f8ea..86fe8b6f 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree @@ -1,7 +1,7 @@ createMerkleStreamerLL.t.sol -├── when the campaign name is longer than 32 characters +├── when the campaign name is too long │ └── it should revert -└── when the campaign name is within 32 characters +└── when the campaign name is not too long ├── given the Merkle streamer has been deployed with CREATE2 │ └── it should revert └── given the Merkle streamer has not been deployed diff --git a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol index 088817bc..607e20fb 100644 --- a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol +++ b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol @@ -33,7 +33,8 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra } function test_Constructor() external { - SablierV2MerkleStreamerLL constructedStreamerLL = new SablierV2MerkleStreamerLL(defaultCreateLLParams); + SablierV2MerkleStreamerLL constructedStreamerLL = + new SablierV2MerkleStreamerLL(defaults.createConstructorParams(), lockupLinear, defaults.durations()); Vars memory vars; @@ -45,8 +46,8 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra vars.expectedAsset = address(asset); assertEq(vars.actualAsset, vars.expectedAsset, "asset"); - vars.actualName = constructedStreamerLL.NAME(); - vars.expectedName = defaults.NAME(); + vars.actualName = constructedStreamerLL.name(); + vars.expectedName = defaults.NAME_BYTES32(); assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); vars.actualMerkleRoot = constructedStreamerLL.MERKLE_ROOT(); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 88829cff..b8d2025b 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -7,7 +7,7 @@ import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { Broker, LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; -import { Batch } from "src/types/DataTypes.sol"; +import { Batch, MerkleStreamer } from "src/types/DataTypes.sol"; import { ArrayBuilder } from "./ArrayBuilder.sol"; import { BatchBuilder } from "./BatchBuilder.sol"; @@ -55,8 +55,8 @@ contract Defaults is Merkle { bool public constant TRANSFERABLE = false; uint256[] public LEAVES = new uint256[](RECIPIENTS_COUNT); bytes32 public immutable MERKLE_ROOT; - string public constant NAME_STRING = "Airdrop Campaign"; - bytes32 public constant NAME = 0x41697264726f702043616d706169676e00000000000000000000000000000000; + string public constant NAME = "Airdrop Campaign"; + bytes32 public constant NAME_BYTES32 = bytes32(abi.encodePacked("Airdrop Campaign")); /*////////////////////////////////////////////////////////////////////////// VARIABLES @@ -116,6 +116,30 @@ contract Defaults is Merkle { return getProof(LEAVES.toBytes32(), pos); } + function createConstructorParams() public view returns (MerkleStreamer.ConstructorParams memory) { + return createConstructorParams(users.admin, MERKLE_ROOT, EXPIRATION); + } + + function createConstructorParams( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + public + view + returns (MerkleStreamer.ConstructorParams memory) + { + return MerkleStreamer.ConstructorParams({ + initialAdmin: admin, + asset: asset, + name: NAME, + merkleRoot: merkleRoot, + expiration: expiration, + cancelable: CANCELABLE, + transferable: TRANSFERABLE + }); + } + /*////////////////////////////////////////////////////////////////////////// SABLIER-V2-LOCKUP //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 20d9625f..2ede7cd6 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -14,14 +14,14 @@ abstract contract Events { event CreateMerkleStreamerLL( ISablierV2MerkleStreamerLL merkleStreamer, address indexed admin, - ISablierV2LockupLinear indexed lockupLinear, IERC20 indexed asset, string name, bytes32 merkleRoot, uint40 expiration, - LockupLinear.Durations streamDurations, bool cancelable, bool transferable, + ISablierV2LockupLinear indexed lockupLinear, + LockupLinear.Durations streamDurations, string ipfsCID, uint256 aggregateAmount, uint256 recipientsCount From 43fd957ec193c8463cd1125b9e4eadd1bc5d0597 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Fri, 19 Jan 2024 13:49:06 +0200 Subject: [PATCH 4/9] test: rename defaults function --- test/Base.t.sol | 5 ++--- test/fork/merkle-streamer/MerkleStreamerLL.t.sol | 2 +- test/integration/merkle-streamer/MerkleStreamer.t.sol | 2 +- .../create-merkle-streamer-ll/createMerkleStreamerLL.t.sol | 5 +++-- .../merkle-streamer/ll/constructor/constructor.t.sol | 2 +- test/utils/Defaults.sol | 6 +++--- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/Base.t.sol b/test/Base.t.sol index 6b14b7fa..24bf95a4 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -288,9 +288,8 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions internal returns (bytes memory) { - bytes memory constructorArgs = abi.encode( - defaults.createConstructorParams(admin, merkleRoot, expiration), lockupLinear, defaults.durations() - ); + bytes memory constructorArgs = + abi.encode(defaults.constructorParams(admin, merkleRoot, expiration), lockupLinear, defaults.durations()); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierV2MerkleStreamerLL).creationCode, constructorArgs); } else { diff --git a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol index 27afd46b..17195ea3 100644 --- a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol +++ b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol @@ -108,7 +108,7 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { recipientsCount: vars.recipientsCount }); - MerkleStreamer.ConstructorParams memory constructorParams = defaults.createConstructorParams({ + MerkleStreamer.ConstructorParams memory constructorParams = defaults.constructorParams({ admin: params.admin, merkleRoot: vars.merkleRoot, expiration: params.expiration diff --git a/test/integration/merkle-streamer/MerkleStreamer.t.sol b/test/integration/merkle-streamer/MerkleStreamer.t.sol index 71af3222..a34587d3 100644 --- a/test/integration/merkle-streamer/MerkleStreamer.t.sol +++ b/test/integration/merkle-streamer/MerkleStreamer.t.sol @@ -55,7 +55,7 @@ abstract contract MerkleStreamer_Integration_Test is Integration_Test { function createMerkleStreamerLL(address admin, uint40 expiration) internal returns (ISablierV2MerkleStreamerLL) { return merkleStreamerFactory.createMerkleStreamerLL({ - params: defaults.createConstructorParams(admin, defaults.MERKLE_ROOT(), expiration), + params: defaults.constructorParams(admin, defaults.MERKLE_ROOT(), expiration), lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index 2b67335e..f69a0613 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -15,7 +15,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T } function test_RevertWhen_CampaignNameTooLong() external { - MerkleStreamer.ConstructorParams memory params = defaults.createConstructorParams(); + MerkleStreamer.ConstructorParams memory params = defaults.constructorParams(); LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); @@ -28,6 +28,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T Errors.SablierV2MerkleStreamerFactory_CampaignNameTooLong.selector, bytes(params.name).length, 32 ) ); + merkleStreamerFactory.createMerkleStreamerLL({ params: params, lockupLinear: lockupLinear, @@ -44,7 +45,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T /// @dev This test works because a default Merkle streamer is deployed in {Integration_Test.setUp} function test_RevertGiven_AlreadyDeployed() external whenCampaignNameIsNotTooLong { - MerkleStreamer.ConstructorParams memory params = defaults.createConstructorParams(); + MerkleStreamer.ConstructorParams memory params = defaults.constructorParams(); LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); diff --git a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol index 607e20fb..aabdd1b9 100644 --- a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol +++ b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol @@ -34,7 +34,7 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra function test_Constructor() external { SablierV2MerkleStreamerLL constructedStreamerLL = - new SablierV2MerkleStreamerLL(defaults.createConstructorParams(), lockupLinear, defaults.durations()); + new SablierV2MerkleStreamerLL(defaults.constructorParams(), lockupLinear, defaults.durations()); Vars memory vars; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index b8d2025b..082d4ca1 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -116,11 +116,11 @@ contract Defaults is Merkle { return getProof(LEAVES.toBytes32(), pos); } - function createConstructorParams() public view returns (MerkleStreamer.ConstructorParams memory) { - return createConstructorParams(users.admin, MERKLE_ROOT, EXPIRATION); + function constructorParams() public view returns (MerkleStreamer.ConstructorParams memory) { + return constructorParams(users.admin, MERKLE_ROOT, EXPIRATION); } - function createConstructorParams( + function constructorParams( address admin, bytes32 merkleRoot, uint40 expiration From 6519ae746d75f2b12ce3cd4c0224daa0f68d07a2 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Tue, 23 Jan 2024 14:23:08 +0200 Subject: [PATCH 5/9] refactor: rename custom error chore: small rewording changes refactor: update import --- src/SablierV2MerkleStreamerFactory.sol | 2 +- src/abstracts/SablierV2MerkleStreamer.sol | 2 +- src/libraries/Errors.sol | 6 +++--- src/types/DataTypes.sol | 2 +- .../create-merkle-streamer-ll/createMerkleStreamerLL.t.sol | 2 +- .../create-merkle-streamer-ll/createMerkleStreamerLL.tree | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/SablierV2MerkleStreamerFactory.sol b/src/SablierV2MerkleStreamerFactory.sol index 1451a16b..4a6fef1e 100644 --- a/src/SablierV2MerkleStreamerFactory.sol +++ b/src/SablierV2MerkleStreamerFactory.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.22; import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; +import { SablierV2MerkleStreamerLL } from "./SablierV2MerkleStreamerLL.sol"; import { ISablierV2MerkleStreamerFactory } from "./interfaces/ISablierV2MerkleStreamerFactory.sol"; import { ISablierV2MerkleStreamerLL } from "./interfaces/ISablierV2MerkleStreamerLL.sol"; -import { SablierV2MerkleStreamerLL } from "./SablierV2MerkleStreamerLL.sol"; import { MerkleStreamer } from "./types/DataTypes.sol"; /// @title SablierV2MerkleStreamerFactory diff --git a/src/abstracts/SablierV2MerkleStreamer.sol b/src/abstracts/SablierV2MerkleStreamer.sol index d5edd760..09b6350c 100644 --- a/src/abstracts/SablierV2MerkleStreamer.sol +++ b/src/abstracts/SablierV2MerkleStreamer.sol @@ -61,7 +61,7 @@ abstract contract SablierV2MerkleStreamer is constructor(MerkleStreamer.ConstructorParams memory params) { // Checks: the campaign name is not greater than 32 bytes if (bytes(params.name).length > 32) { - revert Errors.SablierV2MerkleStreamerFactory_CampaignNameTooLong({ + revert Errors.SablierV2MerkleStreamer_CampaignNameTooLong({ nameLength: bytes(params.name).length, maxLength: 32 }); diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol index ea2c884c..1c343584 100644 --- a/src/libraries/Errors.sol +++ b/src/libraries/Errors.sol @@ -17,6 +17,9 @@ library Errors { /// @notice Thrown when trying to claim after the campaign has expired. error SablierV2MerkleStreamer_CampaignExpired(uint256 currentTime, uint40 expiration); + /// @notice Thrown when trying to create a campaign with a name that is too long. + error SablierV2MerkleStreamer_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); + /// @notice Thrown when trying to clawback when the campaign has not expired. error SablierV2MerkleStreamer_CampaignNotExpired(uint256 currentTime, uint40 expiration); @@ -25,7 +28,4 @@ library Errors { /// @notice Thrown when trying to claim the same stream more than once. error SablierV2MerkleStreamer_StreamClaimed(uint256 index); - - /// @notice Thrown when trying to create a campaign with a name that is too long. - error SablierV2MerkleStreamerFactory_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 659dac88..02549065 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -63,7 +63,7 @@ library Batch { } library MerkleStreamer { - /// @notice Struct encapsulating all constructor parameters of {SablierV2MerkleStreamer}. + /// @notice Struct encapsulating the base constructor parameter of a {SablierV2MerkleStreamer} contract. /// @param initialAdmin The initial admin of the Merkle streamer contract. /// @param asset The address of the streamed ERC-20 asset. /// @param name The name of the Merkle streamer contract. diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index f69a0613..c1090d70 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -25,7 +25,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2MerkleStreamerFactory_CampaignNameTooLong.selector, bytes(params.name).length, 32 + Errors.SablierV2MerkleStreamer_CampaignNameTooLong.selector, bytes(params.name).length, 32 ) ); diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree index 86fe8b6f..0ca44455 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.tree @@ -6,4 +6,4 @@ createMerkleStreamerLL.t.sol │ └── it should revert └── given the Merkle streamer has not been deployed ├── it should deploy the Merkle streamer - └── it should emit an {CreateMerkleStreamerLL} event + └── it should emit a {CreateMerkleStreamerLL} event From 8051b4ea7a7db058f66dd90fc6b00addb8b5346a Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 23 Jan 2024 16:30:37 +0200 Subject: [PATCH 6/9] refactor: add constructor params in event test: update tests accordingly chore: remove unused imports --- src/SablierV2MerkleStreamerFactory.sol | 34 +------------------ .../ISablierV2MerkleStreamerFactory.sol | 13 ++----- test/Base.t.sol | 1 - .../merkle-streamer/MerkleStreamerLL.t.sol | 26 ++++++-------- .../createMerkleStreamerLL.t.sol | 13 +++---- test/utils/Events.sol | 14 +++----- 6 files changed, 24 insertions(+), 77 deletions(-) diff --git a/src/SablierV2MerkleStreamerFactory.sol b/src/SablierV2MerkleStreamerFactory.sol index 4a6fef1e..8a6379d8 100644 --- a/src/SablierV2MerkleStreamerFactory.sol +++ b/src/SablierV2MerkleStreamerFactory.sol @@ -47,40 +47,8 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }(params, lockupLinear, streamDurations); // Using a different function to emit the event to avoid stack too deep error. - _emitLLEvent(merkleStreamerLL, params, lockupLinear, streamDurations, ipfsCID, aggregateAmount, recipientsCount); - } - - /*////////////////////////////////////////////////////////////////////////// - INTERNAL NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Helper function to emit the {CreateMerkleStreamerLL} event. - function _emitLLEvent( - ISablierV2MerkleStreamerLL merkleStreamerLL, - MerkleStreamer.ConstructorParams memory params, - ISablierV2LockupLinear lockupLinear, - LockupLinear.Durations memory streamDurations, - string memory ipfsCID, - uint256 aggregateAmount, - uint256 recipientsCount - ) - internal - { - // Log the creation of the Merkle streamer, including some metadata that is not stored on-chain. emit CreateMerkleStreamerLL( - merkleStreamerLL, - params.initialAdmin, - params.asset, - params.name, - params.merkleRoot, - params.expiration, - params.cancelable, - params.transferable, - lockupLinear, - streamDurations, - ipfsCID, - aggregateAmount, - recipientsCount + merkleStreamerLL, params, lockupLinear, streamDurations, ipfsCID, aggregateAmount, recipientsCount ); } } diff --git a/src/interfaces/ISablierV2MerkleStreamerFactory.sol b/src/interfaces/ISablierV2MerkleStreamerFactory.sol index 3c0ef8d3..f5b9dfef 100644 --- a/src/interfaces/ISablierV2MerkleStreamerFactory.sol +++ b/src/interfaces/ISablierV2MerkleStreamerFactory.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; @@ -17,15 +16,9 @@ interface ISablierV2MerkleStreamerFactory { /// @notice Emitted when a Sablier V2 Lockup Linear Merkle streamer is created. event CreateMerkleStreamerLL( - ISablierV2MerkleStreamerLL merkleStreamer, - address indexed admin, - IERC20 indexed asset, - string name, - bytes32 merkleRoot, - uint40 expiration, - bool cancelable, - bool transferable, - ISablierV2LockupLinear indexed lockupLinear, + ISablierV2MerkleStreamerLL indexed merkleStreamerLL, + MerkleStreamer.ConstructorParams indexed constructorParams, + ISablierV2LockupLinear lockupLinear, LockupLinear.Durations streamDurations, string ipfsCID, uint256 aggregateAmount, diff --git a/test/Base.t.sol b/test/Base.t.sol index 24bf95a4..7b57dfaf 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -19,7 +19,6 @@ import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStrea import { SablierV2Batch } from "src/SablierV2Batch.sol"; import { SablierV2MerkleStreamerFactory } from "src/SablierV2MerkleStreamerFactory.sol"; import { SablierV2MerkleStreamerLL } from "src/SablierV2MerkleStreamerLL.sol"; -import { MerkleStreamer } from "src/types/DataTypes.sol"; import { Defaults } from "./utils/Defaults.sol"; import { DeployOptimized } from "./utils/DeployOptimized.sol"; diff --git a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol index 17195ea3..13b6a09d 100644 --- a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol +++ b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol @@ -41,6 +41,7 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { uint256 aggregateAmount; uint128 clawbackAmount; address expectedStreamerLL; + MerkleStreamer.ConstructorParams constructorParams; LockupLinear.Stream expectedStream; uint256 expectedStreamId; uint256[] indexes; @@ -91,16 +92,17 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { vars.merkleRoot = getRoot(leaves.toBytes32()); vars.expectedStreamerLL = computeMerkleStreamerLLAddress(params.admin, vars.merkleRoot, params.expiration); - vm.expectEmit({ emitter: address(merkleStreamerFactory) }); - emit CreateMerkleStreamerLL({ - merkleStreamer: ISablierV2MerkleStreamerLL(vars.expectedStreamerLL), + + vars.constructorParams = defaults.constructorParams({ admin: params.admin, - asset: asset, - name: defaults.NAME(), merkleRoot: vars.merkleRoot, - expiration: params.expiration, - cancelable: defaults.CANCELABLE(), - transferable: defaults.TRANSFERABLE(), + expiration: params.expiration + }); + + vm.expectEmit({ emitter: address(merkleStreamerFactory) }); + emit CreateMerkleStreamerLL({ + merkleStreamerLL: ISablierV2MerkleStreamerLL(vars.expectedStreamerLL), + constructorParams: vars.constructorParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), @@ -108,14 +110,8 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { recipientsCount: vars.recipientsCount }); - MerkleStreamer.ConstructorParams memory constructorParams = defaults.constructorParams({ - admin: params.admin, - merkleRoot: vars.merkleRoot, - expiration: params.expiration - }); - vars.merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL({ - params: constructorParams, + params: vars.constructorParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index c1090d70..5d6bd114 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -77,16 +77,13 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T vm.assume(admin != users.admin); address expectedStreamerLL = computeMerkleStreamerLLAddress(admin, expiration); + MerkleStreamer.ConstructorParams memory constructorParams = + defaults.constructorParams({ admin: admin, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration }); + vm.expectEmit({ emitter: address(merkleStreamerFactory) }); emit CreateMerkleStreamerLL({ - merkleStreamer: ISablierV2MerkleStreamerLL(expectedStreamerLL), - admin: admin, - asset: asset, - name: defaults.NAME(), - merkleRoot: defaults.MERKLE_ROOT(), - expiration: expiration, - cancelable: defaults.CANCELABLE(), - transferable: defaults.TRANSFERABLE(), + merkleStreamerLL: ISablierV2MerkleStreamerLL(expectedStreamerLL), + constructorParams: constructorParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 2ede7cd6..7390faa5 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -1,26 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2MerkleStreamerLL } from "src/interfaces/ISablierV2MerkleStreamerLL.sol"; +import { MerkleStreamer } from "src/types/DataTypes.sol"; /// @notice Abstract contract containing all the events emitted by the protocol. abstract contract Events { event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); event Clawback(address indexed admin, address indexed to, uint128 amount); event CreateMerkleStreamerLL( - ISablierV2MerkleStreamerLL merkleStreamer, - address indexed admin, - IERC20 indexed asset, - string name, - bytes32 merkleRoot, - uint40 expiration, - bool cancelable, - bool transferable, - ISablierV2LockupLinear indexed lockupLinear, + ISablierV2MerkleStreamerLL indexed merkleStreamerLL, + MerkleStreamer.ConstructorParams indexed constructorParams, + ISablierV2LockupLinear lockupLinear, LockupLinear.Durations streamDurations, string ipfsCID, uint256 aggregateAmount, From bbf6366f0dda5d782f5f7d64beb78ab9fd2ac6c9 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 24 Jan 2024 03:19:43 +0530 Subject: [PATCH 7/9] refactor: use internal for NAME --- src/abstracts/SablierV2MerkleStreamer.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/abstracts/SablierV2MerkleStreamer.sol b/src/abstracts/SablierV2MerkleStreamer.sol index 09b6350c..0fafbfa4 100644 --- a/src/abstracts/SablierV2MerkleStreamer.sol +++ b/src/abstracts/SablierV2MerkleStreamer.sol @@ -40,11 +40,11 @@ abstract contract SablierV2MerkleStreamer is bool public immutable override TRANSFERABLE; /*////////////////////////////////////////////////////////////////////////// - PRIVATE CONSTANT + INTERNAL CONSTANT //////////////////////////////////////////////////////////////////////////*/ /// @dev The name of the campaign stored as bytes32. - bytes32 private immutable _NAME; + bytes32 internal immutable NAME; /*////////////////////////////////////////////////////////////////////////// INTERNAL STORAGE @@ -69,10 +69,10 @@ abstract contract SablierV2MerkleStreamer is admin = params.initialAdmin; ASSET = params.asset; - _NAME = bytes32(abi.encodePacked(params.name)); - MERKLE_ROOT = params.merkleRoot; - EXPIRATION = params.expiration; CANCELABLE = params.cancelable; + EXPIRATION = params.expiration; + MERKLE_ROOT = params.merkleRoot; + NAME = bytes32(abi.encodePacked(params.name)); TRANSFERABLE = params.transferable; } @@ -92,7 +92,7 @@ abstract contract SablierV2MerkleStreamer is /// @inheritdoc ISablierV2MerkleStreamer function name() external view override returns (string memory) { - return string(abi.encodePacked(_NAME)); + return string(abi.encodePacked(NAME)); } /*////////////////////////////////////////////////////////////////////////// From 712c24cce6fe2428791d133c8470316a132b0085 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 30 Jan 2024 16:12:37 +0530 Subject: [PATCH 8/9] refactor: rename params to baseParams when referring to ConstructorParams struct --- script/CreateMerkleStreamerLL.s.sol | 4 ++-- src/SablierV2MerkleStreamerFactory.sol | 20 +++++++++---------- src/SablierV2MerkleStreamerLL.sol | 4 ++-- .../ISablierV2MerkleStreamerFactory.sol | 6 +++--- test/Base.t.sol | 2 +- .../merkle-streamer/MerkleStreamerLL.t.sol | 13 +++++------- .../merkle-streamer/MerkleStreamer.t.sol | 2 +- .../createMerkleStreamerLL.t.sol | 18 ++++++++--------- .../ll/constructor/constructor.t.sol | 2 +- test/utils/Defaults.sol | 6 +++--- test/utils/Events.sol | 2 +- 11 files changed, 38 insertions(+), 41 deletions(-) diff --git a/script/CreateMerkleStreamerLL.s.sol b/script/CreateMerkleStreamerLL.s.sol index c1ec6f69..be5cd898 100644 --- a/script/CreateMerkleStreamerLL.s.sol +++ b/script/CreateMerkleStreamerLL.s.sol @@ -12,7 +12,7 @@ import { MerkleStreamer } from "../src/types/DataTypes.sol"; contract CreateMerkleStreamerLL is BaseScript { struct Params { - MerkleStreamer.ConstructorParams constructorParams; + MerkleStreamer.ConstructorParams baseParams; ISablierV2LockupLinear lockupLinear; LockupLinear.Durations streamDurations; string ipfsCID; @@ -29,7 +29,7 @@ contract CreateMerkleStreamerLL is BaseScript { returns (ISablierV2MerkleStreamerLL merkleStreamerLL) { merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL( - params.constructorParams, + params.baseParams, params.lockupLinear, params.streamDurations, params.ipfsCID, diff --git a/src/SablierV2MerkleStreamerFactory.sol b/src/SablierV2MerkleStreamerFactory.sol index 8a6379d8..7c3097a0 100644 --- a/src/SablierV2MerkleStreamerFactory.sol +++ b/src/SablierV2MerkleStreamerFactory.sol @@ -18,7 +18,7 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { /// @notice inheritdoc ISablierV2MerkleStreamerFactory function createMerkleStreamerLL( - MerkleStreamer.ConstructorParams memory params, + MerkleStreamer.ConstructorParams memory baseParams, ISablierV2LockupLinear lockupLinear, LockupLinear.Durations memory streamDurations, string memory ipfsCID, @@ -31,24 +31,24 @@ contract SablierV2MerkleStreamerFactory is ISablierV2MerkleStreamerFactory { // Hash the parameters to generate a salt. bytes32 salt = keccak256( abi.encodePacked( - params.initialAdmin, - params.asset, - bytes32(abi.encodePacked(params.name)), - params.merkleRoot, - params.expiration, - params.cancelable, - params.transferable, + baseParams.initialAdmin, + baseParams.asset, + bytes32(abi.encodePacked(baseParams.name)), + baseParams.merkleRoot, + baseParams.expiration, + baseParams.cancelable, + baseParams.transferable, lockupLinear, abi.encode(streamDurations) ) ); // Deploy the Merkle streamer with CREATE2. - merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }(params, lockupLinear, streamDurations); + merkleStreamerLL = new SablierV2MerkleStreamerLL{ salt: salt }(baseParams, lockupLinear, streamDurations); // Using a different function to emit the event to avoid stack too deep error. emit CreateMerkleStreamerLL( - merkleStreamerLL, params, lockupLinear, streamDurations, ipfsCID, aggregateAmount, recipientsCount + merkleStreamerLL, baseParams, lockupLinear, streamDurations, ipfsCID, aggregateAmount, recipientsCount ); } } diff --git a/src/SablierV2MerkleStreamerLL.sol b/src/SablierV2MerkleStreamerLL.sol index 4b5473c7..ca9fb690 100644 --- a/src/SablierV2MerkleStreamerLL.sol +++ b/src/SablierV2MerkleStreamerLL.sol @@ -42,11 +42,11 @@ contract SablierV2MerkleStreamerLL is /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier /// contract. constructor( - MerkleStreamer.ConstructorParams memory params, + MerkleStreamer.ConstructorParams memory baseParams, ISablierV2LockupLinear lockupLinear, LockupLinear.Durations memory streamDurations_ ) - SablierV2MerkleStreamer(params) + SablierV2MerkleStreamer(baseParams) { LOCKUP_LINEAR = lockupLinear; streamDurations = streamDurations_; diff --git a/src/interfaces/ISablierV2MerkleStreamerFactory.sol b/src/interfaces/ISablierV2MerkleStreamerFactory.sol index f5b9dfef..46deefaa 100644 --- a/src/interfaces/ISablierV2MerkleStreamerFactory.sol +++ b/src/interfaces/ISablierV2MerkleStreamerFactory.sol @@ -17,7 +17,7 @@ interface ISablierV2MerkleStreamerFactory { /// @notice Emitted when a Sablier V2 Lockup Linear Merkle streamer is created. event CreateMerkleStreamerLL( ISablierV2MerkleStreamerLL indexed merkleStreamerLL, - MerkleStreamer.ConstructorParams indexed constructorParams, + MerkleStreamer.ConstructorParams indexed baseParams, ISablierV2LockupLinear lockupLinear, LockupLinear.Durations streamDurations, string ipfsCID, @@ -31,7 +31,7 @@ interface ISablierV2MerkleStreamerFactory { /// @notice Creates a new Merkle streamer that uses Lockup Linear. /// @dev Emits a {CreateMerkleStreamerLL} event. - /// @param params Struct encapsulating the {SablierV2MerkleStreamer} parameters, which are documented in + /// @param baseParams Struct encapsulating the {SablierV2MerkleStreamer} parameters, which are documented in /// {DataTypes}. /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. /// @param streamDurations The durations for each stream due to the recipient. @@ -40,7 +40,7 @@ interface ISablierV2MerkleStreamerFactory { /// @param recipientsCount Total number of recipients eligible to claim. /// @return merkleStreamerLL The address of the newly created Merkle streamer contract. function createMerkleStreamerLL( - MerkleStreamer.ConstructorParams memory params, + MerkleStreamer.ConstructorParams memory baseParams, ISablierV2LockupLinear lockupLinear, LockupLinear.Durations memory streamDurations, string memory ipfsCID, diff --git a/test/Base.t.sol b/test/Base.t.sol index 7b57dfaf..792277e6 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -288,7 +288,7 @@ abstract contract Base_Test is DeployOptimized, Events, Merkle, V2CoreAssertions returns (bytes memory) { bytes memory constructorArgs = - abi.encode(defaults.constructorParams(admin, merkleRoot, expiration), lockupLinear, defaults.durations()); + abi.encode(defaults.baseParams(admin, merkleRoot, expiration), lockupLinear, defaults.durations()); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierV2MerkleStreamerLL).creationCode, constructorArgs); } else { diff --git a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol index 13b6a09d..18a29b13 100644 --- a/test/fork/merkle-streamer/MerkleStreamerLL.t.sol +++ b/test/fork/merkle-streamer/MerkleStreamerLL.t.sol @@ -41,7 +41,7 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { uint256 aggregateAmount; uint128 clawbackAmount; address expectedStreamerLL; - MerkleStreamer.ConstructorParams constructorParams; + MerkleStreamer.ConstructorParams baseParams; LockupLinear.Stream expectedStream; uint256 expectedStreamId; uint256[] indexes; @@ -93,16 +93,13 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { vars.expectedStreamerLL = computeMerkleStreamerLLAddress(params.admin, vars.merkleRoot, params.expiration); - vars.constructorParams = defaults.constructorParams({ - admin: params.admin, - merkleRoot: vars.merkleRoot, - expiration: params.expiration - }); + vars.baseParams = + defaults.baseParams({ admin: params.admin, merkleRoot: vars.merkleRoot, expiration: params.expiration }); vm.expectEmit({ emitter: address(merkleStreamerFactory) }); emit CreateMerkleStreamerLL({ merkleStreamerLL: ISablierV2MerkleStreamerLL(vars.expectedStreamerLL), - constructorParams: vars.constructorParams, + baseParams: vars.baseParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), @@ -111,7 +108,7 @@ abstract contract MerkleStreamerLL_Fork_Test is Fork_Test { }); vars.merkleStreamerLL = merkleStreamerFactory.createMerkleStreamerLL({ - params: vars.constructorParams, + baseParams: vars.baseParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), diff --git a/test/integration/merkle-streamer/MerkleStreamer.t.sol b/test/integration/merkle-streamer/MerkleStreamer.t.sol index a34587d3..63adb001 100644 --- a/test/integration/merkle-streamer/MerkleStreamer.t.sol +++ b/test/integration/merkle-streamer/MerkleStreamer.t.sol @@ -55,7 +55,7 @@ abstract contract MerkleStreamer_Integration_Test is Integration_Test { function createMerkleStreamerLL(address admin, uint40 expiration) internal returns (ISablierV2MerkleStreamerLL) { return merkleStreamerFactory.createMerkleStreamerLL({ - params: defaults.constructorParams(admin, defaults.MERKLE_ROOT(), expiration), + baseParams: defaults.baseParams(admin, defaults.MERKLE_ROOT(), expiration), lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), diff --git a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol index 5d6bd114..936cc02f 100644 --- a/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol +++ b/test/integration/merkle-streamer/factory/create-merkle-streamer-ll/createMerkleStreamerLL.t.sol @@ -15,22 +15,22 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T } function test_RevertWhen_CampaignNameTooLong() external { - MerkleStreamer.ConstructorParams memory params = defaults.constructorParams(); + MerkleStreamer.ConstructorParams memory baseParams = defaults.baseParams(); LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientsCount = defaults.RECIPIENTS_COUNT(); - params.name = "this string is longer than 32 characters"; + baseParams.name = "this string is longer than 32 characters"; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2MerkleStreamer_CampaignNameTooLong.selector, bytes(params.name).length, 32 + Errors.SablierV2MerkleStreamer_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 ) ); merkleStreamerFactory.createMerkleStreamerLL({ - params: params, + baseParams: baseParams, lockupLinear: lockupLinear, streamDurations: streamDurations, ipfsCID: ipfsCID, @@ -45,7 +45,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T /// @dev This test works because a default Merkle streamer is deployed in {Integration_Test.setUp} function test_RevertGiven_AlreadyDeployed() external whenCampaignNameIsNotTooLong { - MerkleStreamer.ConstructorParams memory params = defaults.constructorParams(); + MerkleStreamer.ConstructorParams memory baseParams = defaults.baseParams(); LockupLinear.Durations memory streamDurations = defaults.durations(); string memory ipfsCID = defaults.IPFS_CID(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); @@ -53,7 +53,7 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T vm.expectRevert(); merkleStreamerFactory.createMerkleStreamerLL({ - params: params, + baseParams: baseParams, lockupLinear: lockupLinear, streamDurations: streamDurations, ipfsCID: ipfsCID, @@ -77,13 +77,13 @@ contract CreateMerkleStreamerLL_Integration_Test is MerkleStreamer_Integration_T vm.assume(admin != users.admin); address expectedStreamerLL = computeMerkleStreamerLLAddress(admin, expiration); - MerkleStreamer.ConstructorParams memory constructorParams = - defaults.constructorParams({ admin: admin, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration }); + MerkleStreamer.ConstructorParams memory baseParams = + defaults.baseParams({ admin: admin, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration }); vm.expectEmit({ emitter: address(merkleStreamerFactory) }); emit CreateMerkleStreamerLL({ merkleStreamerLL: ISablierV2MerkleStreamerLL(expectedStreamerLL), - constructorParams: constructorParams, + baseParams: baseParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), ipfsCID: defaults.IPFS_CID(), diff --git a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol index aabdd1b9..2f0d3ea2 100644 --- a/test/integration/merkle-streamer/ll/constructor/constructor.t.sol +++ b/test/integration/merkle-streamer/ll/constructor/constructor.t.sol @@ -34,7 +34,7 @@ contract Constructor_MerkleStreamerLL_Integration_Test is MerkleStreamer_Integra function test_Constructor() external { SablierV2MerkleStreamerLL constructedStreamerLL = - new SablierV2MerkleStreamerLL(defaults.constructorParams(), lockupLinear, defaults.durations()); + new SablierV2MerkleStreamerLL(defaults.baseParams(), lockupLinear, defaults.durations()); Vars memory vars; diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 082d4ca1..bb9e395f 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -116,11 +116,11 @@ contract Defaults is Merkle { return getProof(LEAVES.toBytes32(), pos); } - function constructorParams() public view returns (MerkleStreamer.ConstructorParams memory) { - return constructorParams(users.admin, MERKLE_ROOT, EXPIRATION); + function baseParams() public view returns (MerkleStreamer.ConstructorParams memory) { + return baseParams(users.admin, MERKLE_ROOT, EXPIRATION); } - function constructorParams( + function baseParams( address admin, bytes32 merkleRoot, uint40 expiration diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 7390faa5..9a8c2a96 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -13,7 +13,7 @@ abstract contract Events { event Clawback(address indexed admin, address indexed to, uint128 amount); event CreateMerkleStreamerLL( ISablierV2MerkleStreamerLL indexed merkleStreamerLL, - MerkleStreamer.ConstructorParams indexed constructorParams, + MerkleStreamer.ConstructorParams indexed baseParams, ISablierV2LockupLinear lockupLinear, LockupLinear.Durations streamDurations, string ipfsCID, From 45c0c231b64d70e4f9b4493d80a0eb220f536315 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 30 Jan 2024 16:37:37 +0530 Subject: [PATCH 9/9] build: update bun lockfile --- bun.lockb | Bin 43329 -> 43329 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/bun.lockb b/bun.lockb index 2ba27d49b45464e71bbc676d57ea0a703b1d0c64..c0526ba6953ea0e9ad57efbb655de3d65d5c4c78 100755 GIT binary patch delta 66 zcmV-I0KNag(gMNK0+22szhWX+#y+AdA`^;hIz1?nVb5;tNXa{89TMX#n73$au};T_ Y2Vym1I5;$9lTnBqlaQzcvpk3eA)yxb%7 delta 66 zcmV-I0KNag(gMNK0+22s->6=>+;t2hmB7-@PIP+blEdLn^x8wkt7P~Mltxy8u};T_ Y2W4S4W-vK7lTnBqlaQzcvpk3eA%LeJrvLx|