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

dynamic trait updates #4

Merged
merged 5 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions EIPS/eip-7496.md
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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`):
ryanio marked this conversation as resolved.
Show resolved Hide resolved

- `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:

Expand All @@ -90,7 +90,7 @@ Here is an example of the specified schema:
"bits": 16,
"decimals": 0
},
"consumptionValidationOnSale": "requireUintGte"
"validateOnSale": "requireUintGte"
},
"name": {
"displayName": "Name",
Expand Down Expand Up @@ -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

Expand All @@ -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`.

Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion assets/eip-7496/DynamicTraitsSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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`."
},
Expand Down