From 6b53b56da6c8f7f9020892e826f5402a1399efe0 Mon Sep 17 00:00:00 2001 From: steven2308 Date: Thu, 14 Mar 2024 20:37:29 -0500 Subject: [PATCH] Includes token attributes for signed ints and refactors interface. Interface was refactoring purely for ordering purposes. --- .../extension/tokenAttributes/IERC7508.sol | 1023 ++++++++++------- .../RMRKTokenAttributesRepository.sol | 293 ++++- hardhat.config.ts | 1 + test/extensions/tokenAttributesRepository.ts | 343 +++--- test/interfaces.ts | 2 +- 5 files changed, 1000 insertions(+), 662 deletions(-) diff --git a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol index dc0dcc12..c5afb16d 100644 --- a/contracts/RMRK/extension/tokenAttributes/IERC7508.sol +++ b/contracts/RMRK/extension/tokenAttributes/IERC7508.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.21; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** - * @title IERC7508 + * @title ERC-7508 Public On-Chain NFT Attributes Repository * @author RMRK team - * @notice Interface smart contract of the RMRK token properties extension. + * @notice Interface smart contract of Dynamic On-Chain Token Attributes Repository */ interface IERC7508 is IERC165 { /** @@ -27,53 +27,63 @@ interface IERC7508 is IERC165 { } /** - * @notice Structure used to represent a string attribute. + * @notice Structure used to represent an address attribute. * @return key The key of the attribute * @return value The value of the attribute */ - struct StringAttribute { + struct AddressAttribute { string key; - string value; + address value; } /** - * @notice Structure used to represent an uint attribute. + * @notice Structure used to represent a boolean attribute. * @return key The key of the attribute * @return value The value of the attribute */ - struct UintAttribute { + struct BoolAttribute { string key; - uint256 value; + bool value; } /** - * @notice Structure used to represent a boolean attribute. + * @notice Structure used to represent a bytes attribute. * @return key The key of the attribute * @return value The value of the attribute */ - struct BoolAttribute { + struct BytesAttribute { string key; - bool value; + bytes value; } /** - * @notice Structure used to represent an address attribute. + * @notice Structure used to represent an int attribute. * @return key The key of the attribute * @return value The value of the attribute */ - struct AddressAttribute { + struct IntAttribute { string key; - address value; + int256 value; } /** - * @notice Structure used to represent a bytes attribute. + * @notice Structure used to represent a string attribute. * @return key The key of the attribute * @return value The value of the attribute */ - struct BytesAttribute { + struct StringAttribute { string key; - bytes value; + string value; + } + + /** + * @notice Structure used to represent an uint attribute. + * @return key The key of the attribute + * @return value The value of the attribute + */ + struct UintAttribute { + string key; + uint256 value; } /** @@ -129,75 +139,118 @@ interface IERC7508 is IERC165 { ); /** - * @notice Used to notify listeners that a string attribute has been updated. + * @notice Used to notify listeners that an address attribute has been updated. * @param collection The collection address * @param tokenId The token ID * @param key The key of the attribute * @param value The new value of the attribute */ - event StringAttributeUpdated( + event AddressAttributeUpdated( address indexed collection, uint256 indexed tokenId, string key, - string value + address value ); /** - * @notice Used to notify listeners that an uint attribute has been updated. + * @notice Used to notify listeners that a boolean attribute has been updated. * @param collection The collection address * @param tokenId The token ID * @param key The key of the attribute * @param value The new value of the attribute */ - event UintAttributeUpdated( + event BoolAttributeUpdated( address indexed collection, uint256 indexed tokenId, string key, - uint256 value + bool value ); /** - * @notice Used to notify listeners that a boolean attribute has been updated. + * @notice Used to notify listeners that a bytes attribute has been updated. * @param collection The collection address * @param tokenId The token ID * @param key The key of the attribute * @param value The new value of the attribute */ - event BoolAttributeUpdated( + event BytesAttributeUpdated( address indexed collection, uint256 indexed tokenId, string key, - bool value + bytes value ); /** - * @notice Used to notify listeners that an address attribute has been updated. + * @notice Used to notify listeners that an int attribute has been updated. * @param collection The collection address * @param tokenId The token ID * @param key The key of the attribute * @param value The new value of the attribute */ - event AddressAttributeUpdated( + event IntAttributeUpdated( address indexed collection, uint256 indexed tokenId, string key, - address value + int256 value ); /** - * @notice Used to notify listeners that a bytes attribute has been updated. + * @notice Used to notify listeners that a string attribute has been updated. * @param collection The collection address * @param tokenId The token ID * @param key The key of the attribute * @param value The new value of the attribute */ - event BytesAttributeUpdated( + event StringAttributeUpdated( address indexed collection, uint256 indexed tokenId, string key, - bytes value + string value ); + /** + * @notice Used to notify listeners that an uint attribute has been updated. + * @param collection The collection address + * @param tokenId The token ID + * @param key The key of the attribute + * @param value The new value of the attribute + */ + event UintAttributeUpdated( + address indexed collection, + uint256 indexed tokenId, + string key, + uint256 value + ); + + // ------------------- ACCESS CONTROL ------------------- + + /** + * @notice Used to check if the specified address is listed as a collaborator of the given collection's parameter. + * @param collaborator Address to be checked. + * @param collection Address of the collection. + * @return isCollaborator_ Boolean value indicating if the address is a collaborator of the given collection's (`true`) or not + * (`false`). + */ + function isCollaborator( + address collaborator, + address collection + ) external view returns (bool isCollaborator_); + + /** + * @notice Used to check if the specified address is listed as a specific address of the given collection's + * parameter. + * @param specificAddress Address to be checked. + * @param collection Address of the collection. + * @param key The key of the attribute + * @return isSpecificAddress_ Boolean value indicating if the address is a specific address of the given collection's parameter + * (`true`) or not (`false`). + */ + function isSpecificAddress( + address specificAddress, + address collection, + string memory key + ) external view returns (bool isSpecificAddress_); + /** * @notice Used to register a collection to use the RMRK token attributes repository. * @dev If the collection does not implement the Ownable interface, the `useOwnable` value must be set to `false`. @@ -254,6 +307,8 @@ interface IERC7508 is IERC165 { bool[] memory collaboratorAddressAccess ) external; + // ------------------- METADATA URI ------------------- + /** * @notice Used to retrieve the attributes metadata URI for a collection, which contains all the information about the collection attributes. * @param collection Address of the collection @@ -274,622 +329,702 @@ interface IERC7508 is IERC165 { string memory attributesMetadataURI ) external; + // ------------------- GETTERS ------------------- + /** - * @notice Used to set a number attribute. - * @dev Emits a {UintAttributeUpdated} event. - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the address type token attributes. + * @param collection The collection address * @param tokenId The token ID - * @param key The attribute key - * @param value The attribute value + * @param key The key of the attribute + * @return attribute The value of the address attribute */ - function setUintAttribute( + function getAddressAttribute( address collection, uint256 tokenId, - string memory key, - uint256 value - ) external; + string memory key + ) external view returns (address attribute); /** - * @notice Used to set a string attribute. - * @dev Emits a {StringAttributeUpdated} event. - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the bool type token attributes. + * @param collection The collection address * @param tokenId The token ID - * @param key The attribute key - * @param value The attribute value + * @param key The key of the attribute + * @return attribute The value of the bool attribute */ - function setStringAttribute( + function getBoolAttribute( address collection, uint256 tokenId, - string memory key, - string memory value - ) external; + string memory key + ) external view returns (bool attribute); /** - * @notice Used to set a boolean attribute. - * @dev Emits a {BoolAttributeUpdated} event. - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the bytes type token attributes. + * @param collection The collection address * @param tokenId The token ID - * @param key The attribute key - * @param value The attribute value + * @param key The key of the attribute + * @return attribute The value of the bytes attribute */ - function setBoolAttribute( + function getBytesAttribute( address collection, uint256 tokenId, - string memory key, - bool value - ) external; + string memory key + ) external view returns (bytes memory attribute); /** - * @notice Used to set an bytes attribute. - * @dev Emits a {BytesAttributeUpdated} event. - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the uint type token attributes. + * @param collection The collection address * @param tokenId The token ID - * @param key The attribute key - * @param value The attribute value + * @param key The key of the attribute + * @return attribute The value of the uint attribute */ - function setBytesAttribute( + function getUintAttribute( address collection, uint256 tokenId, - string memory key, - bytes memory value - ) external; + string memory key + ) external view returns (uint256 attribute); + /** + * @notice Used to retrieve the string type token attributes. + * @param collection The collection address + * @param tokenId The token ID + * @param key The key of the attribute + * @return attribute The value of the string attribute + */ + function getStringAttribute( + address collection, + uint256 tokenId, + string memory key + ) external view returns (string memory attribute); /** - * @notice Used to set an address attribute. - * @dev Emits a {AddressAttributeUpdated} event. - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the int type token attributes. + * @param collection The collection address * @param tokenId The token ID - * @param key The attribute key - * @param value The attribute value + * @param key The key of the attribute + * @return attribute The value of the uint attribute */ - function setAddressAttribute( + function getIntAttribute( address collection, uint256 tokenId, - string memory key, - address value - ) external; + string memory key + ) external view returns (int256 attribute); + + // ------------------- BATCH GETTERS ------------------- /** - * @notice Sets multiple string attributes for a token at once. - * @dev The `StringAttribute` struct contains the following fields: + * @notice Used to get multiple address parameter values for a token. + * @dev The `AddressAttribute` struct contains the following fields: * [ - * string key, - * string value + * string key, + * address value * ] - * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributes An array of `StringAttribute` structs to be assigned to the given token + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of address keys to retrieve + * @return attributes An array of addresses, in the same order as the attribute keys */ - function setStringAttributes( + function getAddressAttributes( address[] memory collections, uint256[] memory tokenIds, - StringAttribute[] memory attributes - ) external; + string[] memory attributeKeys + ) external view returns (address[] memory attributes); /** - * @notice Sets multiple uint attributes for a token at once. - * @dev The `UintAttribute` struct contains the following fields: + * @notice Used to get multiple bool parameter values for a token. + * @dev The `BoolAttribute` struct contains the following fields: * [ - * string key, - * uint value + * string key, + * bool value * ] - * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributes An array of `UintAttribute` structs to be assigned to the given token + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of bool keys to retrieve + * @return attributes An array of bools, in the same order as the attribute keys */ - function setUintAttributes( + function getBoolAttributes( address[] memory collections, uint256[] memory tokenIds, - UintAttribute[] memory attributes - ) external; + string[] memory attributeKeys + ) external view returns (bool[] memory attributes); /** - * @notice Sets multiple bool attributes for a token at once. - * @dev The `BoolAttribute` struct contains the following fields: + * @notice Used to get multiple bytes parameter values for a token. + * @dev The `BytesAttribute` struct contains the following fields: * [ - * string key, - * bool value + * string key, + * bytes value * ] - * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributes An array of `BoolAttribute` structs to be assigned to the given token + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of bytes keys to retrieve + * @return attributes An array of bytes, in the same order as the attribute keys */ - function setBoolAttributes( + function getBytesAttributes( address[] memory collections, uint256[] memory tokenIds, - BoolAttribute[] memory attributes - ) external; + string[] memory attributeKeys + ) external view returns (bytes[] memory attributes); /** - * @notice Sets multiple address attributes for a token at once. - * @dev The `AddressAttribute` struct contains the following fields: - * [ - * string key, - * address value - * ] - * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributes An array of `AddressAttribute` structs to be assigned to the given token + * @notice Used to get multiple int parameter values for a token. + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of int keys to retrieve + * @return attributes An array of ints, in the same order as the attribute keys */ - function setAddressAttributes( + function getIntAttributes( address[] memory collections, uint256[] memory tokenIds, - AddressAttribute[] memory attributes - ) external; + string[] memory attributeKeys + ) external view returns (int256[] memory attributes); /** - * @notice Sets multiple bytes attributes for a token at once. - * @dev The `BytesAttribute` struct contains the following fields: - * [ - * string key, - * bytes value - * ] - * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributes An array of `BytesAttribute` structs to be assigned to the given token + * @notice Used to get multiple sting parameter values for a token. + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of string keys to retrieve + * @return attributes An array of strings, in the same order as the attribute keys */ - function setBytesAttributes( + function getStringAttributes( address[] memory collections, uint256[] memory tokenIds, - BytesAttribute[] memory attributes - ) external; + string[] memory attributeKeys + ) external view returns (string[] memory attributes); /** - * @notice Sets multiple attributes of multiple types for a token at the same time. - * @dev Emits a separate event for each attribute set. - * @dev The `StringAttribute`, `UintAttribute`, `BoolAttribute`, `AddressAttribute` and `BytesAttribute` structs consists + * @notice Used to get multiple uint parameter values for a token. + * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributeKeys An array of uint keys to retrieve + * @return attributes An array of uints, in the same order as the attribute keys + */ + function getUintAttributes( + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) external view returns (uint256[] memory attributes); + + /** + * @notice Used to retrieve multiple token attributes of any type at once. + * @dev The `StringAttribute`, `UintAttribute`, `IntAttribute`, `BoolAttribute`, `AddressAttribute` and `BytesAttribute` structs consists * to the following fields (where `value` is of the appropriate type): * [ * key, * value, * ] - * @param collection The address of the collection + * @param collection The collection address * @param tokenId The token ID - * @param stringAttributes An array of `StringAttribute` structs containing string attributes to set - * @param uintAttributes An array of `UintAttribute` structs containing uint attributes to set - * @param boolAttributes An array of `BoolAttribute` structs containing bool attributes to set - * @param addressAttributes An array of `AddressAttribute` structs containing address attributes to set - * @param bytesAttributes An array of `BytesAttribute` structs containing bytes attributes to set + * @param addressKeys An array of address type attribute keys to retrieve + * @param boolKeys An array of bool type attribute keys to retrieve + * @param bytesKeys An array of bytes type attribute keys to retrieve + * @param intKeys An array of int type attribute keys to retrieve + * @param stringKeys An array of string type attribute keys to retrieve + * @param uintKeys An array of uint type attribute keys to retrieve + * @return addressAttributes An array of addresses, in the same order as the addressKeys + * @return boolAttributes An array of bools, in the same order as the boolKeys + * @return bytesAttributes An array of bytes, in the same order as the bytesKeys + * @return intAttributes An array of ints, in the same order as the intKeys + * @return stringAttributes An array of strings, in the same order as the stringKeys + * @return uintAttributes An array of uints, in the same order as the uintKeys */ - function setAttributes( + function getAttributes( address collection, uint256 tokenId, - StringAttribute[] memory stringAttributes, - UintAttribute[] memory uintAttributes, - BoolAttribute[] memory boolAttributes, - AddressAttribute[] memory addressAttributes, - BytesAttribute[] memory bytesAttributes - ) external; + string[] memory addressKeys, + string[] memory boolKeys, + string[] memory bytesKeys, + string[] memory intKeys, + string[] memory stringKeys, + string[] memory uintKeys + ) + external + view + returns ( + address[] memory addressAttributes, + bool[] memory boolAttributes, + bytes[] memory bytesAttributes, + int256[] memory intAttributes, + string[] memory stringAttributes, + uint256[] memory uintAttributes + ); + + // ------------------- PREPARE PRESIGNED MESSAGES ------------------- /** - * @notice Used to set the uint attribute on behalf of an authorized account. - * @dev Emits a {UintAttributeUpdated} event. - * @param setter Address of the account that presigned the attribute change - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the message to be signed for submitting a presigned address attribute change. + * @param collection The address of the collection smart contract of the token receiving the attribute * @param tokenId The ID of the token receiving the attribute * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction - * @param v `v` value of an ECDSA signature of the presigned message - * @param r `r` value of an ECDSA signature of the presigned message - * @param s `s` value of an ECDSA signature of the presigned message + * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid + * @return message Raw message to be signed by the authorized account */ - function presignedSetUintAttribute( - address setter, + function prepareMessageToPresignAddressAttribute( address collection, uint256 tokenId, string memory key, - uint256 value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; + address value, + uint256 deadline + ) external view returns (bytes32 message); /** - * @notice Used to set the string attribute on behalf of an authorized account. - * @dev Emits a {StringAttributeUpdated} event. - * @param setter Address of the account that presigned the attribute change - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the message to be signed for submitting a presigned bool attribute change. + * @param collection The address of the collection smart contract of the token receiving the attribute * @param tokenId The ID of the token receiving the attribute * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction - * @param v `v` value of an ECDSA signature of the presigned message - * @param r `r` value of an ECDSA signature of the presigned message - * @param s `s` value of an ECDSA signature of the presigned message + * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid + * @return message Raw message to be signed by the authorized account */ - function presignedSetStringAttribute( - address setter, + function prepareMessageToPresignBoolAttribute( address collection, uint256 tokenId, string memory key, - string memory value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; + bool value, + uint256 deadline + ) external view returns (bytes32 message); /** - * @notice Used to set the bool attribute on behalf of an authorized account. - * @dev Emits a {BoolAttributeUpdated} event. - * @param setter Address of the account that presigned the attribute change - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the message to be signed for submitting a presigned bytes attribute change. + * @param collection The address of the collection smart contract of the token receiving the attribute * @param tokenId The ID of the token receiving the attribute * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction - * @param v `v` value of an ECDSA signature of the presigned message - * @param r `r` value of an ECDSA signature of the presigned message - * @param s `s` value of an ECDSA signature of the presigned message + * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid + * @return message Raw message to be signed by the authorized account */ - function presignedSetBoolAttribute( - address setter, + function prepareMessageToPresignBytesAttribute( address collection, uint256 tokenId, string memory key, - bool value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; + bytes memory value, + uint256 deadline + ) external view returns (bytes32 message); /** - * @notice Used to set the bytes attribute on behalf of an authorized account. - * @dev Emits a {BytesAttributeUpdated} event. - * @param setter Address of the account that presigned the attribute change - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the message to be signed for submitting a presigned int attribute change. + * @param collection The address of the collection smart contract of the token receiving the attribute * @param tokenId The ID of the token receiving the attribute * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction - * @param v `v` value of an ECDSA signature of the presigned message - * @param r `r` value of an ECDSA signature of the presigned message - * @param s `s` value of an ECDSA signature of the presigned message + * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid + * @return message Raw message to be signed by the authorized account */ - function presignedSetBytesAttribute( - address setter, + function prepareMessageToPresignIntAttribute( address collection, uint256 tokenId, string memory key, - bytes memory value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; + int256 value, + uint256 deadline + ) external view returns (bytes32 message); /** - * @notice Used to set the address attribute on behalf of an authorized account. - * @dev Emits a {AddressAttributeUpdated} event. - * @param setter Address of the account that presigned the attribute change - * @param collection Address of the collection receiving the attribute + * @notice Used to retrieve the message to be signed for submitting a presigned string attribute change. + * @param collection The address of the collection smart contract of the token receiving the attribute * @param tokenId The ID of the token receiving the attribute * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction - * @param v `v` value of an ECDSA signature of the presigned message - * @param r `r` value of an ECDSA signature of the presigned message - * @param s `s` value of an ECDSA signature of the presigned message + * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid + * @return message Raw message to be signed by the authorized account */ - function presignedSetAddressAttribute( - address setter, + function prepareMessageToPresignStringAttribute( address collection, uint256 tokenId, string memory key, - address value, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - /** - * @notice Used to check if the specified address is listed as a collaborator of the given collection's parameter. - * @param collaborator Address to be checked. - * @param collection Address of the collection. - * @return isCollaborator_ Boolean value indicating if the address is a collaborator of the given collection's (`true`) or not - * (`false`). - */ - function isCollaborator( - address collaborator, - address collection - ) external view returns (bool isCollaborator_); + string memory value, + uint256 deadline + ) external view returns (bytes32 message); /** - * @notice Used to check if the specified address is listed as a specific address of the given collection's - * parameter. - * @param specificAddress Address to be checked. - * @param collection Address of the collection. - * @param key The key of the attribute - * @return isSpecificAddress_ Boolean value indicating if the address is a specific address of the given collection's parameter - * (`true`) or not (`false`). + * @notice Used to retrieve the message to be signed for submitting a presigned uint attribute change. + * @param collection The address of the collection smart contract of the token receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid + * @return message Raw message to be signed by the authorized account */ - function isSpecificAddress( - address specificAddress, + function prepareMessageToPresignUintAttribute( address collection, - string memory key - ) external view returns (bool isSpecificAddress_); + uint256 tokenId, + string memory key, + uint256 value, + uint256 deadline + ) external view returns (bytes32 message); + + // ------------------- SETTERS ------------------- /** - * @notice Used to retrieve the string type token attributes. - * @param collection The collection address + * @notice Used to set an address attribute. + * @dev Emits a {AddressAttributeUpdated} event. + * @param collection Address of the collection receiving the attribute * @param tokenId The token ID - * @param key The key of the attribute - * @return attribute The value of the string attribute + * @param key The attribute key + * @param value The attribute value */ - function getStringAttribute( + function setAddressAttribute( address collection, uint256 tokenId, - string memory key - ) external view returns (string memory attribute); - - /** - * @notice Used to retrieve the uint type token attributes. - * @param collection The collection address - * @param tokenId The token ID - * @param key The key of the attribute - * @return attribute The value of the uint attribute - */ - function getUintAttribute( - address collection, - uint256 tokenId, - string memory key - ) external view returns (uint256 attribute); - - /** - * @notice Used to retrieve the bool type token attributes. - * @param collection The collection address - * @param tokenId The token ID - * @param key The key of the attribute - * @return attribute The value of the bool attribute - */ - function getBoolAttribute( - address collection, - uint256 tokenId, - string memory key - ) external view returns (bool attribute); - - /** - * @notice Used to retrieve the address type token attributes. - * @param collection The collection address - * @param tokenId The token ID - * @param key The key of the attribute - * @return attribute The value of the address attribute - */ - function getAddressAttribute( - address collection, - uint256 tokenId, - string memory key - ) external view returns (address attribute); + string memory key, + address value + ) external; /** - * @notice Used to retrieve the bytes type token attributes. - * @param collection The collection address + * @notice Used to set a boolean attribute. + * @dev Emits a {BoolAttributeUpdated} event. + * @param collection Address of the collection receiving the attribute * @param tokenId The token ID - * @param key The key of the attribute - * @return attribute The value of the bytes attribute - */ - function getBytesAttribute( - address collection, - uint256 tokenId, - string memory key - ) external view returns (bytes memory attribute); - - /** - * @notice Used to retrieve the message to be signed for submitting a presigned uint attribute change. - * @param collection The address of the collection smart contract of the token receiving the attribute - * @param tokenId The ID of the token receiving the attribute * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid - * @return message Raw message to be signed by the authorized account */ - function prepareMessageToPresignUintAttribute( + function setBoolAttribute( address collection, uint256 tokenId, string memory key, - uint256 value, - uint256 deadline - ) external view returns (bytes32 message); + bool value + ) external; /** - * @notice Used to retrieve the message to be signed for submitting a presigned string attribute change. - * @param collection The address of the collection smart contract of the token receiving the attribute - * @param tokenId The ID of the token receiving the attribute + * @notice Used to set an bytes attribute. + * @dev Emits a {BytesAttributeUpdated} event. + * @param collection Address of the collection receiving the attribute + * @param tokenId The token ID * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid - * @return message Raw message to be signed by the authorized account */ - function prepareMessageToPresignStringAttribute( + function setBytesAttribute( address collection, uint256 tokenId, string memory key, - string memory value, - uint256 deadline - ) external view returns (bytes32 message); + bytes memory value + ) external; /** - * @notice Used to retrieve the message to be signed for submitting a presigned bool attribute change. - * @param collection The address of the collection smart contract of the token receiving the attribute - * @param tokenId The ID of the token receiving the attribute + * @notice Used to set a signed number attribute. + * @dev Emits a {IntAttributeUpdated} event. + * @param collection Address of the collection receiving the attribute + * @param tokenId The token ID * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid - * @return message Raw message to be signed by the authorized account */ - function prepareMessageToPresignBoolAttribute( + function setIntAttribute( address collection, uint256 tokenId, string memory key, - bool value, - uint256 deadline - ) external view returns (bytes32 message); + int256 value + ) external; /** - * @notice Used to retrieve the message to be signed for submitting a presigned bytes attribute change. - * @param collection The address of the collection smart contract of the token receiving the attribute - * @param tokenId The ID of the token receiving the attribute + * @notice Used to set a string attribute. + * @dev Emits a {StringAttributeUpdated} event. + * @param collection Address of the collection receiving the attribute + * @param tokenId The token ID * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid - * @return message Raw message to be signed by the authorized account */ - function prepareMessageToPresignBytesAttribute( + function setStringAttribute( address collection, uint256 tokenId, string memory key, - bytes memory value, - uint256 deadline - ) external view returns (bytes32 message); + string memory value + ) external; /** - * @notice Used to retrieve the message to be signed for submitting a presigned address attribute change. - * @param collection The address of the collection smart contract of the token receiving the attribute - * @param tokenId The ID of the token receiving the attribute + * @notice Used to set an unsigned number attribute. + * @dev Emits a {UintAttributeUpdated} event. + * @param collection Address of the collection receiving the attribute + * @param tokenId The token ID * @param key The attribute key * @param value The attribute value - * @param deadline The deadline timestamp for the presigned transaction after which the message is invalid - * @return message Raw message to be signed by the authorized account */ - function prepareMessageToPresignAddressAttribute( + function setUintAttribute( address collection, uint256 tokenId, string memory key, - address value, - uint256 deadline - ) external view returns (bytes32 message); + uint256 value + ) external; + + // ------------------- BATCH SETTERS ------------------- /** - * @notice Used to retrieve multiple token attributes of any type at once. - * @dev The `StringAttribute`, `UintAttribute`, `BoolAttribute`, `AddressAttribute` and `BytesAttribute` structs consists - * to the following fields (where `value` is of the appropriate type): + * @notice Sets multiple address attributes for a token at once. + * @dev The `AddressAttribute` struct contains the following fields: * [ - * key, - * value, + * string key, + * address value * ] - * @param collection The collection address - * @param tokenId The token ID - * @param stringKeys An array of string type attribute keys to retrieve - * @param uintKeys An array of uint type attribute keys to retrieve - * @param boolKeys An array of bool type attribute keys to retrieve - * @param addressKeys An array of address type attribute keys to retrieve - * @param bytesKeys An array of bytes type attribute keys to retrieve - * @return stringAttributes An array of strings, in the same order as the stringKeys - * @return uintAttributes An array of uints, in the same order as the uintKeys - * @return boolAttributes An array of bools, in the same order as the boolKeys - * @return addressAttributes An array of addresses, in the same order as the addressKeys - * @return bytesAttributes An array of bytes, in the same order as the bytesKeys + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributes An array of `AddressAttribute` structs to be assigned to the given token */ - function getAttributes( - address collection, - uint256 tokenId, - string[] memory stringKeys, - string[] memory uintKeys, - string[] memory boolKeys, - string[] memory addressKeys, - string[] memory bytesKeys - ) - external - view - returns ( - string[] memory stringAttributes, - uint256[] memory uintAttributes, - bool[] memory boolAttributes, - address[] memory addressAttributes, - bytes[] memory bytesAttributes - ); + function setAddressAttributes( + address[] memory collections, + uint256[] memory tokenIds, + AddressAttribute[] memory attributes + ) external; /** - * @notice Used to get multiple sting parameter values for a token. - * @dev The `StringAttribute` struct contains the following fields: + * @notice Sets multiple bool attributes for a token at once. + * @dev The `BoolAttribute` struct contains the following fields: * [ - * string key, - * string value + * string key, + * bool value * ] - * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributeKeys An array of string keys to retrieve - * @return attributes An array of strings, in the same order as the attribute keys + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributes An array of `BoolAttribute` structs to be assigned to the given token */ - function getStringAttributes( + function setBoolAttributes( address[] memory collections, uint256[] memory tokenIds, - string[] memory attributeKeys - ) external view returns (string[] memory attributes); + BoolAttribute[] memory attributes + ) external; /** - * @notice Used to get multiple uint parameter values for a token. - * @dev The `UintAttribute` struct contains the following fields: + * @notice Sets multiple bytes attributes for a token at once. + * @dev The `BytesAttribute` struct contains the following fields: * [ - * string key, - * uint value + * string key, + * bytes value * ] - * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributeKeys An array of uint keys to retrieve - * @return attributes An array of uints, in the same order as the attribute keys + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributes An array of `BytesAttribute` structs to be assigned to the given token */ - function getUintAttributes( + function setBytesAttributes( address[] memory collections, uint256[] memory tokenIds, - string[] memory attributeKeys - ) external view returns (uint256[] memory attributes); + BytesAttribute[] memory attributes + ) external; /** - * @notice Used to get multiple bool parameter values for a token. - * @dev The `BoolAttribute` struct contains the following fields: + * @notice Sets multiple int attributes for a token at once. + * @dev The `UintAttribute` struct contains the following fields: * [ - * string key, - * bool value + * string key, + * int value * ] - * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributeKeys An array of bool keys to retrieve - * @return attributes An array of bools, in the same order as the attribute keys + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributes An array of `IntAttribute` structs to be assigned to the given token */ - function getBoolAttributes( + function setIntAttributes( address[] memory collections, uint256[] memory tokenIds, - string[] memory attributeKeys - ) external view returns (bool[] memory attributes); + IntAttribute[] memory attributes + ) external; /** - * @notice Used to get multiple address parameter values for a token. - * @dev The `AddressAttribute` struct contains the following fields: + * @notice Sets multiple string attributes for a token at once. + * @dev The `StringAttribute` struct contains the following fields: * [ - * string key, - * address value + * string key, + * string value * ] - * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributeKeys An array of address keys to retrieve - * @return attributes An array of addresses, in the same order as the attribute keys + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributes An array of `StringAttribute` structs to be assigned to the given token */ - function getAddressAttributes( + function setStringAttributes( address[] memory collections, uint256[] memory tokenIds, - string[] memory attributeKeys - ) external view returns (address[] memory attributes); + StringAttribute[] memory attributes + ) external; /** - * @notice Used to get multiple bytes parameter values for a token. - * @dev The `BytesAttribute` struct contains the following fields: + * @notice Sets multiple uint attributes for a token at once. + * @dev The `UintAttribute` struct contains the following fields: * [ - * string key, - * bytes value + * string key, + * uint value * ] - * @param collections Addresses of the collections, in the same order as the attribute keys. If all tokens are from the same collection the array can contain a single element with the collection address. - * @param tokenIds IDs of the tokens, in the same order as the attribute keys. If all attributes are for the same token the array can contain a single element with the token ID. - * @param attributeKeys An array of bytes keys to retrieve - * @return attributes An array of bytes, in the same order as the attribute keys + * @param collections Addresses of the collections, in the same order as the attributes. If all tokens are from the same collection the array can contain a single element with the collection address. + * @param tokenIds IDs of the tokens, in the same order as the attributes. If all attributes are for the same token the array can contain a single element with the token ID. + * @param attributes An array of `UintAttribute` structs to be assigned to the given token */ - function getBytesAttributes( + function setUintAttributes( address[] memory collections, uint256[] memory tokenIds, - string[] memory attributeKeys - ) external view returns (bytes[] memory attributes); + UintAttribute[] memory attributes + ) external; + + /** + * @notice Sets multiple attributes of multiple types for a token at the same time. + * @dev Emits a separate event for each attribute set. + * @dev The `StringAttribute`, `UintAttribute`, `BoolAttribute`, `AddressAttribute` and `BytesAttribute` structs consists + * to the following fields (where `value` is of the appropriate type): + * [ + * key, + * value, + * ] + * @param collection The address of the collection + * @param tokenId The token ID + * @param addressAttributes An array of `AddressAttribute` structs containing address attributes to set + * @param boolAttributes An array of `BoolAttribute` structs containing bool attributes to set + * @param bytesAttributes An array of `BytesAttribute` structs containing bytes attributes to set + * @param intAttributes An array of `IntAttribute` structs containing int attributes to set + * @param stringAttributes An array of `StringAttribute` structs containing string attributes to set + * @param uintAttributes An array of `UintAttribute` structs containing uint attributes to set + */ + function setAttributes( + address collection, + uint256 tokenId, + AddressAttribute[] memory addressAttributes, + BoolAttribute[] memory boolAttributes, + BytesAttribute[] memory bytesAttributes, + IntAttribute[] memory intAttributes, + StringAttribute[] memory stringAttributes, + UintAttribute[] memory uintAttributes + ) external; + + // ------------------- PRESIGNED SETTERS ------------------- + + /** + * @notice Used to set the address attribute on behalf of an authorized account. + * @dev Emits a {AddressAttributeUpdated} event. + * @param setter Address of the account that presigned the attribute change + * @param collection Address of the collection receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction + * @param v `v` value of an ECDSA signature of the presigned message + * @param r `r` value of an ECDSA signature of the presigned message + * @param s `s` value of an ECDSA signature of the presigned message + */ + function presignedSetAddressAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + address value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @notice Used to set the bool attribute on behalf of an authorized account. + * @dev Emits a {BoolAttributeUpdated} event. + * @param setter Address of the account that presigned the attribute change + * @param collection Address of the collection receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction + * @param v `v` value of an ECDSA signature of the presigned message + * @param r `r` value of an ECDSA signature of the presigned message + * @param s `s` value of an ECDSA signature of the presigned message + */ + function presignedSetBoolAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + bool value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @notice Used to set the bytes attribute on behalf of an authorized account. + * @dev Emits a {BytesAttributeUpdated} event. + * @param setter Address of the account that presigned the attribute change + * @param collection Address of the collection receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction + * @param v `v` value of an ECDSA signature of the presigned message + * @param r `r` value of an ECDSA signature of the presigned message + * @param s `s` value of an ECDSA signature of the presigned message + */ + function presignedSetBytesAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + bytes memory value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @notice Used to set the int attribute on behalf of an authorized account. + * @dev Emits a {IntAttributeUpdated} event. + * @param setter Address of the account that presigned the attribute change + * @param collection Address of the collection receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction + * @param v `v` value of an ECDSA signature of the presigned message + * @param r `r` value of an ECDSA signature of the presigned message + * @param s `s` value of an ECDSA signature of the presigned message + */ + function presignedSetIntAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + int256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @notice Used to set the string attribute on behalf of an authorized account. + * @dev Emits a {StringAttributeUpdated} event. + * @param setter Address of the account that presigned the attribute change + * @param collection Address of the collection receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction + * @param v `v` value of an ECDSA signature of the presigned message + * @param r `r` value of an ECDSA signature of the presigned message + * @param s `s` value of an ECDSA signature of the presigned message + */ + function presignedSetStringAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + string memory value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @notice Used to set the uint attribute on behalf of an authorized account. + * @dev Emits a {UintAttributeUpdated} event. + * @param setter Address of the account that presigned the attribute change + * @param collection Address of the collection receiving the attribute + * @param tokenId The ID of the token receiving the attribute + * @param key The attribute key + * @param value The attribute value + * @param deadline The deadline timestamp for the presigned transaction + * @param v `v` value of an ECDSA signature of the presigned message + * @param r `r` value of an ECDSA signature of the presigned message + * @param s `s` value of an ECDSA signature of the presigned message + */ + function presignedSetUintAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; } diff --git a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol index f1711765..4f4f693e 100644 --- a/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol +++ b/contracts/RMRK/extension/tokenAttributes/RMRKTokenAttributesRepository.sol @@ -27,6 +27,10 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { keccak256( "setUintAttribute(address collection,uint256 tokenId,string memory key,uint256 value)" ); + bytes32 public immutable SET_INT_ATTRIBUTE_TYPEHASH = + keccak256( + "setUintAttribute(address collection,uint256 tokenId,string memory key,int256 value)" + ); bytes32 public immutable SET_STRING_ATTRIBUTE_TYPEHASH = keccak256( "setStringAttribute(address collection,uint256 tokenId,string memory key,string memory value)" @@ -66,6 +70,8 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { private _bytesValues; mapping(address collection => mapping(uint256 => mapping(uint256 => uint256))) private _uintValues; + mapping(address collection => mapping(uint256 => mapping(uint256 => int256))) + private _intValues; mapping(address collection => mapping(uint256 => mapping(uint256 => bool))) private _boolValues; mapping(address collection => mapping(uint256 => mapping(uint256 => string))) @@ -341,6 +347,17 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { attribute = _uintValues[collection][tokenId][_keysToIds[key]]; } + /** + * @inheritdoc IERC7508 + */ + function getIntAttribute( + address collection, + uint256 tokenId, + string memory key + ) public view returns (int256 attribute) { + attribute = _intValues[collection][tokenId][_keysToIds[key]]; + } + /** * @inheritdoc IERC7508 */ @@ -380,40 +397,92 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { function getAttributes( address collection, uint256 tokenId, - string[] memory stringKeys, - string[] memory uintKeys, - string[] memory boolKeys, string[] memory addressKeys, - string[] memory bytesKeys + string[] memory boolKeys, + string[] memory bytesKeys, + string[] memory intKeys, + string[] memory stringKeys, + string[] memory uintKeys ) external view returns ( - string[] memory stringAttributes, - uint256[] memory uintAttributes, - bool[] memory boolAttributes, address[] memory addressAttributes, - bytes[] memory bytesAttributes + bool[] memory boolAttributes, + bytes[] memory bytesAttributes, + int256[] memory intAttributes, + string[] memory stringAttributes, + uint256[] memory uintAttributes ) { - address[] memory collections = new address[](1); - uint256[] memory tokenIds = new uint256[](1); - collections[0] = collection; - tokenIds[0] = tokenId; - - stringAttributes = getStringAttributes( - collections, - tokenIds, - stringKeys - ); - uintAttributes = getUintAttributes(collections, tokenIds, uintKeys); - boolAttributes = getBoolAttributes(collections, tokenIds, boolKeys); - addressAttributes = getAddressAttributes( - collections, - tokenIds, - addressKeys - ); - bytesAttributes = getBytesAttributes(collections, tokenIds, bytesKeys); + // WARNING: This implementation is a bit inneficient and differs slightly from the ERC one, to avoid stack too deep errors without using via-IR flag which would affect all other contracts in the package. This is not relevant since you should only need the interface to interact with the actual repo on each network anyway. + stringAttributes = new string[](stringKeys.length); + for (uint256 i; i < stringKeys.length; ) { + stringAttributes[i] = getStringAttribute( + collection, + tokenId, + stringKeys[i] + ); + unchecked { + ++i; + } + } + + uintAttributes = new uint256[](uintKeys.length); + for (uint256 i; i < uintKeys.length; ) { + uintAttributes[i] = getUintAttribute( + collection, + tokenId, + uintKeys[i] + ); + unchecked { + ++i; + } + } + + intAttributes = new int256[](intKeys.length); + for (uint256 i; i < intKeys.length; ) { + intAttributes[i] = getIntAttribute(collection, tokenId, intKeys[i]); + unchecked { + ++i; + } + } + + boolAttributes = new bool[](boolKeys.length); + for (uint256 i; i < boolKeys.length; ) { + boolAttributes[i] = getBoolAttribute( + collection, + tokenId, + boolKeys[i] + ); + unchecked { + ++i; + } + } + + addressAttributes = new address[](addressKeys.length); + for (uint256 i; i < addressKeys.length; ) { + addressAttributes[i] = getAddressAttribute( + collection, + tokenId, + addressKeys[i] + ); + unchecked { + ++i; + } + } + + bytesAttributes = new bytes[](bytesKeys.length); + for (uint256 i; i < bytesKeys.length; ) { + bytesAttributes[i] = getBytesAttribute( + collection, + tokenId, + bytesKeys[i] + ); + unchecked { + ++i; + } + } } /** @@ -482,6 +551,39 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } + /** + * @inheritdoc IERC7508 + */ + function getIntAttributes( + address[] memory collections, + uint256[] memory tokenIds, + string[] memory attributeKeys + ) public view returns (int256[] memory attributes) { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributeKeys.length + ); + + attributes = new int256[](loopLength); + + for (uint256 i; i < loopLength; ) { + attributes[i] = getIntAttribute( + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + multipleAttributes ? attributeKeys[i] : attributeKeys[0] + ); + unchecked { + ++i; + } + } + } + /** * @inheritdoc IERC7508 */ @@ -604,6 +706,29 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { ); } + /** + * @inheritdoc IERC7508 + */ + function prepareMessageToPresignIntAttribute( + address collection, + uint256 tokenId, + string memory key, + int256 value, + uint256 deadline + ) public view returns (bytes32 message) { + message = keccak256( + abi.encode( + DOMAIN_SEPARATOR, + SET_UINT_ATTRIBUTE_TYPEHASH, + collection, + tokenId, + key, + value, + deadline + ) + ); + } + /** * @inheritdoc IERC7508 */ @@ -744,6 +869,18 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { _setUintAttribute(_msgSender(), collection, tokenId, key, value); } + /** + * @inheritdoc IERC7508 + */ + function setIntAttribute( + address collection, + uint256 tokenId, + string memory key, + int256 value + ) external { + _setIntAttribute(_msgSender(), collection, tokenId, key, value); + } + /** * @inheritdoc IERC7508 */ @@ -896,6 +1033,41 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } + /** + * @inheritdoc IERC7508 + */ + function setIntAttributes( + address[] memory collections, + uint256[] memory tokenIds, + IntAttribute[] memory attributes + ) external { + ( + bool multipleCollections, + bool multipleTokens, + bool multipleAttributes, + uint256 loopLength + ) = _checkIfMultipleCollectionsAndTokens( + collections, + tokenIds, + attributes.length + ); + for (uint256 i; i < loopLength; ) { + IntAttribute memory attribute = multipleAttributes + ? attributes[i] + : attributes[0]; + _setIntAttribute( + _msgSender(), + multipleCollections ? collections[i] : collections[0], + multipleTokens ? tokenIds[i] : tokenIds[0], + attribute.key, + attribute.value + ); + unchecked { + ++i; + } + } + } + /** * @inheritdoc IERC7508 */ @@ -937,11 +1109,12 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { function setAttributes( address collection, uint256 tokenId, - StringAttribute[] memory stringAttributes, - UintAttribute[] memory uintAttributes, - BoolAttribute[] memory boolAttributes, AddressAttribute[] memory addressAttributes, - BytesAttribute[] memory bytesAttributes + BoolAttribute[] memory boolAttributes, + BytesAttribute[] memory bytesAttributes, + IntAttribute[] memory intAttributes, + StringAttribute[] memory stringAttributes, + UintAttribute[] memory uintAttributes ) external { uint256 length = stringAttributes.length; for (uint256 i; i < length; ) { @@ -971,6 +1144,20 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { } } + length = intAttributes.length; + for (uint256 i; i < length; ) { + _setIntAttribute( + _msgSender(), + collection, + tokenId, + intAttributes[i].key, + intAttributes[i].value + ); + unchecked { + ++i; + } + } + length = boolAttributes.length; for (uint256 i; i < length; ) { _setBoolAttribute( @@ -1114,6 +1301,18 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { emit UintAttributeUpdated(collection, tokenId, key, value); } + function _setIntAttribute( + address caller, + address collection, + uint256 tokenId, + string memory key, + int256 value + ) internal { + _onlyAuthorizedCaller(caller, collection, key, tokenId); + _intValues[collection][tokenId][_getIdForKey(key)] = value; + emit IntAttributeUpdated(collection, tokenId, key, value); + } + /** * @inheritdoc IERC7508 */ @@ -1148,6 +1347,40 @@ contract RMRKTokenAttributesRepository is IERC7508, Context { _setUintAttribute(setter, collection, tokenId, key, value); } + /** + * @inheritdoc IERC7508 + */ + function presignedSetIntAttribute( + address setter, + address collection, + uint256 tokenId, + string memory key, + int256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external { + bytes32 digest = keccak256( + abi.encodePacked( + "\x19Ethereum Signed Message:\n32", + keccak256( + abi.encode( + DOMAIN_SEPARATOR, + SET_UINT_ATTRIBUTE_TYPEHASH, + collection, + tokenId, + key, + value, + deadline + ) + ) + ) + ); + _checkDeadlineAndSigner(setter, deadline, digest, v, r, s); + _setIntAttribute(setter, collection, tokenId, key, value); + } + /** * @inheritdoc IERC7508 */ diff --git a/hardhat.config.ts b/hardhat.config.ts index 338ffd93..9a241fcc 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -22,6 +22,7 @@ const config: HardhatUserConfig = { solidity: { version: '0.8.21', settings: { + // viaIR: true, evmVersion: 'london', optimizer: { enabled: true, diff --git a/test/extensions/tokenAttributesRepository.ts b/test/extensions/tokenAttributesRepository.ts index 53c7c4d9..1f73b8d4 100644 --- a/test/extensions/tokenAttributesRepository.ts +++ b/test/extensions/tokenAttributesRepository.ts @@ -54,7 +54,7 @@ describe('RMRKTokenAttributesRepository', async function () { this.ownedCollection = ownedCollection; }); - shouldBehaveLikeTokenAttributesRepositoryInterface(); + shouldBehaveLikeAttributesRepositoryInterface(); describe('Registering attributes and setting values', async function () { beforeEach(async function () { @@ -66,53 +66,59 @@ describe('RMRKTokenAttributesRepository', async function () { }); it('can set and get token attributes', async function () { - expect( - await tokenAttributes.setStringAttribute( + await expect( + tokenAttributes.setStringAttribute( collectionAddress, tokenId, 'description', 'test description', ), ) - .to.emit(tokenAttributes, 'StringAttributeSet') + .to.emit(tokenAttributes, 'StringAttributeUpdated') .withArgs(collectionAddress, tokenId, 'description', 'test description'); - expect( - await tokenAttributes.setStringAttribute( + await expect( + tokenAttributes.setStringAttribute( collectionAddress, tokenId, 'description1', 'test description', ), ) - .to.emit(tokenAttributes, 'StringAttributeSet') + .to.emit(tokenAttributes, 'StringAttributeUpdated') .withArgs(collectionAddress, tokenId, 'description1', 'test description'); - expect(await tokenAttributes.setBoolAttribute(collectionAddress, tokenId, 'rare', true)) - .to.emit(tokenAttributes, 'BoolAttributeSet') + await expect(tokenAttributes.setBoolAttribute(collectionAddress, tokenId, 'rare', true)) + .to.emit(tokenAttributes, 'BoolAttributeUpdated') .withArgs(collectionAddress, tokenId, 'rare', true); - expect( - await tokenAttributes.setAddressAttribute( + await expect( + tokenAttributes.setAddressAttribute( collectionAddress, tokenId, 'owner', tokenOwner.address, ), ) - .to.emit(tokenAttributes, 'AddressAttributeSet') + .to.emit(tokenAttributes, 'AddressAttributeUpdated') .withArgs(collectionAddress, tokenId, 'owner', tokenOwner.address); - expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'atk', 100n)) - .to.emit(tokenAttributes, 'UintAttributeSet') + await expect(tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'atk', 100n)) + .to.emit(tokenAttributes, 'UintAttributeUpdated') .withArgs(collectionAddress, tokenId, 'atk', 100n); - expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 100n)) - .to.emit(tokenAttributes, 'UintAttributeSet') + await expect(tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 100n)) + .to.emit(tokenAttributes, 'UintAttributeUpdated') .withArgs(collectionAddress, tokenId, 'health', 100n); - expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 95n)) - .to.emit(tokenAttributes, 'UintAttributeSet') + await expect(tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 95n)) + .to.emit(tokenAttributes, 'UintAttributeUpdated') .withArgs(collectionAddress, tokenId, 'health', 95n); - expect(await tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 80n)) - .to.emit(tokenAttributes, 'UintAttributeSet') + await expect(tokenAttributes.setUintAttribute(collectionAddress, tokenId, 'health', 80n)) + .to.emit(tokenAttributes, 'UintAttributeUpdated') .withArgs(collectionAddress, tokenId, 'health', 80n); - expect(await tokenAttributes.setBytesAttribute(collectionAddress, tokenId, 'data', '0x1234')) - .to.emit(tokenAttributes, 'BytesAttributeSet') + await expect(tokenAttributes.setIntAttribute(collectionAddress, tokenId, 'int', 1n)) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, tokenId, 'int', 1n); + await expect(tokenAttributes.setIntAttribute(collectionAddress, tokenId, 'int2', -10n)) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, tokenId, 'int2', -10n); + await expect(tokenAttributes.setBytesAttribute(collectionAddress, tokenId, 'data', '0x1234')) + .to.emit(tokenAttributes, 'BytesAttributeUpdated') .withArgs(collectionAddress, tokenId, 'data', '0x1234'); expect( @@ -133,6 +139,10 @@ describe('RMRKTokenAttributesRepository', async function () { expect(await tokenAttributes.getUintAttribute(collectionAddress, tokenId, 'health')).to.eql( 80n, ); + expect(await tokenAttributes.getIntAttribute(collectionAddress, tokenId, 'int')).to.eql(1n); + expect(await tokenAttributes.getIntAttribute(collectionAddress, tokenId, 'int2')).to.eql( + -10n, + ); expect(await tokenAttributes.getBytesAttribute(collectionAddress, tokenId, 'data')).to.eql( '0x1234', ); @@ -154,79 +164,21 @@ describe('RMRKTokenAttributesRepository', async function () { collectionAddress, tokenId, [ - { key: 'string1', value: 'value1' }, - { key: 'string2', value: 'value2' }, - ], - [ - { key: 'uint1', value: 1n }, - { key: 'uint2', value: 2n }, + { key: 'address1', value: tokenOwner.address }, + { key: 'address2', value: await collectionOwner.getAddress() }, ], [ { key: 'bool1', value: true }, { key: 'bool2', value: false }, ], - [ - { key: 'address1', value: tokenOwner.address }, - { key: 'address2', value: await collectionOwner.getAddress() }, - ], [ { key: 'bytes1', value: '0x1234' }, { key: 'bytes2', value: '0x5678' }, ], - ), - ) - .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'string1', 'value1') - .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'string2', 'value2') - .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'uint1', 1n) - .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'uint2', 2n) - .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bool1', true) - .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bool2', false) - .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) - .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()) - .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') - .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); - }); - - it('can update multiple attributes of multiple types at the same time', async function () { - await tokenAttributes.setAttributes( - collectionAddress, - tokenId, - [ - { key: 'string1', value: 'value0' }, - { key: 'string2', value: 'value1' }, - ], - [ - { key: 'uint1', value: 0n }, - { key: 'uint2', value: 1n }, - ], - [ - { key: 'bool1', value: false }, - { key: 'bool2', value: true }, - ], - [ - { key: 'address1', value: await collectionOwner.getAddress() }, - { key: 'address2', value: tokenOwner.address }, - ], - [ - { key: 'bytes1', value: '0x5678' }, - { key: 'bytes2', value: '0x1234' }, - ], - ); - - await expect( - tokenAttributes.setAttributes( - collectionAddress, - tokenId, + [ + { key: 'int1', value: -10n }, + { key: 'int2', value: 2n }, + ], [ { key: 'string1', value: 'value1' }, { key: 'string2', value: 'value2' }, @@ -235,18 +187,6 @@ describe('RMRKTokenAttributesRepository', async function () { { key: 'uint1', value: 1n }, { key: 'uint2', value: 2n }, ], - [ - { key: 'bool1', value: true }, - { key: 'bool2', value: false }, - ], - [ - { key: 'address1', value: tokenOwner.address }, - { key: 'address2', value: await collectionOwner.getAddress() }, - ], - [ - { key: 'bytes1', value: '0x1234' }, - { key: 'bytes2', value: '0x5678' }, - ], ), ) .to.emit(tokenAttributes, 'StringAttributeUpdated') @@ -257,6 +197,10 @@ describe('RMRKTokenAttributesRepository', async function () { .withArgs(collectionAddress, tokenId, 'uint1', 1n) .to.emit(tokenAttributes, 'UintAttributeUpdated') .withArgs(collectionAddress, tokenId, 'uint2', 2n) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, tokenId, 'int1', -10n) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, tokenId, 'int2', 2n) .to.emit(tokenAttributes, 'BoolAttributeUpdated') .withArgs(collectionAddress, tokenId, 'bool1', true) .to.emit(tokenAttributes, 'BoolAttributeUpdated') @@ -275,43 +219,45 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes.setAttributes( collectionAddress, tokenId, - [{ key: 'string1', value: 'value0' }], [ - { key: 'uint1', value: 0n }, - { key: 'uint2', value: 1n }, + { key: 'address1', value: await collectionOwner.getAddress() }, + { key: 'address2', value: tokenOwner.address }, ], [ { key: 'bool1', value: false }, { key: 'bool2', value: true }, ], + [], + [], + [{ key: 'string1', value: 'value0' }], [ - { key: 'address1', value: await collectionOwner.getAddress() }, - { key: 'address2', value: tokenOwner.address }, + { key: 'uint1', value: 0n }, + { key: 'uint2', value: 1n }, ], - [], ); await expect( tokenAttributes.setAttributes( collectionAddress, tokenId, - [], [ - { key: 'uint1', value: 1n }, - { key: 'uint2', value: 2n }, + { key: 'address1', value: tokenOwner.address }, + { key: 'address2', value: await collectionOwner.getAddress() }, ], [ { key: 'bool1', value: true }, { key: 'bool2', value: false }, ], - [ - { key: 'address1', value: tokenOwner.address }, - { key: 'address2', value: await collectionOwner.getAddress() }, - ], [ { key: 'bytes1', value: '0x1234' }, { key: 'bytes2', value: '0x5678' }, ], + [], + [], + [ + { key: 'uint1', value: 1n }, + { key: 'uint2', value: 2n }, + ], ), ) .to.emit(tokenAttributes, 'UintAttributeUpdated') @@ -336,13 +282,14 @@ describe('RMRKTokenAttributesRepository', async function () { collectionAddress, tokenId, [], - [], [ { key: 'bool1', value: false }, { key: 'bool2', value: true }, ], [], [], + [], + [], ), ) .to.emit(tokenAttributes, 'BoolAttributeUpdated') @@ -351,97 +298,54 @@ describe('RMRKTokenAttributesRepository', async function () { .withArgs(collectionAddress, tokenId, 'bool2', true); }); - it('can set and update multiple attributes of multiple types at the same time', async function () { - await expect( - tokenAttributes.setAttributes( - collectionAddress, - tokenId, - [ - { key: 'string1', value: 'value1' }, - { key: 'string2', value: 'value2' }, - ], - [ - { key: 'uint1', value: 1n }, - { key: 'uint2', value: 2n }, - ], - [ - { key: 'bool1', value: true }, - { key: 'bool2', value: false }, - ], - [ - { key: 'address1', value: tokenOwner.address }, - { key: 'address2', value: await collectionOwner.getAddress() }, - ], - [ - { key: 'bytes1', value: '0x1234' }, - { key: 'bytes2', value: '0x5678' }, - ], - ), - ) - .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'string1', 'value1') - .to.emit(tokenAttributes, 'StringAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'string2', 'value2') - .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'uint1', 1n) - .to.emit(tokenAttributes, 'UintAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'uint2', 2n) - .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bool1', true) - .to.emit(tokenAttributes, 'BoolAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bool2', false) - .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'address1', tokenOwner.address) - .to.emit(tokenAttributes, 'AddressAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'address2', await collectionOwner.getAddress()) - .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bytes1', '0x1234') - .to.emit(tokenAttributes, 'BytesAttributeUpdated') - .withArgs(collectionAddress, tokenId, 'bytes2', '0x5678'); - }); - it('should allow to retrieve multiple attributes at once', async function () { await tokenAttributes.setAttributes( collectionAddress, tokenId, [ - { key: 'string1', value: 'value1' }, - { key: 'string2', value: 'value2' }, - ], - [ - { key: 'uint1', value: 1n }, - { key: 'uint2', value: 2n }, + { key: 'address1', value: tokenOwner.address }, + { key: 'address2', value: await collectionOwner.getAddress() }, ], [ { key: 'bool1', value: true }, { key: 'bool2', value: false }, ], - [ - { key: 'address1', value: tokenOwner.address }, - { key: 'address2', value: await collectionOwner.getAddress() }, - ], [ { key: 'bytes1', value: '0x1234' }, { key: 'bytes2', value: '0x5678' }, ], + [ + { key: 'int1', value: -10n }, + { key: 'int2', value: 2n }, + ], + [ + { key: 'string1', value: 'value1' }, + { key: 'string2', value: 'value2' }, + ], + [ + { key: 'uint1', value: 1n }, + { key: 'uint2', value: 2n }, + ], ); expect( await tokenAttributes.getAttributes( collectionAddress, tokenId, - ['string1', 'string2'], - ['uint1', 'uint2'], - ['bool1', 'bool2'], ['address1', 'address2'], + ['bool1', 'bool2'], ['bytes1', 'bytes2'], + ['int1', 'int2'], + ['string1', 'string2'], + ['uint1', 'uint2'], ), ).to.eql([ - ['value1', 'value2'], - [1n, 2n], - [true, false], [tokenOwner.address, await collectionOwner.getAddress()], + [true, false], ['0x1234', '0x5678'], + [-10n, 2n], + ['value1', 'value2'], + [1n, 2n], ]); }); @@ -465,13 +369,14 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes.getAttributes( collectionAddress, tokenId, - ['string1', 'string2'], [], [], [], [], + ['string1', 'string2'], + [], ), - ).to.eql([['value1', 'value2'], [], [], [], []]); + ).to.eql([[], [], [], [], ['value1', 'value2'], []]); }); it('can set multiple uint attributes at the same time', async function () { @@ -495,12 +400,43 @@ describe('RMRKTokenAttributesRepository', async function () { collectionAddress, tokenId, [], + [], + [], + [], + [], ['uint1', 'uint2'], + ), + ).to.eql([[], [], [], [], [], [1n, 2n]]); + }); + + it('can set multiple int attributes at the same time', async function () { + await expect( + tokenAttributes.setIntAttributes( + [collectionAddress], + [tokenId], + [ + { key: 'int1', value: -10n }, + { key: 'int2', value: 2n }, + ], + ), + ) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, tokenId, 'int1', -10n) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, tokenId, 'int2', 2n); + + expect( + await tokenAttributes.getAttributes( + collectionAddress, + tokenId, + [], [], [], + ['int1', 'int2'], + [], [], ), - ).to.eql([[], [1n, 2n], [], [], []]); + ).to.eql([[], [], [], [-10n, 2n], [], []]); }); it('can set multiple bool attributes at the same time', async function () { @@ -524,12 +460,13 @@ describe('RMRKTokenAttributesRepository', async function () { collectionAddress, tokenId, [], - [], ['bool1', 'bool2'], [], [], + [], + [], ), - ).to.eql([[], [], [true, false], [], []]); + ).to.eql([[], [true, false], [], [], [], []]); }); it('can set multiple address attributes at the same time', async function () { @@ -552,13 +489,14 @@ describe('RMRKTokenAttributesRepository', async function () { await tokenAttributes.getAttributes( collectionAddress, tokenId, + ['address1', 'address2'], + [], [], [], [], - ['address1', 'address2'], [], ), - ).to.eql([[], [], [], [tokenOwner.address, await collectionOwner.getAddress()], []]); + ).to.eql([[tokenOwner.address, await collectionOwner.getAddress()], [], [], [], [], []]); }); it('can set multiple bytes attributes at the same time', async function () { @@ -583,11 +521,12 @@ describe('RMRKTokenAttributesRepository', async function () { tokenId, [], [], + ['bytes1', 'bytes2'], + [], [], [], - ['bytes1', 'bytes2'], ), - ).to.eql([[], [], [], [], ['0x1234', '0x5678']]); + ).to.eql([[], [], ['0x1234', '0x5678'], [], [], []]); }); it('can reuse keys and values are fine', async function () { @@ -1066,6 +1005,13 @@ describe('RMRKTokenAttributesRepository', async function () { 1, 9999999999n, ); + const intMessage = await tokenAttributes.prepareMessageToPresignIntAttribute( + collectionAddress, + tokenId, + 'X', + -10n, + 9999999999n, + ); const stringMessage = await tokenAttributes.prepareMessageToPresignStringAttribute( collectionAddress, tokenId, @@ -1096,6 +1042,7 @@ describe('RMRKTokenAttributesRepository', async function () { ); const uintSignature = await collectionOwner.signMessage(ethers.getBytes(uintMessage)); + const intSignature = await collectionOwner.signMessage(ethers.getBytes(intMessage)); const stringSignature = await collectionOwner.signMessage(ethers.getBytes(stringMessage)); const boolSignature = await collectionOwner.signMessage(ethers.getBytes(boolMessage)); const bytesSignature = await collectionOwner.signMessage(ethers.getBytes(bytesMessage)); @@ -1105,6 +1052,10 @@ describe('RMRKTokenAttributesRepository', async function () { const uintS: string = '0x' + uintSignature.substring(66, 130); const uintV: string = parseInt(uintSignature.substring(130, 132), 16).toString(); + const intR: string = intSignature.substring(0, 66); + const intS: string = '0x' + intSignature.substring(66, 130); + const intV: string = parseInt(intSignature.substring(130, 132), 16).toString(); + const stringR: string = stringSignature.substring(0, 66); const stringS: string = '0x' + stringSignature.substring(66, 130); const stringV: string = parseInt(stringSignature.substring(130, 132), 16).toString(); @@ -1138,6 +1089,24 @@ describe('RMRKTokenAttributesRepository', async function () { ) .to.emit(tokenAttributes, 'UintAttributeUpdated') .withArgs(collectionAddress, 1, 'X', 1); + + await expect( + tokenAttributes + .connect(tokenOwner) + .presignedSetIntAttribute( + await collectionOwner.getAddress(), + collectionAddress, + tokenId, + 'X', + -10n, + 9999999999n, + intV, + intR, + intS, + ), + ) + .to.emit(tokenAttributes, 'IntAttributeUpdated') + .withArgs(collectionAddress, 1, 'X', -10); await expect( tokenAttributes .connect(tokenOwner) @@ -1640,7 +1609,7 @@ describe('RMRKTokenAttributesRepository', async function () { }); }); -async function shouldBehaveLikeTokenAttributesRepositoryInterface() { +async function shouldBehaveLikeAttributesRepositoryInterface() { it('can support IERC165', async function () { expect(await this.tokenAttributes.supportsInterface(IERC165)).to.equal(true); }); diff --git a/test/interfaces.ts b/test/interfaces.ts index aab29664..27d083bc 100644 --- a/test/interfaces.ts +++ b/test/interfaces.ts @@ -7,7 +7,7 @@ export const IERC6220 = '0x28bc9ae4'; // Equippable and Composable export const IERC6454 = '0x91a6262f'; // Soulbound export const IERC7401 = '0x42b0e56f'; // Nestable export const IERC7409 = '0x1b3327ab'; // Emotes Repository -export const IERC7508 = '0x62ee8e7a'; // Attributes Repository +export const IERC7508 = '0x502f80e4'; // Attributes Repository export const IERC7590 = '0x6f87c75c'; // ERC20 Token Holder export const IOtherInterface = '0xffffffff'; export const IRMRKCatalog = '0xd912401f'; // ERC6220