Skip to content

Commit e782f4e

Browse files
committed
remove fn pointers for constraints in ERC721._update
1 parent 54cb3ca commit e782f4e

File tree

10 files changed

+67
-91
lines changed

10 files changed

+67
-91
lines changed

contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@ contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable
3030

3131
function _update(
3232
address to,
33-
uint256 tokenId,
34-
function(address, address, uint256) view constraints
33+
uint256 tokenId
3534
) internal virtual override(ERC721Consecutive, ERC721Enumerable) returns (address) {
36-
return super._update(to, tokenId, constraints);
35+
return super._update(to, tokenId);
3736
}
3837

3938
// solhint-disable-next-line func-name-mixedcase

contracts/mocks/token/ERC721ConsecutiveMock.sol

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ contract ERC721ConsecutiveMock is ERC721Consecutive, ERC721Pausable, ERC721Votes
4343

4444
function _update(
4545
address to,
46-
uint256 tokenId,
47-
function(address, address, uint256) view constraints
46+
uint256 tokenId
4847
) internal virtual override(ERC721Consecutive, ERC721Pausable, ERC721Votes) returns (address) {
49-
return super._update(to, tokenId, constraints);
48+
return super._update(to, tokenId);
5049
}
5150

5251
// solhint-disable-next-line func-name-mixedcase

contracts/token/ERC721/ERC721.sol

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,16 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
155155
if (to == address(0)) {
156156
revert ERC721InvalidReceiver(address(0));
157157
}
158-
address owner = _update(to, tokenId, _constraintApprovedOrOwner);
159-
if (owner != from) {
160-
revert ERC721IncorrectOwner(from, tokenId, owner);
158+
159+
_checkApproved(from, _msgSender(), tokenId);
160+
address previousOwner = _update(to, tokenId);
161+
162+
if (previousOwner != from) {
163+
if (previousOwner == address(0)) {
164+
revert ERC721NonexistentToken(tokenId);
165+
} else {
166+
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
167+
}
161168
}
162169
}
163170

@@ -223,17 +230,42 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
223230
}
224231

225232
/**
226-
* @dev Returns whether `spender` is allowed to manage `tokenId`.
233+
* @dev Returns whether `spender` is allowed to manage `tokenId` owned by `owner`.
227234
*
228235
* Requirements:
229236
*
230237
* - `tokenId` must exist.
231238
*/
232-
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
233-
address owner = ownerOf(tokenId);
239+
function _isApprovedOrOwner(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
234240
return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
235241
}
236242

