Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Codearena-145,147: PermitERC721 EIP-4494 compliance #818
Codearena-145,147: PermitERC721 EIP-4494 compliance #818
Changes from 7 commits
bde850b
ec1f05f
832d145
c00a01f
3401525
6aa0cd4
425fe41
775d774
238c7d0
d88f372
95f75f8
3578be8
3448c07
1b9a6ed
c23bb27
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
Does the license need to be switched from BUSL-1.1 since it uses some logic from a MIT licensed codebase?
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.
No, the MIT license doesn't even require derivative works to be open-sourced. If we have used a "substantial portion" of that implementation, however, we should include a copyright notice in this file. However, the original work by
dievardump
does not include a LICENSE file or copyright notice.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.
just checking if you've considered to include the overloaded
permit
as well, as follow:It doesn't seem to be mentioned in the standard implementation but I guess would be good to have for integrators.
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 think it's a small task for integrators to generate signature at their end, i m in favour of not adding this method in contract as it adds one more step for the permit increasing gas cost as well as increases contract size.
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.
Why these extra steps are introduced instead of using directly
isValidSignatureNow
check fromSignatureChecker.sol
?In this issue I've broken down the recommendation with related issues for consideration:
isValidSignature
directly Fixed-Point-Solutions/prototech-ajna-audit#35There 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.
Primarily to offload as much of the logic as possible to well audited and tested external libraries. I recognize the gas and storage size benefits to just implementing that logic directly, I had just avoided it to minimize the amount of logic that is self-rolled.
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.
another reason we can not use
isValidSignatureNow
is that this check returns just the bool. we want to get the recovered address because the recovered address can wither be owner or the approved account. if we useisValidSignatureNow
permit will fail when the approved account(not the owner) has given the permit. This check here,_isApprovedOrOwner(recoveredAddress_, tokenId_)
@naszam
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 just noticed now that the refactoring is following the implementation linked in the description, I'll check that in depth and adjust the certora specs accordingly (the related issues linked were referring to the previous implementation, so they might need to be adjusted following the linked implementation where the
_isApprovedOrOwner
function seems to be required, thanks for flagging that out).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.
_incrementeNonce
seems to be done inside the overrided_transfer
in the reference linked implementation (see here), in accordance with the standard specifications:Alternatively, usually is before the approval in the erc20 permit.
What is the rationale behind this change?
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.
That was a mistake on my part, no solid rationale in light of @prateek105 proposed exploit. Updated to
_incrementNonce
in an override_transfer
similar to the reference implementation.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.
This seems to diverge with the standard implementation, where the
chainId_
is used in thekeccak256
as follows:where indeed the
chainId_
passed as argument can be used directly instead ofblock.chainid
, but the hash I guess it should be computed each time asblock.chainid
might diverge from deployment, due to forks.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.
As per my understanding of this comment, u mean that we should calculate
keccak256( 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)' )
each time rather than hardcoding it as0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f
But this is hash of a string which is constant across forks, so we can hardcode this instead of calculating it each time.
If u meant something else please let me know.
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.
Oh! Right, got confused with the argument, good to resolve, I was just ensuring
block.chainid
is passed each time the internal function is called.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.
checked the hash via
chisel
, it matches: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.
See related issue:
PermitERC721
Fixed-Point-Solutions/prototech-ajna-audit#36There 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.
yes, right, the zero address check is redundant I can add a commit for this.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.
zero address check is required as
getApproved(tokenId)
can return zero addressThere 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.
@naszam
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.
getApproved(tokenId)
uses the_exists
check, inside_requireMinted
, to ensure thetokenId
exists and checks also to ensure owner is not address zero (in ozv4.8.2
):But I see that for the approved
address
there doesn't seem to be any check and it could return indeed a zero address and considering the refactoring with the extra logic it makes sense now to have an explicit check for zero address due to the extra conditions,isApprovedForAll(owner, spender)
andgetApproved(tokenId) == spender
(the above issue was related to the previous implementation specifically).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 think this does not cover the case where the signature is made by a contract that is not the owner of the tokenId but instead is approved by the owner.
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.
check also this one Fixed-Point-Solutions/prototech-ajna-audit#27
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.
This PR addresses the prototech issue as well
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.
Also, I believe that this specific case is checked on line 1367 of PositionManager.t.sol @prateek105
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 saw the tests and the scenario I mentioned is different from the test, my scenario will fail for contracts but pass for EOA. Scenario is that an EOA account which is approved can give permit to spender address on behalf of owner but the same thing will fail for a contract which is approved trying to give permit to a spender. The same limitation applies to this reference implementation https://github.com/dievardump/erc721-with-permits/blob/main/contracts/ERC721WithPermit.sol as well.
I think that this is the limitation of ERC1271, so I am approving the PR.
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.
See here for related issues:
isValidSignature
doesn't check for well formed signature Fixed-Point-Solutions/prototech-ajna-audit#33isValidSignature
directly Fixed-Point-Solutions/prototech-ajna-audit#35There 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 believe the usage of OpenZeppelin's
SignatureChecker
library should fix the previous issues withisValidSignature
.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.
yes, above issues are fixed now.