Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ERC721 standard in both Linear and Pro contracts #131

Merged
merged 10 commits into from
Oct 24, 2022

Conversation

andreivladbrg
Copy link
Member

@andreivladbrg andreivladbrg commented Aug 15, 2022

  • Install Solmate library
  • Inherit ERC721 in both contracts
  • Mint NFT in the create function in both contracts
  • Remove the recipient address from the Stream struct in both contracts
  • Add isApprovedOrOwner function that returns a bool value wether the caller is the owner of the stream or is approved
  • Change the onlySenderOrRecipient modifier to isAuthorizedForStream that calls isApprovedOrOwner function
  • Test the case when the caller is an approved third party in the cancel cancelAll withdraw withdrawAll withdrawAllTo withdrawTo functions
  • Test the case when the recipient is no longer the owner of the stream in the cancel cancelAll withdraw withdrawAll withdrawAllTo withdrawTo functions

@andreivladbrg
Copy link
Member Author

Is worth mentioning that the changes will increase the gas cost for the create function.

Before: https://imgur.com/a/reBfXXR
After: https://imgur.com/a/fooGyFr

remappings.txt Outdated Show resolved Hide resolved
src/SablierV2Linear.sol Outdated Show resolved Hide resolved
src/SablierV2Pro.sol Outdated Show resolved Hide resolved
src/SablierV2.sol Outdated Show resolved Hide resolved
src/SablierV2.sol Outdated Show resolved Hide resolved
src/SablierV2Pro.sol Outdated Show resolved Hide resolved
src/SablierV2Linear.sol Outdated Show resolved Hide resolved
src/SablierV2Linear.sol Outdated Show resolved Hide resolved
src/SablierV2Pro.sol Outdated Show resolved Hide resolved
src/SablierV2.sol Outdated Show resolved Hide resolved
@PaulRBerg
Copy link
Member

PaulRBerg commented Oct 22, 2022

Great work! I have left multiple specific bits of feedback to your code above.

Separately, this is my general feedback:

Common Inheritance

You should have inherited from IERC721 in the interface ISablierV2. This is due to two reasons:

  1. All SablierV2 contracts are expected to be NFTs.
  2. This is the practice that we've been following so far, to aggregate all common interfaces in ISablierV2.

Unfortunately, it doesn't look like Solmate offers any interface for ERC-721. To achieve this, I had to switch over to OpenZeppelin.

Recipient

I agree that it would be useful to keep the getRecipient function and keep referring to the recipient of the stream as a recipient in the code as well, not just in speach and marketing materials. However, I have opened a discussion about this, in case we change our minds later: #141

src/SablierV2Linear.sol Outdated Show resolved Hide resolved
src/SablierV2Pro.sol Outdated Show resolved Hide resolved
@PaulRBerg PaulRBerg force-pushed the andrei/feat-erc-721 branch from 7e9cec0 to 835ff40 Compare October 23, 2022 17:42
@PaulRBerg
Copy link
Member

PaulRBerg commented Oct 23, 2022

I have just went through all tests and they generally looked good to me, but there several wordings that needed improvements, which I did in my latest commit.

There are two things left to do in this PR:

  • Burn the NFT in the cancel function
  • Decide on whether we should keep using OpenZeppelin's isApprovedOrOwner implementation, or switch to our own.

@PaulRBerg
Copy link
Member

As discussed privately, we can keep using OZ's _isApprovedOrOwner function for the time being, and decide whether it would be worth it switch to our own implementation later on (to avoid checking for the owner).

What we certainly don't want is to keep isApprovedOrOwner in the ISablierV2. The ISablierV2 interface should be concerned with user-facing functions exclusively.

src/SablierV2.sol Outdated Show resolved Hide resolved
@andreivladbrg
Copy link
Member Author

andreivladbrg commented Oct 24, 2022

Given that usually the functions which return a boolean use the "is" prefix. I suggest we rename the modifier from isAuthorizedForStream to authorizedForStream.

@PaulRBerg
Copy link
Member

@andreivladbrg let's discuss that separately outside of this PR. For now I would like to keep isAuthorizedForStream.

Why did you use safeMint instead of mint?

@andreivladbrg
Copy link
Member Author

andreivladbrg commented Oct 24, 2022

@andreivladbrg let's discuss that separately outside of this PR. For now I would like to keep isAuthorizedForStream.

Ok.

Why did you use safeMint instead of mint?

I followed the openzeppelin recommendation.

Just noticed that gas cost increased by 711 using _safeMint. Should we switch to _mint again?

