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
EIP5008: ERC-721 Nonce Extension #5008
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
5667640
EIP: ERC-721 Nonce Extension
a6fde1c
add test code
10ded93
update test code
ebe2b6f
typo fix
26b1365
update file name
5b3d11c
update Motivation
30be53e
update by SamWilsn's suggestion
98d18d2
update code
0xanders File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
--- | ||
eip: 5008 | ||
title: ERC-721 Nonce Extension | ||
description: Add a `nonce` function to ERC-721. | ||
author: Anders (@0xanders), Lance (@LanceSnow), Shrug <shrug@emojidao.org> | ||
discussions-to: https://ethereum-magicians.org/t/eip5008-erc-721-nonce-and-metadata-update-extension/8925 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2022-04-10 | ||
requires: 165, 721 | ||
--- | ||
|
||
## Abstract | ||
|
||
This standard is an extension of [ERC-721](./eip-721.md). It proposes adding a `nonce` function to ERC-721 tokens. | ||
|
||
## Motivation | ||
|
||
Some orders of NFT marketplaces have been attacked and the NFTs sold at a lower price than the current market floor price. This can happen when users transfer an NFT to another wallet and, later, back to the original wallet. This reactivates the order, which may list the token at a much lower price than the owner would have intended. | ||
|
||
This EIP proposes adding a `nonce` property to ERC-721 tokens, and the `nonce` will be changed when a token is transferred. If a `nonce` is added to an order, the order can be checked to avoid attacks. | ||
|
||
## Specification | ||
|
||
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. | ||
|
||
```solidity | ||
interface IERC5008 is IERC165 { | ||
/// @notice Get the nonce of an NFT | ||
/// Throws if `tokenId` is not a valid NFT | ||
/// @param tokenId The id of the NFT | ||
/// @return The nonce of the NFT | ||
function nonce(uint256 tokenId) external view returns(uint256); | ||
} | ||
``` | ||
The `nonce(uint256 tokenId)` function MUST be implemented as `view`. | ||
|
||
The `supportsInterface` method MUST return `true` when called with `0xce03fdab`. | ||
|
||
## Rationale | ||
|
||
At first `transferCount` was considered as function name, but there may some case to change the `nonce` besides transfer, such as important properties changed, then we changed `transferCount` to `nonce`. | ||
|
||
|
||
## Backwards Compatibility | ||
|
||
This standard is compatible with ERC-721 standards. | ||
|
||
## Test Cases | ||
|
||
### Test Contract | ||
|
||
```solidity | ||
pragma solidity 0.8.10; | ||
import "./ERC5008.sol"; | ||
|
||
contract ERC5008Demo is ERC5008{ | ||
mapping(uint256 => uint256) private _tokenData; | ||
|
||
constructor(string memory name_, string memory symbol_)ERC5008(name_, symbol_){ | ||
} | ||
|
||
/// @notice mint a new NFT | ||
/// @param to The owner of the new token | ||
/// @param tokenId The id of the new token | ||
function mint(address to, uint256 tokenId) public { | ||
_mint(to, id); | ||
} | ||
|
||
} | ||
|
||
``` | ||
### Test Code | ||
|
||
run in terminal: `npm hardhat test` | ||
|
||
```TypeScript | ||
import { expect } from "chai"; | ||
import { ethers } from "hardhat"; | ||
|
||
describe("Test ERC5008 ", function () { | ||
|
||
let [alice, bob] = await ethers.getSigners(); | ||
|
||
const ERC5008Demo = await ethers.getContractFactory("ERC5008Demo"); | ||
|
||
let contract = await ERC5008Demo.deploy(); | ||
|
||
let tokenId = 1; | ||
await contract.mint(alice.address, tokenId); | ||
|
||
expect(await contract.nonce(tokenId)).equals(1); | ||
|
||
await contract.transferFrom(alice.address, bob.address, tokenId); | ||
|
||
expect(await contract.nonce(tokenId)).equals(2); | ||
|
||
}); | ||
``` | ||
|
||
## Reference Implementation | ||
|
||
```solidity | ||
// SPDX-License-Identifier: CC0 | ||
pragma solidity ^0.8.0; | ||
|
||
import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; | ||
import "./IERC5008.sol"; | ||
|
||
contract ERC5008 is ERC721, IERC5008 { | ||
mapping(uint256 => uint256) private _tokenNonce; | ||
|
||
constructor(string memory name_, string memory symbol_)ERC721(name_, symbol_){ | ||
} | ||
|
||
/// @notice Get the nonce of an NFT | ||
/// Throws if `tokenId` is not a valid NFT | ||
/// @param tokenId The NFT to get the nonce for | ||
/// @return The nonce of this NFT | ||
function nonce(uint256 tokenId) public virtual override view returns(uint256) { | ||
require(_exists(tokenId), "Error: query for nonexistent token"); | ||
|
||
return _tokenNonce[tokenId]; | ||
} | ||
|
||
function _beforeTokenTransfer( | ||
address from, | ||
address to, | ||
uint256 tokenId | ||
) internal virtual override{ | ||
super._beforeTokenTransfer(from, to, tokenId); | ||
_tokenNonce[tokenId]++; | ||
} | ||
|
||
/// @dev See {IERC165-supportsInterface}. | ||
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { | ||
return interfaceId == type(IERC5008).interfaceId || super.supportsInterface(interfaceId); | ||
} | ||
} | ||
``` | ||
|
||
## Security Considerations | ||
No security issues found. | ||
|
||
## Copyright | ||
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
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.
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.
You probably want to specify the EIP-165 identifier, and that implementers of this EIP must handle
supportsInterface
.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.
Updated.
The
supportsInterface
method MUST returntrue
when called with0xce03fdab
.