243+
/**
244+
* @dev Alternative version of {_isApprovedOrOwner} that will fetch the owner from storage.
245+
* This is not virtual, overrides should be performed on the other version of {_isApprovedOrOwner}
246+
*/
247+
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
248+
return _isApprovedOrOwner(_ownerOf(tokenId), spender, tokenId);
249+
}
250+
251+
/**
252+
* @dev Check that spender is approved or owner, and revert if that is not the case.
253+
*
254+
* NOTE: If the approval is correct, the owner is not checked. If the `owner` parameter is not directly comming
255+
* from a call to `_ownerOf`, it should be checked. {_update} returns the previousOwner, which should match the
256+
* `owner` for this function. See {transferFrom}.
257+
*/
258+
function _checkApproved(address owner, address spender, uint256 tokenId) internal view virtual {
259+
if (!_isApprovedOrOwner(owner, spender, tokenId)) {
260+
address actualOwner = _ownerOf(tokenId);
261+
if (owner == actualOwner) {
262+
revert ERC721InsufficientApproval(spender, tokenId);
263+
} else {
264+
revert ERC721IncorrectOwner(owner, tokenId, actualOwner);
265+
}
266+
}
267+
}
268+
237269
/**
238270
* @dev Safely mints `tokenId` and transfers it to `to`.
239271
*
@@ -270,15 +302,9 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
270302
*
271303
* Emits a {Transfer} event.
272304
*/
273-
function _update(
274-
address to,
275-
uint256 tokenId,
276-
function(address, address, uint256) view constraints
277-
) internal virtual returns (address) {
305+
function _update(address to, uint256 tokenId) internal virtual returns (address previousOwner) {
278306
address from = _ownerOf(tokenId);
279307

280-
constraints(from, to, tokenId);
281-
282308
if (from != address(0)) {
283309
delete _tokenApprovals[tokenId];
284310
unchecked {
@@ -315,7 +341,10 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
315341
if (to == address(0)) {
316342
revert ERC721InvalidReceiver(address(0));
317343
}
318-
_update(to, tokenId, _constraintNotMinted);
344+
address previousOwner = _update(to, tokenId);
345+
if (previousOwner != address(0)) {
346+
revert ERC721InvalidSender(address(0));
347+
}
319348
}
320349

321350
/**
@@ -330,7 +359,10 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
330359
* Emits a {Transfer} event.
331360
*/
332361
function _burn(uint256 tokenId) internal {
333-
_update(address(0), tokenId, _constraintMinted);
362+
address previousOwner = _update(address(0), tokenId);
363+
if (previousOwner == address(0)) {
364+
revert ERC721NonexistentToken(tokenId);
365+
}
334366
}
335367

336368
/**
@@ -348,9 +380,9 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
348380
if (to == address(0)) {
349381
revert ERC721InvalidReceiver(address(0));
350382
}
351-
address owner = _update(to, tokenId, _constraintMinted);
352-
if (owner != from) {
353-
revert ERC721IncorrectOwner(from, tokenId, owner);
383+
address previousOwner = _update(to, tokenId);
384+
if (previousOwner != from) {
385+
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
354386
}
355387
}
356388

@@ -386,34 +418,6 @@ abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Er
386418
}
387419
}
388420

389-
/**
390-
* @dev Constraint: revert if token is already minted
391-
*/
392-
function _constraintNotMinted(address from, address, uint256) internal pure {
393-
if (from != address(0)) {
394-
revert ERC721InvalidSender(address(0));
395-
}
396-
}
397-
398-
/**
399-
* @dev Constraint: revert if token is not yet minted
400-
*/
401-
function _constraintMinted(address from, address, uint256 tokenId) internal pure {
402-
if (from == address(0)) {
403-
revert ERC721NonexistentToken(tokenId);
404-
}
405-
}
406-
407-
/**
408-
* @dev Constraint: check that the caller is the current owner, or approved by the current owner
409-
*/
410-
function _constraintApprovedOrOwner(address owner, address, uint256 tokenId) internal view {
411-
address spender = _msgSender();
412-
if (spender != owner && !isApprovedForAll(owner, spender) && getApproved(tokenId) != spender) {
413-
revert ERC721InsufficientApproval(_msgSender(), tokenId);
414-
}
415-
}
416-
417421
/**
418422
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address.
419423
* The call is not executed if the target address is not a contract.

contracts/token/ERC721/extensions/ERC721Burnable.sol

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ abstract contract ERC721Burnable is Context, ERC721 {
1919
* - The caller must own `tokenId` or be an approved operator.
2020
*/
2121
function burn(uint256 tokenId) public virtual {
22-
if (!_isApprovedOrOwner(_msgSender(), tokenId)) {
23-
revert ERC721InsufficientApproval(_msgSender(), tokenId);
24-
}
22+
_checkApproved(_ownerOf(tokenId), _msgSender(), tokenId);
2523
_burn(tokenId);
2624
}
2725
}

contracts/token/ERC721/extensions/ERC721Consecutive.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,8 @@ abstract contract ERC721Consecutive is IERC2309, ERC721 {
140140
* Warning: Using {ERC721Consecutive} prevents minting during construction in favor of {_mintConsecutive}.
141141
* After construction, {_mintConsecutive} is no longer available and minting through {_update} becomes available.
142142
*/
143-
function _update(
144-
address to,
145-
uint256 tokenId,
146-
function(address, address, uint256) view constraints
147-
) internal virtual override returns (address) {
148-
address from = super._update(to, tokenId, constraints);
143+
function _update(address to, uint256 tokenId) internal virtual override returns (address) {
144+
address from = super._update(to, tokenId);
149145

150146
// only mint after construction
151147
if (from == address(0) && address(this).code.length == 0) {

contracts/token/ERC721/extensions/ERC721Enumerable.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,8 @@ abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
7676
/**
7777
* @dev See {ERC721-_update}.
7878
*/
79-
function _update(
80-
address to,
81-
uint256 tokenId,
82-
function(address, address, uint256) view constraints
83-
) internal virtual override returns (address) {
84-
address from = super._update(to, tokenId, constraints);
79+
function _update(address to, uint256 tokenId) internal virtual override returns (address) {
80+
address from = super._update(to, tokenId);
8581

8682
if (from == address(0)) {
8783
_addTokenToAllTokensEnumeration(tokenId);

contracts/token/ERC721/extensions/ERC721Pausable.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,8 @@ abstract contract ERC721Pausable is ERC721, Pausable {
2727
*
2828
* - the contract must not be paused.
2929
*/
30-
function _update(
31-
address to,
32-
uint256 tokenId,
33-
function(address, address, uint256) view constraints
34-
) internal virtual override returns (address) {
30+
function _update(address to, uint256 tokenId) internal virtual override returns (address) {
3531
_requireNotPaused();
36-
return super._update(to, tokenId, constraints);
32+
return super._update(to, tokenId);
3733
}
3834
}

contracts/token/ERC721/extensions/ERC721Royalty.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,8 @@ abstract contract ERC721Royalty is ERC2981, ERC721 {
3131
/**
3232
* @dev See {ERC721-_update}. This override additionally clears the royalty information for the token.
3333
*/
34-
function _update(
35-
address to,
36-
uint256 tokenId,
37-
function(address, address, uint256) view constraints
38-
) internal virtual override returns (address) {
39-
address from = super._update(to, tokenId, constraints);
34+
function _update(address to, uint256 tokenId) internal virtual override returns (address) {
35+
address from = super._update(to, tokenId);
4036

4137
if (to == address(0)) {
4238
_resetTokenRoyalty(tokenId);

contracts/token/ERC721/extensions/ERC721URIStorage.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,8 @@ abstract contract ERC721URIStorage is IERC4906, ERC721 {
6868
* token-specific URI was set for the token, and if so, it deletes the token URI from
6969
* the storage mapping.
7070
*/
71-
function _update(
72-
address to,
73-
uint256 tokenId,
74-
function(address, address, uint256) view constraints
75-
) internal virtual override returns (address) {
76-
address from = super._update(to, tokenId, constraints);
71+
function _update(address to, uint256 tokenId) internal virtual override returns (address) {
72+
address from = super._update(to, tokenId);
7773

7874
if (to == address(0) && bytes(_tokenURIs[tokenId]).length != 0) {
7975
delete _tokenURIs[tokenId];

contracts/token/ERC721/extensions/ERC721Votes.sol

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,8 @@ abstract contract ERC721Votes is ERC721, Votes {
2222
*
2323
* Emits a {IVotes-DelegateVotesChanged} event.
2424
*/
25-
function _update(
26-
address to,
27-
uint256 tokenId,
28-
function(address, address, uint256) view constraints
29-
) internal virtual override returns (address) {
30-
address from = super._update(to, tokenId, constraints);
25+
function _update(address to, uint256 tokenId) internal virtual override returns (address) {
26+
address from = super._update(to, tokenId);
3127
_transferVotingUnits(from, to, 1);
3228
return from;
3329
}

0 commit comments

Comments
 (0)