andreivladbrg and others added 10 commits October 24, 2022 16:43
feat: inherit "ERC721" in "SablierV2Linear"
feat: inherit "ERC721" in "SablierV2Pro"
feat: mint NFT in the "_create" function
feat: add "isApprovedOrOwner" function
feat: change the modifier to "isAuthorizedForStream"
feat: add "tokenURI" function
perf: remove the recipient address from the "Stream" struct
refactor: swap the order of the checks in the "withdrawTo" function
test: change the struct recipient with the "users.recipient"
test: make recipient the default caller in the "cancel" function
test: order correctly the branches in the "cancel" tree
test: order correctly the branches in the "cancelAll" tree
test: order correctly the branches in the "withdraw" tree
test: when the caller is an approved third party in the "cancel" function
test: when the caller is an approved third party in the "cancelAll" funtion
test: when the caller is an approved third party in the "withdraw" function
test: when the caller is an approved third party in the "withdrawAll" function
test: when the caller is an approved third party in the "withdrawAllTo" function
test: when the caller is an approved third party in the "withdtawTo" function
test: when the recipient is no longer the owner of the stream in the "cancel" function
test: when the recipient is no longer the owner of the stream in the "withdraw" function
test: when the recipient is no longer the owner of the streams in the "cancelAll" function
test: when the recipient is no longer the owner of the streams in the "withdrawAll" function
test: when the recipient is no longer the owner of the streams in the "withdrawAllTo" function
test: when the recipient is no longer the owner of the stream in the "withrawTo" function
test: remove the local "withdrawAmount" variable from the test functions
test: change the new owner of the streams to "eve" when using "safeTransferFrom" function
test: "isApprovedOrOwner" function in the "SablierV2Linear" contract
test: "isApprovedOrOwner" function in the "SablierV2Pro" contract
test: correct comment about return value for the "isCancelable" function
build: remove "solmate"
build: install "openzeppelin-contracts" lib
build: upgrade to latest "prb-math" lib
chore: add ".solhintignore" file
chore: improve wording in comments
docs: improve wording in NatSpec
refactor: change the ERC-721 name
refactor: name return args in "isApprovedOrOwner" and "tokenURI"
refactor: refer to "to" as "recipient"
refactor: use OpenZeppelin's ERC721 implementation
refactor: use "_isApprovedOrOwner" from OpenZeppelin
test: add dummy function implementations in "AbstractSablierV2"
test: delete "isApprovedOrOwner" tests
build: upgrade to "release-v4.8" of "openzeppelin-contracts"
test: add new "operator" user
test: add new testing branches for un/authorized
test: delete superfluous warps in "withdraw" tests
test: move assertions for recipients at the bottom
test: refer to approved "third-party" as "operator"
test: rename "withdrawAmountZero" to "withdrawAmount"
test: refactor "CallerRecipient" to "OriginalRecipient"
test: use the new operator user in the "approved operator" tests
chore: add visibility keyword in function separators
refactor: inherit from ERC721 last
test: simplify AbstractSablierV2 contract
chore: remove unnecessary imports
test: update tests to check for burned NFT
@andreivladbrg andreivladbrg merged commit 31575ad into main Oct 24, 2022
@andreivladbrg andreivladbrg deleted the andrei/feat-erc-721 branch October 24, 2022 13:54
andreivladbrg added a commit that referenced this pull request Oct 24, 2022
* feat: ERC721

build: install "openzeppelin-contracts" lib
feat: inherit "ERC721" in "SablierV2Linear"
feat: inherit "ERC721" in "SablierV2Pro"
feat: mint NFT in the "_create" function
feat: add "isApprovedOrOwner" function
feat: change the modifier to "isAuthorizedForStream"
feat: add "tokenURI" function
perf: remove the recipient address from the "Stream" struct
refactor: swap the order of the checks in the "withdrawTo" function
test: change the struct recipient with the "users.recipient"
test: make recipient the default caller in the "cancel" function
test: order correctly the branches in the "cancel" tree
test: order correctly the branches in the "cancelAll" tree
test: order correctly the branches in the "withdraw" tree
test: when the caller is an approved third party in the "cancel" function
test: when the caller is an approved third party in the "cancelAll" funtion
test: when the caller is an approved third party in the "withdraw" function
test: when the caller is an approved third party in the "withdrawAll" function
test: when the caller is an approved third party in the "withdrawAllTo" function
test: when the caller is an approved third party in the "withdtawTo" function
test: when the recipient is no longer the owner of the stream in the "cancel" function
test: when the recipient is no longer the owner of the stream in the "withdraw" function
test: when the recipient is no longer the owner of the streams in the "cancelAll" function
test: when the recipient is no longer the owner of the streams in the "withdrawAll" function
test: when the recipient is no longer the owner of the streams in the "withdrawAllTo" function
test: when the recipient is no longer the owner of the stream in the "withrawTo" function
test: remove the local "withdrawAmount" variable from the test functions
test: change the new owner of the streams to "eve" when using "safeTransferFrom" function
test: "isApprovedOrOwner" function in the "SablierV2Linear" contract
test: "isApprovedOrOwner" function in the "SablierV2Pro" contract
test: correct comment about return value for the "isCancelable" function

* refactor: inherit from "IERC721" in "ISablierV2"

build: upgrade to latest "prb-math" lib
chore: add ".solhintignore" file
chore: improve wording in comments
docs: improve wording in NatSpec
refactor: change the ERC-721 name
refactor: name return args in "isApprovedOrOwner" and "tokenURI"
refactor: refer to "to" as "recipient"
refactor: use OpenZeppelin's ERC721 implementation
refactor: use "_isApprovedOrOwner" from OpenZeppelin
test: add dummy function implementations in "AbstractSablierV2"
test: delete "isApprovedOrOwner" tests

* fix: use "_ownerOf" ERC721 function

build: upgrade to "release-v4.8" of "openzeppelin-contracts"

* test: improve wording in testing trees

test: add new "operator" user
test: add new testing branches for un/authorized
test: delete superfluous warps in "withdraw" tests
test: move assertions for recipients at the bottom
test: refer to approved "third-party" as "operator"
test: rename "withdrawAmountZero" to "withdrawAmount"
test: refactor "CallerRecipient" to "OriginalRecipient"
test: use the new operator user in the "approved operator" tests

* refactor: isApprovedOrOwner

chore: add visibility keyword in function separators
refactor: inherit from ERC721 last
test: simplify AbstractSablierV2 contract

* chore: remove unnecessary imports

* style: order imports

chore: remove unnecessary imports

* refactor: burn NFT when stream is ended

test: update tests to check for burned NFT

* refactor: use "safeMint" in the "create" function

* test: correct explanatory comment

Co-authored-by: Paul Razvan Berg <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants