Skip to content

Commit

Permalink
refactor!: set LSP8 TokenId Type on deployment / initialization (#712)
Browse files Browse the repository at this point in the history
* feat!: add tokenidType setting in `constructor` + prevent updating it via `_setData`

* build: add constants for different types of LSP8 tokenIds

* refactor: remove error check to allow setting additional future types of tokenIds

* docs: auto-generate new docs for LSP8

* test: fix failing tests for Foundry and LSP1

* chore: fix linter errors and re-generate docs

* docs: add leading `_` to param name + add Natspec
  • Loading branch information
CJ42 authored Sep 27, 2023
1 parent ff83dfb commit 67cb333
Show file tree
Hide file tree
Showing 56 changed files with 523 additions and 99 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import {
ERC725YDataKeys,
PERMISSIONS,
ALL_PERMISSIONS,
LSP8_TOKEN_ID_TYPES,
LSP25_VERSION,
ErrorSelectors,
EventSigHashes,
Expand Down
18 changes: 18 additions & 0 deletions constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ export const ERC725YDataKeys = {
// AddressPermissions:AllowedCalls:<address> + bytes2(0)
'AddressPermissions:AllowedCalls': '0x4b80742de2bf393a64c70000',
},
LSP8: {
LSP8TokenIdType: '0x715f248956de7ce65e94d9d836bfead479f7e70d69b718d47bfe7b00e05b4fe4',
},
LSP9: {
SupportedStandards_LSP9: SupportedStandards.LSP9Vault.key,
},
Expand Down Expand Up @@ -371,6 +374,21 @@ export const LSP1_TYPE_IDS = {
'0xe32c7debcb817925ba4883fdbfc52797187f28f73f860641dab1a68d9b32902c',
};

// LSP8
// ----------

/**
* @dev list of LSP8 Token ID types that can be used to create different types of NFTs.
* @see for details see: https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenidtype
*/
export const LSP8_TOKEN_ID_TYPES = {
NUMBER: 0,
STRING: 1,
UNIQUE_ID: 2,
HASH: 3,
ADDRESS: 4,
};

// LSP25
// ----------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ abstract contract LSP4DigitalAssetMetadata is ERC725Y {

/**
* @dev The ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol` cannot be changed
* via this function once the digital asset contract has been deployed.
* via this function once the digital asset contract has been deployed.
*
* @dev Save gas by emitting the {DataChanged} event with only the first 256 bytes of dataValue
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ abstract contract LSP4DigitalAssetMetadataInitAbstract is ERC725YInitAbstract {

/**
* @dev the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol` cannot be changed
* via this function once the digital asset contract has been deployed.
* via this function once the digital asset contract has been deployed.
*
* @dev Save gas by emitting the {DataChanged} event with only the first 256 bytes of dataValue
*/
Expand Down
11 changes: 11 additions & 0 deletions contracts/LSP8IdentifiableDigitalAsset/LSP8Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ bytes4 constant _INTERFACEID_LSP8 = 0x1ae9ba1f;

// --- ERC725Y Data Keys

// keccak256('LSP8TokenIdType')
bytes32 constant _LSP8_TOKENID_TYPE_KEY = 0x715f248956de7ce65e94d9d836bfead479f7e70d69b718d47bfe7b00e05b4fe4;

// bytes10(keccak256('LSP8MetadataAddress')) + bytes2(0)
bytes12 constant _LSP8_METADATA_ADDRESS_KEY_PREFIX = 0x73dcc7c3c4096cdc7f8a0000;

Expand All @@ -22,3 +25,11 @@ bytes32 constant _TYPEID_LSP8_TOKENSRECIPIENT = 0x0b084a55ebf70fd3c06fd755269dac

// keccak256('LSP8Tokens_OperatorNotification')
bytes32 constant _TYPEID_LSP8_TOKENOPERATOR = 0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970;

// --- Types of token IDs

uint256 constant _LSP8_TOKENID_TYPE_NUMBER = 0;
uint256 constant _LSP8_TOKENID_TYPE_STRING = 1;
uint256 constant _LSP8_TOKENID_TYPE_UNIQUE_ID = 2;
uint256 constant _LSP8_TOKENID_TYPE_HASH = 3;
uint256 constant _LSP8_TOKENID_TYPE_ADDRESS = 4;
7 changes: 7 additions & 0 deletions contracts/LSP8IdentifiableDigitalAsset/LSP8Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,10 @@ error LSP8TokenOwnerCannotBeOperator();
* @notice LSP8 contract cannot receive native tokens.
*/
error LSP8TokenContractCannotHoldValue();

/**
* @dev Reverts when trying to edit the data key `LSP8TokenIdType` after the identifiable digital asset contract has been deployed.
* The `LSP8TokenIdType` data key is located inside the ERC725Y Data key-value store of the identifiable digital asset contract.
* It can be set only once inside the constructor/initializer when the identifiable digital asset contract is being deployed.
*/
error LSP8TokenIdTypeNotEditable();
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ import {LSP17Extendable} from "../LSP17ContractExtension/LSP17Extendable.sol";
import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol";

// constants
import {_INTERFACEID_LSP8} from "./LSP8Constants.sol";
import {LSP8TokenContractCannotHoldValue} from "./LSP8Errors.sol";
import {_INTERFACEID_LSP8, _LSP8_TOKENID_TYPE_KEY} from "./LSP8Constants.sol";

// errors
import {
LSP8TokenContractCannotHoldValue,
LSP8TokenIdTypeNotEditable
} from "./LSP8Errors.sol";

import {
_LSP17_EXTENSION_PREFIX
Expand Down Expand Up @@ -51,16 +56,32 @@ abstract contract LSP8IdentifiableDigitalAsset is
LSP17Extendable
{
/**
* @notice Sets the token-Metadata
* @notice Deploying a LSP8IdentifiableDigitalAsset with name `name_`, symbol `symbol_`, owned by address `newOwner_`
* with tokenId type `tokenIdType_`.
*
* @dev Deploy a `LSP8IdentifiableDigitalAsset` contract and set the tokenId type inside the ERC725Y storage of the contract.
* This will also set the token `name_` and `symbol_` under the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol`.
*
* @param name_ The name of the token
* @param symbol_ The symbol of the token
* @param newOwner_ The owner of the the token-Metadata
* @param tokenIdType_ The type of tokenIds (= NFTs) that this contract will create.
* Available options are: NUMBER = `0`; STRING = `1`; UNIQUE_ID = `2`; HASH = `3`; ADDRESS = `4`.
*
* @custom:warning Make sure the tokenId type provided on deployment is correct, as it can only be set once
* and cannot be changed in the ERC725Y storage after the contract has been deployed.
*/
constructor(
string memory name_,
string memory symbol_,
address newOwner_
) LSP4DigitalAssetMetadata(name_, symbol_, newOwner_) {}
address newOwner_,
uint256 tokenIdType_
) LSP4DigitalAssetMetadata(name_, symbol_, newOwner_) {
LSP4DigitalAssetMetadata._setData(
_LSP8_TOKENID_TYPE_KEY,
abi.encode(tokenIdType_)
);
}

// fallback function

Expand Down Expand Up @@ -190,4 +211,19 @@ abstract contract LSP8IdentifiableDigitalAsset is
super.supportsInterface(interfaceId) ||
LSP17Extendable._supportsInterfaceInERC165Extension(interfaceId);
}

/**
* @inheritdoc LSP4DigitalAssetMetadata
* @dev The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed
* once the identifiable digital asset contract has been deployed.
*/
function _setData(
bytes32 dataKey,
bytes memory dataValue
) internal virtual override {
if (dataKey == _LSP8_TOKENID_TYPE_KEY) {
revert LSP8TokenIdTypeNotEditable();
}
LSP4DigitalAssetMetadata._setData(dataKey, dataValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,13 @@ import {LSP17Extendable} from "../LSP17ContractExtension/LSP17Extendable.sol";
import {LSP2Utils} from "../LSP2ERC725YJSONSchema/LSP2Utils.sol";

// constants
import {_INTERFACEID_LSP8} from "./LSP8Constants.sol";
import {LSP8TokenContractCannotHoldValue} from "./LSP8Errors.sol";
import {_INTERFACEID_LSP8, _LSP8_TOKENID_TYPE_KEY} from "./LSP8Constants.sol";

// errors
import {
LSP8TokenContractCannotHoldValue,
LSP8TokenIdTypeNotEditable
} from "./LSP8Errors.sol";

import {
_LSP17_EXTENSION_PREFIX
Expand Down Expand Up @@ -50,16 +55,35 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is
LSP8IdentifiableDigitalAssetCore,
LSP17Extendable
{
/**
* @dev Initialize a `LSP8IdentifiableDigitalAsset` contract and set the tokenId type inside the ERC725Y storage of the contract.
* This will also set the token `name_` and `symbol_` under the ERC725Y data keys `LSP4TokenName` and `LSP4TokenSymbol`.
*
* @param name_ The name of the token
* @param symbol_ The symbol of the token
* @param newOwner_ The owner of the the token-Metadata
* @param tokenIdType_ The type of tokenIds (= NFTs) that this contract will create.
* Available options are: NUMBER = `0`; STRING = `1`; UNIQUE_ID = `2`; HASH = `3`; ADDRESS = `4`.
*
* @custom:warning Make sure the tokenId type provided on deployment is correct, as it can only be set once
* and cannot be changed in the ERC725Y storage after the contract has been initialized.
*/
function _initialize(
string memory name_,
string memory symbol_,
address newOwner_
) internal virtual override onlyInitializing {
address newOwner_,
uint256 tokenIdType_
) internal virtual onlyInitializing {
LSP4DigitalAssetMetadataInitAbstract._initialize(
name_,
symbol_,
newOwner_
);

LSP4DigitalAssetMetadataInitAbstract._setData(
_LSP8_TOKENID_TYPE_KEY,
abi.encode(tokenIdType_)
);
}

// fallback function
Expand Down Expand Up @@ -190,4 +214,19 @@ abstract contract LSP8IdentifiableDigitalAssetInitAbstract is
super.supportsInterface(interfaceId) ||
LSP17Extendable._supportsInterfaceInERC165Extension(interfaceId);
}

/**
* @inheritdoc LSP4DigitalAssetMetadataInitAbstract
* @dev The ERC725Y data key `_LSP8_TOKENID_TYPE_KEY` cannot be changed
* once the identifiable digital asset contract has been deployed.
*/
function _setData(
bytes32 dataKey,
bytes memory dataValue
) internal virtual override {
if (dataKey == _LSP8_TOKENID_TYPE_KEY) {
revert LSP8TokenIdTypeNotEditable();
}
LSP4DigitalAssetMetadataInitAbstract._setData(dataKey, dataValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol";
import {
LSP8IdentifiableDigitalAsset,
LSP4DigitalAssetMetadata,
ERC725YCore
} from "../LSP8IdentifiableDigitalAsset.sol";
import {
Expand Down Expand Up @@ -74,8 +73,9 @@ abstract contract LSP8CompatibleERC721 is
constructor(
string memory name_,
string memory symbol_,
address newOwner_
) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {}
address newOwner_,
uint256 tokenIdType_
) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) {}

/**
* @inheritdoc LSP8IdentifiableDigitalAsset
Expand Down Expand Up @@ -407,12 +407,12 @@ abstract contract LSP8CompatibleERC721 is
}

/**
* @inheritdoc LSP4DigitalAssetMetadata
* @inheritdoc LSP8IdentifiableDigitalAsset
*/
function _setData(
bytes32 key,
bytes memory value
) internal virtual override(LSP4DigitalAssetMetadata, ERC725YCore) {
) internal virtual override(LSP8IdentifiableDigitalAsset, ERC725YCore) {
super._setData(key, value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
} from "../../LSP4DigitalAssetMetadata/LSP4Compatibility.sol";
import {
LSP8IdentifiableDigitalAssetInitAbstract,
LSP4DigitalAssetMetadataInitAbstract,
ERC725YCore
} from "../LSP8IdentifiableDigitalAssetInitAbstract.sol";
import {
Expand Down Expand Up @@ -75,12 +74,14 @@ abstract contract LSP8CompatibleERC721InitAbstract is
function _initialize(
string memory name_,
string memory symbol_,
address newOwner_
address newOwner_,
uint256 tokenIdType_
) internal virtual override onlyInitializing {
LSP8IdentifiableDigitalAssetInitAbstract._initialize(
name_,
symbol_,
newOwner_
newOwner_,
tokenIdType_
);
}

Expand Down Expand Up @@ -415,15 +416,15 @@ abstract contract LSP8CompatibleERC721InitAbstract is
}

/**
* @inheritdoc LSP4DigitalAssetMetadataInitAbstract
* @inheritdoc LSP8IdentifiableDigitalAssetInitAbstract
*/
function _setData(
bytes32 key,
bytes memory value
)
internal
virtual
override(LSP4DigitalAssetMetadataInitAbstract, ERC725YCore)
override(LSP8IdentifiableDigitalAssetInitAbstract, ERC725YCore)
{
super._setData(key, value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ contract LSP8CompatibleERC721Mintable is LSP8CompatibleERC721 {
constructor(
string memory name_,
string memory symbol_,
address newOwner_
) LSP8CompatibleERC721(name_, symbol_, newOwner_) {}
address newOwner_,
uint256 tokenIdType_
) LSP8CompatibleERC721(name_, symbol_, newOwner_, tokenIdType_) {}

/**
* @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ contract LSP8CompatibleERC721MintableInit is
function initialize(
string memory name_,
string memory symbol_,
address newOwner_
address newOwner_,
uint256 tokenIdType_
) external virtual initializer {
LSP8CompatibleERC721MintableInitAbstract._initialize(
name_,
symbol_,
newOwner_
newOwner_,
tokenIdType_
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ contract LSP8CompatibleERC721MintableInitAbstract is
function _initialize(
string memory name_,
string memory symbol_,
address newOwner_
address newOwner_,
uint256 tokenIdType_
) internal virtual override onlyInitializing {
LSP8CompatibleERC721InitAbstract._initialize(name_, symbol_, newOwner_);
LSP8CompatibleERC721InitAbstract._initialize(
name_,
symbol_,
newOwner_,
tokenIdType_
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ contract LSP8Mintable is LSP8IdentifiableDigitalAsset, ILSP8Mintable {
constructor(
string memory name_,
string memory symbol_,
address newOwner_
) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_) {}
address newOwner_,
uint256 tokenIdType_
) LSP8IdentifiableDigitalAsset(name_, symbol_, newOwner_, tokenIdType_) {}

/**
* @notice Minting tokenId `tokenId` for address `to` with the additional data `data` (Note: allow non-LSP1 recipient is set to `force`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ contract LSP8MintableInit is LSP8MintableInitAbstract {
function initialize(
string memory name_,
string memory symbol_,
address newOwner_
address newOwner_,
uint256 tokenIdType_
) external virtual initializer {
LSP8MintableInitAbstract._initialize(name_, symbol_, newOwner_);
LSP8MintableInitAbstract._initialize(
name_,
symbol_,
newOwner_,
tokenIdType_
);
}
}
Loading

0 comments on commit 67cb333

Please sign in to comment.