diff --git a/EIPS/eip-7496.md b/EIPS/eip-7496.md index 606887e11f003..ff8f863395048 100644 --- a/EIPS/eip-7496.md +++ b/EIPS/eip-7496.md @@ -25,15 +25,13 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S Contracts implementing this EIP MUST include the events, getters, and setters as defined below, and MUST return `true` for [ERC-165](./eip-165.md) `supportsInterface` for `0x12345678(placeholder, to be set when finalized)`, the 4 byte `interfaceId` for this ERC. -If the contract does not wish for others to modify their metadata, the setters MAY revert when called. - ```solidity interface IERC7496 { /* Events */ event TraitUpdated(bytes32 indexed traitKey, uint256 indexed tokenId, bytes32 value); event TraitUpdatedBulkRange(bytes32 indexed traitKey, uint256 fromTokenId, uint256 toTokenId); event TraitUpdatedBulkList(bytes32 indexed traitKey, uint256[] tokenIds); - event TraitMetadataURIUpdated(string uri); + event TraitMetadataURIUpdated(); /* Getters */ function getTraitValue(bytes32 traitKey, uint256 tokenId) external view returns (bytes32); @@ -63,12 +61,14 @@ The keys in the `traits` object MUST be unique trait names. If the trait name is The `displayName` values MUST be unique and MUST NOT collide with the `displayName` of any other traits defined in the metadata. -The `consumptionValidationOnSale` value provides a signal to marketplaces on how to validate the trait value when a token is being sold. If the validation criteria is not met, the sale SHOULD not be permitted by the marketplace contract. If specified, the value of `consumptionValidationOnSale` MUST be one of the following (or it is assumed to be `none`): +The `validateOnSale` value provides a signal to marketplaces on how to validate the trait value when a token is being sold. If the validation criteria is not met, the sale MUST not be permitted by the marketplace contract. If specified, the value of `validateOnSale` MUST be one of the following (or it is assumed to be `none`): - `none`: No validation is necessary. -- `requireEq`: The `bytes32` `traitValue` SHOULD be equal to the value at the time the offer to purchase was made. -- `requireUintGte`: The `bytes32` `traitValue` SHOULD be greater than or equal to the value at the time the offer to purchase was made. This comparison is made using the `uint256` representation of the `bytes32` value. -- `requireUintLte`: The `bytes32` `traitValue` SHOULD be less than or equal to the value at the time the offer to purchase was made. This comparison is made using the `uint256` representation of the `bytes32` value. +- `requireEq`: The `bytes32` `traitValue` MUST be equal to the value at the time the offer to purchase was made. +- `requireUintGte`: The `bytes32` `traitValue` MUST be greater than or equal to the value at the time the offer to purchase was made. This comparison is made using the `uint256` representation of the `bytes32` value. +- `requireUintLte`: The `bytes32` `traitValue` MUST be less than or equal to the value at the time the offer to purchase was made. This comparison is made using the `uint256` representation of the `bytes32` value. + +Note that even though this specification requires marketplaces to validate the required trait values, buyers and sellers cannot fully rely on marketplaces to do this and must also take their own precautions to research the current trait values prior to initiating the transaction. Here is an example of the specified schema: @@ -90,7 +90,7 @@ Here is an example of the specified schema: "bits": 16, "decimals": 0 }, - "consumptionValidationOnSale": "requireUintGte" + "validateOnSale": "requireUintGte" }, "name": { "displayName": "Name", @@ -151,7 +151,9 @@ The `dataType` object MAY have a `valueMappings` object defined. If the `valueMa The `boolean` metadata type allows for a boolean value to be set for a trait. -The `dataType` object MAY have a `valueMappings` object defined. If the `valueMappings` object is defined, the `valueMappings` object MUST be a mapping of `bytes32` values to `boolean` or unset `null` values. The `bytes32` values SHOULD be the `keccak256` hash of the `boolean` value. The `boolean` values MUST be unique. +The `dataType` object MAY have a `valueMappings` object defined. If the `valueMappings` object is defined, the `valueMappings` object MUST be a mapping of `bytes32` values to `boolean` or unset `null` values. The `boolean` values MUST be unique. + +If `valueMappings` is not used, the default trait values for `boolean` should be `bytes32(0)` for `false` and `bytes32(uint256(1))` (`0x0000000000000000000000000000000000000000000000000000000000000001`) for `true`. #### `epochSeconds` Metadata Type @@ -161,13 +163,15 @@ The `dataType` object MAY have a `valueMappings` object defined. If the `valueMa ### Events -Updating traits MUST either emit the `TraitUpdated`, `TraitUpdatedBulkRange` or `TraitUpdatedBulkList` event. For the event `TraitUpdatedBulkRange`, the `fromTokenId` and `toTokenId` MUST be a consecutive range of tokens IDs and MUST be treated as an inclusive range. For the event `TraitUpdatedBulkList`, the `tokenIds` MAY be in any order. Updating the trait labels URI or the contents within the URI MUST emit the event `TraitMetadataURIUpdated` so offchain indexers can be notified to parse the changes. +Updating traits MUST either emit the `TraitUpdated`, `TraitUpdatedBulkRange` or `TraitUpdatedBulkList` event. For the event `TraitUpdatedBulkRange`, the `fromTokenId` and `toTokenId` MUST be a consecutive range of tokens IDs and MUST be treated as an inclusive range. For the event `TraitUpdatedBulkList`, the `tokenIds` MAY be in any order. + +Updating the trait metadata URI MUST emit the event `TraitMetadataURIUpdated` so offchain indexers can be notified to query the contract for the latest changes via `getTraitMetadataURI()`. ### `setTrait` -If a trait defines `tokenOwnerCanUpdateValue` as `true`, then the trait value SHOULD be updatable by the token owner by calling `setTrait`. +If a trait defines `tokenOwnerCanUpdateValue` as `true`, then the trait value MUST be updatable by the token owner by calling `setTrait`. -If the value the token owner is attempting to set is not valid, the transaction SHOULD revert. If the value is valid, the trait value SHOULD be updated and the `TraitUpdated` event SHOULD be emitted. +If the value the token owner is attempting to set is not valid, the transaction MUST revert. If the value is valid, the trait value MUST be updated and one of the `TraitUpdated` events MUST be emitted. If the trait has a `valueMappings` entry defined for the desired value being set, `setTrait` MUST be called with the corresponding `traitValue`. @@ -191,7 +195,7 @@ Authors have included reference implementations of the specification in the asse The set\* methods exposed externally MUST be permissioned so they are not callable by everyone but only by select roles or addresses. -Marketplaces SHOULD NOT trust offchain state of traits as they can be frontrunned. Marketplaces SHOULD check the current state of onchain traits at the time of transfer. Marketplaces MAY check certain traits that change the value of the NFT (e.g. redemption status) or they MAY hash all the trait values to guarantee the same state at the time of order creation. +Marketplaces SHOULD NOT trust offchain state of traits as they can be frontrunned. Marketplaces SHOULD check the current state of onchain traits at the time of transfer. Marketplaces MAY check certain traits that change the value of the NFT (e.g. redemption status, defined by metadata values with `validateOnSale` property) or they MAY hash all the trait values to guarantee the same state at the time of order creation. ## Copyright diff --git a/assets/eip-7496/DynamicTraitsSchema.json b/assets/eip-7496/DynamicTraitsSchema.json index 17bea2fbd215f..8ea83f3de7cca 100644 --- a/assets/eip-7496/DynamicTraitsSchema.json +++ b/assets/eip-7496/DynamicTraitsSchema.json @@ -13,7 +13,7 @@ "type": ["string"], "description": "The user-facing display name for the trait." }, - "consumptionValidationOnSale": { + "validateOnSale": { "enum": ["none", "requireEq", "requireUintGte", "requireUintLte"], "description": "Whether the trait value should be validated when the token is sold. If this isn't specified, it is assumed to be `none`." },