-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add name
, introduces struct ConstructorParams
#262
Conversation
name
string parametername
string parameter, introduces struct CreateWithLockupLinear
name
string parameter, introduces struct CreateWithLockupLinear
name
, introduces struct CreateWithLockupLinear
b0fc891
to
fa9af8f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were you getting the stack too deep
error in both MerkleStreamer.constructor
and MerkleStreamerFactory.create
function?
Also, why do we pass a string in the constructor instead of bytes32
, wouldn't it be more efficient?
adds a new private storage _NAME of type bytes32 to store name.
smart way of doing this, congrats
I've created a separate branch where I approached things differently. The reason I did not start from your branch is that it would have taken me more time to make the changes.
Could you take a look at my branch and tell me if you consider that approach better? If yes, I will polish it. I personally prefer it because the campaign contract is not modified as much.
Thanks for the PR, Shub. It's a shame that this additional parameter forces us to use a struct in the constructor. Structs have caused all sorts of problems for V2 integrators (e.g., Tally). But I can't see any way out - unless we remove another parameter, which we can't do. My initial reaction was to suggest you discard this feature, but then I remembered LockupTranched/ LockupDynamic. It is very likely that the implementation of these other contracts will require a struct (because of the segments). So introducing structs in |
haven't we decided that the segments would be passed in the claim function, but not in the create factory function? so, there shouldn't be a difference between
now i feel like it's the right choice 😅 |
Oooh, you're right, @andreivladbrg. But at any rate, I guess that other parameters will be needed in the constructor for these other implementations. Anyway. I am happy to proceed with the implementation brought about by this PR. |
@PaulRBerg have you checked the other branch? which version do you say it's better? |
I haven't checked the other branch, no. In fact, I haven't even checked this PR properly. I've just seen the struct and wanted to comment on that. I will review it later. |
Thanks @andreivladbrg and @PaulRBerg for the comments. Please find my response below.
Only in
Yes, it's slightly more optimized to allow For example, using It might be a wrong assumption though.
Thank you for this. I am happy to take a look at it tomorrow.
Well there is
I might agree too. Do we really need a |
I had a look at your branch @andreivladbrg. It looks good to me. However, I would like to give remarks on the two major differences between this PR and your branch: 1. Data structure
See code snippet
struct CreateLL {
address initialAdmin;
string name;
ISablierV2LockupLinear lockupLinear;
IERC20 asset;
bytes32 merkleRoot;
uint40 expiration;
LockupLinear.Durations streamDurations;
bool cancelable;
bool transferable;
string ipfsCID;
uint256 aggregateAmount;
uint256 recipientsCount;
}
vs
struct CreateLL {
address initialAdmin;
ISablierV2LockupLinear lockupLinear;
IERC20 asset;
string name;
bytes32 merkleRoot;
uint40 expiration;
LockupLinear.Durations streamDurations;
bool cancelable;
bool transferable;
} My initial approach was just like yours. But then I stared to make the following assumptions:
2. Testing
After studying the v2-core and v2-periphery codebase, my observation was that all the utility files, except precompiles, are designed to declare default variables that are not dependent on interfaces. Then we have For that reason, I assumed it could break our design consistency if I import interfaces and declare If this is something which you do not agree upon, I am happy to accept your changes. |
thanks for your responses @smol-ninja
this , and there is one more thing if we keep the check in the constructor, we won't need to make the same check in every After rethinking about this, I consider now that it would be better to have a struct that cointains only the parameters passed in the abstract contract: library MerkleStreamer {
struct ConstructorParams {
address initialAdmin;
string name;
IERC20 asset;
bytes32 merkleRoot;
uint40 expiration;
bool cancelable;
bool transferable;
}
} So that it can be used in all future contracts that inherit function createMerkleStreamerLL(
MerkleStreamer.ConstructorParams memory params,
ISablierV2LockupLinear lockupLinear,
LockupLinear.Durations streamDurations,
string ipfsCID,
uint256 aggregateAmount,
uint256 recipientsCount
)
external
returns (ISablierV2MerkleStreamerLL merkleStreamerLL); wdyt, do you like this proposal? @PaulRBerg tagging you again because Shub has asked:
|
Great idea @andreivladbrg. I prefer this approach too. This way, we won't have to deal with separate structs for future streamer contracts. I think it should work because it would nonetheless reduce the no. of stack variables for the factory create function. I would also like to know your comment on my 2nd point: "not having Whatever decision @PaulRBerg takes on discarding this feature or not, we should still do this because there might be new variables in the factory create versions of LD and LT that would eventually place us into If you agree, I am happy to make these changes and update the PR. |
well, if we switch to the proposal i've made, we will no longer need the |
a248c8f
to
dae768d
Compare
name
, introduces struct CreateWithLockupLinear
name
, introduces struct ConstructorParams
@andreivladbrg I've updated the PR based on our newest proposal. I have also taken some suggestions from your branch. Let me know what you think. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking good now
might be new variables in the factory create versions of LD and LT
well, what are these new variables? maybe they will even be less, we will remove the LockupLinear.Durations
struct, but we will add MAX_SEGMENT_COUNT
363d600
to
d355029
Compare
09c1b82
to
bf5c3a4
Compare
Yes, you are right. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like your approach to modularize the constructor params in (i) shared params and (ii) bespoke params for each shape (LL, LT, etc.)
However:
- I would prefer the name of the struct parameter to better reflect the fact that the parameters are shared. Maybe we could rename it to
baseParams
,sharedParams
,commonParams
, or something along these lines. Suggestions welcome. - Why are
ipfsCID
,aggregateAmount
, andrecipientsCount
not part of theConstructorParams
struct? They seem to be common to all campaigns, not just the LL campaigns.
vm.expectRevert( | ||
abi.encodeWithSelector( | ||
Errors.SablierV2MerkleStreamerFactory_CampaignNameTooLong.selector, bytes(params.name).length, 32 | ||
) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also write a fuzz test that fuzzes the name
.
Or maybe we can incorporate this fuzzing in the existing testFuzz_CreateMerkleStreamerLL
test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, but why do you want to fuzz name
? We have an integration test for name length and since it is constant, as long as it fits into 32 bytes, there can never be a problem.
because these parameters are not passed in the constructor and the struct passed is called
do you want to add a new library initially considered the same thing as being better, but as i said in my comment here, i no longer find it to be the better option |
Got it. Makes sense. My feedback about the name of the struct parameter still stands, though. Can we rename it to
No. |
well, not sure if it would be better, since this struct is not within a i personally consider the current version to be better @smol-ninja wdyt? |
I agree with @andreivladbrg on renaming |
refactor: use struct `CreateWithLockupLinear` in Merkle streamer constructor
chore: small rewording changes refactor: update import
test: update tests accordingly chore: remove unused imports
dfe645a
to
bbf6366
Compare
@PaulRBerg do you have any suggestions on this? Andrei has already approved the changes. |
I don't think you have understood what I meant. I wanted to rename the name of the struct parameter, not of the struct itself. I.e. here:
Rename |
I agree with that @PaulRBerg. So I've decided to use |
shouldn't why does it need to be named "base" in the abstract contract as well? |
8eca7f4
to
712c24c
Compare
Yes! You're right @andreivladbrg. That was a mistake. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM now
Though the build fails in CI |
That's because we updated package.json in #264 without updating bun lockfile. I've now fixed it. "@sablier/v2-core": "github:sablier-labs/v2-core#staging" |
* feat: add `name` string parameter in MerkleStreamer contract constructor refactor: use struct `CreateWithLockupLinear` in Merkle streamer constructor * test: name should not exceed 32 bytes * refactor: use an struct for MerkleStreamer constructor parameters * test: rename defaults function * refactor: rename custom error chore: small rewording changes refactor: update import * refactor: add constructor params in event test: update tests accordingly chore: remove unused imports * refactor: use internal for NAME * refactor: rename params to baseParams when referring to ConstructorParams struct * build: update bun lockfile --------- Co-authored-by: andreivladbrg <andreivladbrg@gmail.com> Co-authored-by: Paul Razvan Berg <paul.razvan.berg@gmail.com>
* feat: add `name` string parameter in MerkleStreamer contract constructor refactor: use struct `CreateWithLockupLinear` in Merkle streamer constructor * test: name should not exceed 32 bytes * refactor: use an struct for MerkleStreamer constructor parameters * test: rename defaults function * refactor: rename custom error chore: small rewording changes refactor: update import * refactor: add constructor params in event test: update tests accordingly chore: remove unused imports * refactor: use internal for NAME * refactor: rename params to baseParams when referring to ConstructorParams struct * build: update bun lockfile --------- Co-authored-by: andreivladbrg <andreivladbrg@gmail.com> Co-authored-by: Paul Razvan Berg <paul.razvan.berg@gmail.com>
closes #233
Adding
name
throwsstack too deep
error because of the large number of variables in functioncreateMerkleStreamerLL
. In order to fix that, this PR introduces a new structConstructorParams
forSablierV2MerkleStreamer
constructor parameters.Summary
Source
ConstructorParams
to encapsulateSablierV2MerkleStreamer
constructor parameters.name
parameter of type string.NAME
of typebytes32
to store campaign name.bytes32
is preferred overstring
to optimize for gas.name()
to retrieves the campaign name asstring
.Events
CreateMerkleStreamerLL
.Errors
SablierV2MerkleStreamer_CampaignNameTooLong
.Tests
baseParams
to retrieve default value ofConstructorParams
struct.test_RevertWhen_CampaignNameTooLong
to check forname
lengthcreateMerkleStreamerLL.tree