Skip to content

Latest commit

 

History

History
722 lines (449 loc) · 35.5 KB

LSP-8-IdentifiableDigitalAsset.md

File metadata and controls

722 lines (449 loc) · 35.5 KB
lip title author discussions-to status type created requires
8
Identifiable Digital Asset
Claudio Weck <claudio@fanzone.media>, Fabian Vogelsteller <fabian@lukso.network>, Matthew Stevens <@mattgstevens>, Ankit Kumar <@ankitkumar9018>
Review
LSP
2021-09-02
ERC165, ERC725Y, LSP1, LSP2, LSP4, LSP17

Simple Summary

The LSP8 Identifiable Digital Asset Standard defines a standard interface for uniquely identifiable digital assets. It allows tokens to be uniquely traded and given with metadata using ERC725Y and LSP4.

Abstract

This standard defines a digital asset standard that can represent non-fungible tokens (NFTs).

Key functionalities of this asset standard include:

  • Flexible Asset Representation: The tokenId defined in the standard is bytes32 allowing different tokenId identification including numbers, contract addresses, and any other unique identifiers (e.g: serial numbers, NFTs with unique names, hash values, etc...).

  • Dynamic Information Attachment: Leverages ERC725Y to add generic information to the asset and to each tokenId even post-deployment according to the LSP4-DigitalAssetMetadata standard.

  • Secure Transfers: By checking whether the recipient is capable of handling the asset before the actual transfer, it avoids loss and transfer of tokens to uncontrolled addresses.

  • Transfer Interaction: Notifies the operator, sender, and the recipient about the transfer, allowing users to be informed about the incoming asset and decide how to react accordingly (e.g., denying the token, forwarding it, etc.).

  • Future-Proof Functionalities: Through [LSP17-ContractExtension], allows the asset to be extended and support new standardized functions and interface IDs over time.

  • Asset Flexibility and Discoverability: Offers several flexible features, such as batch transfers and the ability to add several operators, as well as the ability to discover them.

Motivation

The motivation for developing this new digital asset standard can be organized into several key points, each showing a specific limitation of current token standards:

  • Limited Asset Representation: Current NFT standards represent tokenId as a simple uint256 type with no indication about how to parse it, making the NFT very limited.

  • Limited Asset Metadata: Current token standards offer limited metadata attachment capabilities, typically confined to basic elements like name, symbol, and tokenURI. This limitation is particularly restrictive for assets that require verifiable, on-chain metadata – such as details about creators, the community behind the token, or dynamic attributes that allow an NFT to evolve.

  • No Interaction and Notification: Traditional token standards lack in terms of interaction, particularly in notifying recipients about transfers. As a result, users cannot be unaware of incoming tokens and lose the opportunity to respond, for example, react to transfers, whether to deny, accept, or forward the tokens.

  • Limited Functionalities: Many tokens are confined to the functionalities they possess at deployment, making them rigid and unable to adapt to new requirements or standards.

  • Risk of asset loss: A common issue with current assets is the risk of loss due to transfers to incorrect or uncontrolled addresses as these standards does not check whether the recipient is able to handle the asset or not.

  • Limited Features: The limitation of having only one operator and the absence of batch transfer capabilities or even the discoverability of tokens a user own restricts and provide bad user experience. Users need to rely on centralized indexers to know which tokens they own, need to do several transactions to do a batch of transfers, and cannot have more than one operator.

Specification

ERC165 interface id: 0x3a271706

The LSP8 interface ID is calculated as the XOR of the LSP8 interface (see interface cheat-sheet below) and the LSP17 Extendable interface ID.

Methods

totalSupply

function totalSupply() external view returns (uint256);

Returns the number of existing tokens.

Returns: uint256 the number of existing tokens.

balanceOf

function balanceOf(address tokenOwner) external view returns (uint256);

Returns the number of tokens owned by tokenOwner.

Parameters:

  • tokenOwner the address to query.

Returns: uint256 the number of tokens owned by this address.

tokenOwnerOf

function tokenOwnerOf(bytes32 tokenId) external view returns (address);

Returns the tokenOwner address of the tokenId token.

Parameters:

  • tokenId the token to query.

Requirements:

  • tokenId must exist

Returns: address the token owner.

tokenIdsOf

function tokenIdsOf(address tokenOwner) external view returns (bytes32[] memory);

Returns the list of tokenIds for the tokenOwner address.

Parameters:

  • tokenOwner the address to query.

Returns: bytes32[] the list of owned token ids.

authorizeOperator

function authorizeOperator(address operator, bytes32 tokenId, bytes memory operatorNotificationData) external;

Makes operator address an operator of tokenId.

MUST emit an OperatorAuthorizationChanged event.

Parameters:

  • operator the address to authorize as an operator.
  • tokenId the token to enable operator status to.
  • operatorNotificationData the data to send when notifying the operator via LSP1.

Requirements:

  • tokenId must exist.
  • operator cannot be already authorized for the same tokenId.
  • caller must be current tokenOwner of tokenId.
  • operator cannot be calling address.
  • operator cannot be the zero address.

LSP1 Hooks:

  • If the operator is a contract that supports LSP1 interface, it SHOULD call operator's [universalReceiver(...)] function with the parameters below:

    • typeId: keccak256('LSP8Tokens_OperatorNotification') > 0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970
    • data: The data sent SHOULD be abi encoded and contain the tokenOwner (address), tokenId (bytes32), isAuthorized (boolean), and the operatorNotificationData (bytes) respectively.

revokeOperator

function revokeOperator(address operator, bytes32 tokenId, bool notify, bytes memory operatorNotificationData) external;

Removes operator address as an operator of tokenId.

MUST emit a OperatorRevoked event.

Parameters:

  • operator the address to revoke as an operator.
  • tokenId the token to disable operator status to.
  • notify the boolean indicating whether to notify the operator via LSP1 or not.
  • operatorNotificationData the data to send when notifying the operator via LSP1.

Requirements:

  • tokenId must exist.
  • operator must be authorized for tokenId.
  • caller must be current tokenOwner or the operator of tokenId.
  • operator cannot be the zero address.

LSP1 Hooks:

  • If the notify boolean is set to true and the operator is a contract that supports LSP1 interface, it SHOULD call operator's [universalReceiver(...)] function with the parameters below:

    • typeId: keccak256('LSP8Tokens_OperatorNotification') > 0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970
    • data: The data sent SHOULD be abi encoded and contain the tokenOwner (address), tokenId (bytes32), isAuthorized (boolean), and the operatorNotificationData (bytes) respectively.

isOperatorFor

function isOperatorFor(address operator, bytes32 tokenId) external view returns (bool);

Returns whether operator address is an operator of tokenId. Operators can send and burn tokens on behalf of their owners. The tokenOwner is their own operator.

Parameters:

  • operator the address to query operator status for.
  • tokenId the token to query.

Requirements:

  • tokenId must exist

Returns: bool, TRUE if operator address is an operator of tokenId, FALSE otherwise.

getOperatorsOf

function getOperatorsOf(bytes32 tokenId) external view returns (address[] memory);

Returns all operator addresses of tokenId.

Parameters:

  • tokenId the token to query.

Requirements:

  • tokenId must exist

Returns: address[] the list of operators.

transfer

function transfer(address from, address to, bytes32 tokenId, bool force, bytes memory data) external;

Transfers tokenId token from from to to. The force parameter will be used when notifying the token sender and receiver.

MUST emit a Transfer event when transfer was successful. MUST emit a OperatorRevoked to clear the past operators.

Parameters:

  • from the sending address.
  • to the receiving address.
  • tokenId the token to transfer.
  • force when set to TRUE, to may be any address; when set to FALSE to must be a contract that supports LSP1 UniversalReceiver and successfully processes a call to universalReceiver(bytes32 typeId, bytes memory data).
  • data additional data the caller wants included in the emitted event, and sent in the hooks to from and to addresses.

Requirements:

  • from cannot be the zero address.
  • to cannot be the zero address.
  • tokenId token must be owned by from.
  • If the caller is not from, it must be an operator of tokenId.

LSP1 Hooks:

  • If the token sender is a contract that supports LSP1 interface, it SHOULD call the token sender's [universalReceiver(...)] function with the parameters below:

    • typeId: keccak256('LSP8Tokens_SenderNotification') = 0xb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab00
    • data: The data sent SHOULD be ABI encoded and contain the caller (address), sender (address), receiver (address), tokenId (bytes32) and the data (bytes) respectively.

  • If the token recipient is a contract that supports LSP1 interface, it SHOULD call the token recipient's [universalReceiver(...)] function with the parameters below:

    • typeId: keccak256('LSP8Tokens_RecipientNotification') = 0x0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d
    • data: The data sent SHOULD be ABI encoded and contain the caller (address), sender (address), receiver (address), tokenId (bytes32) and the data (bytes) respectively.

Note: LSP1 Hooks MUST be implemented in any type of token transfer (mint, transfer, burn, transferBatch).

transferBatch

function transferBatch(address[] memory from, address[] memory to, bytes32[] memory tokenId, bool[] memory force, bytes[] memory data) external;

Transfers many tokens based on the list from, to, tokenId. If any transfer fails, the call will revert.

MUST emit a Transfer event for each transferred token. MUST emit a OperatorRevoked to clear the past operators for each transferred token.

Parameters:

  • from the list of sending addresses.
  • to the list of receiving addresses.
  • tokenId the list of tokens to transfer.
  • force when set to TRUE, to may be any address; when set to FALSE to must be a contract that supports LSP1 UniversalReceiver and successfully processes a call to universalReceiver(bytes32 typeId, bytes memory data).
  • data the list of additional data the caller wants included in the emitted event, and sent in the hooks to from and to addresses.

Requirements:

  • from, to, tokenId, force, and data lists are the same length.
  • no values in from can be the zero address.
  • no values in to can be the zero address.
  • each tokenId token must be owned by from.
  • If the caller is not from, it must be an operator of each tokenId.

getDataForTokenId

function getDataForTokenId(bytes32 tokenId, bytes32 dataKey) external view returns (bytes memory dataValue)

Gets the data set for the given data key for a specific tokenId.

Parameters:

  • tokenId: the tokenId to retrieve data for.
  • dataKey: the data key which value to retrieve.

Returns: bytes , The data for the requested data key.

getDataBatchForTokenIds

function getDataBatchForTokenIds(bytes32[] memory tokenIds, bytes32[] memory dataKeys) external view returns(bytes[] memory dataValues)

Gets array of data at multiple given data keys for given tokenIds.

Parameters:

  • tokenIds: the tokenIds to retrieve data for.
  • dataKeys: the data keys which values to retrieve.

Returns: bytes[] , array of data values for the requested data keys.

setDataForTokenId

function setDataForTokenId(bytes32 tokenId, bytes32 dataKey, bytes memory dataValue) external;

Sets data as bytes in the storage for a single data key for a tokenId.

Parameters:

  • tokenId: the tokenId to set data for.
  • dataKey: the data key which value to set.
  • dataValue: the data to store.

Requirements:

  • MUST only be called by the current owner of the contract.

Triggers Event: TokenIdDataChanged

setDataBatchForTokenIds

function setDataBatchForTokenIds(bytes32[] memory tokenIds, bytes32[] memory dataKeys, bytes[] memory dataValues) external

Sets array of data at multiple data keys for multiple tokenIds.

Parameters:

  • tokenIds: the tokenIds to set data for.
  • dataKeys: the data keys which values to set.
  • dataValues: the array of bytes to set.

Requirements:

  • Array parameters MUST have the same length.
  • MUST only be called by the current owner of the contract.

Triggers Event: TokenIdDataChanged on each iteration

batchCalls

function batchCalls(bytes[] memory data) external returns (bytes[] memory results);

Enables the execution of a batch of encoded function calls on the current contract in a single transaction, provided as an array of bytes.

MUST use the [DELEGATECALL] opcode to execute each call in the same context of the current contract.

Parameters:

  • data: an array of encoded function calls to be executed on the current contract.

The data field can be:

  • an array of ABI-encoded function calls such as an array of ABI-encoded transfer, authorizeOperator, balanceOf or any LSP8 functions.
  • an array of bytes which will resolve to the fallback function to be checked for an extension.

Requirements:

  • MUST NOT be payable.

Returns: results , an array of bytes containing the return values of each executed function call.

Events

TokenIdDataChanged

event TokenIdDataChanged(bytes32 indexed tokenId, bytes32 indexed dataKey, bytes dataValue);

MUST be emitted when dataValue is set as a value for dataValue for the tokenId.

Transfer

event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data);

MUST be emitted when tokenId token is transferred from from to to.

OperatorAuthorizationChanged

event OperatorAuthorizationChanged(address indexed operator, address indexed tokenOwner, bytes32 indexed tokenId, bytes operatorNotificationData);

MUST be emitted when tokenOwner enables operator for tokenId.

OperatorRevoked

event OperatorRevoked(address indexed operator, address indexed tokenOwner, bytes32 indexed tokenId, bool notified, bytes operatorNotificationData);

MUST be emitted when tokenOwner disables operator for tokenId.

Metadata

The LSP8-IdentifiableDigitalAsset expect the usage of LSP4-DigitalAsset-Metadata to store the metadata of the asset, as well as defining standard data keys to store LSP8 specific metadata.

Data keys such as LSP8TokenIdFormat or LSP4Metadata can be stored:

For instance, to set metadata for each specific tokenId, set the LSP4Metadata data key for each tokenId using setDataForTokenId(..) function.

ERC725Y Data Keys

LSP8TokenIdFormat

{
  "name": "LSP8TokenIdFormat",
  "key": "0xf675e9361af1c1664c1868cfa3eb97672d6b1a513aa5b81dec34c9ee330e818d",
  "keyType": "Singleton",
  "valueType": "uint256",
  "valueContent": "Number"
}

The LSP8-IdentifiableDigitalAsset standard, defines each tokenId as bytes32, this data key describes the format of the tokenId and how to parse it and can take one of the following values described in the table below.

Value Format Representation Description
0 uint256 Number each NFT is parsed as a unique number.
1 string String each NFT is parsed as a unique name (as a short UTF-8 encoded string, no more than 32 characters long)
2 address Smart Contract each NFT is parsed as its own smart contract that can hold its own logic and metadata (e.g ERC725Y compatible).
3 bytes32 Unique Bytes each NFT is parsed as a 32 bytes long unique identifier.
4 bytes32 Hash Digest each NFT is parsed as a 32 bytes hash digest. This can be used as the hash of a very long string representing the tokenId.

The standard allows for Mixed formats. In a mixed format scenario, while there's a default format for the collection, individual tokenIds can have unique formats. This concept is represented with special values ranging from 100 to 104.

Value Format Description
100 Mixed with default as uint256 Default NFT is parsed as a unique number with querying the LSP8TokenIdFormat for each tokenId.
101 Mixed with default as string Default NFT is parsed as a unique name (as a short UTF-8 encoded string, no more than 32 characters long) with querying the LSP8TokenIdFormat for each tokenId.
102 Mixed with default as address Default NFT is parsed as its own smart contract that can hold its own logic and metadata (e.g ERC725Y compatible) with querying the LSP8TokenIdFormat for each tokenId. .
103 Mixed with default as bytes32 unique bytes Default NFT is parsed as a 32 bytes long unique identifier with querying the LSP8TokenIdFormat for each tokenId.
104 Mixed with default as bytes32 hash digest Default NFT is parsed as a 32 bytes hash digestwith querying the LSP8TokenIdFormat for each tokenId.

Setting and Querying Token ID Formats:

  • Setting a tokenId format: Use setDataForTokenId(..) to set the LSP8TokenIdFormat for a specific tokenId.
  • Querying a tokenId format: Use getDataForTokenId(..) to retrieve the LSP8TokenIdFormat for a specific tokenId.

Example Scenario:

Given a collection where the LSP8TokenIdFormat is set to 101, indicating that tokenIds are primarily formatted as strings. However, for a specific tokenId that needs to be represented as a number, its LSP8TokenIdFormat would be set to 100 using setDataForTokenId(..).

This change signifies that while the default format for the collection is string (101), this particular tokenId deviates from the norm and is formatted as a number (100), exemplifying the mixed format approach.

If the value for the LSP8TokenIdFormat for a specific tokenId is 0, it means the value is non-set (default value), and should not be treated as LSP8TokenIdFormat = 0 (parsing as a number).

A tokenId is always represented as a bytes32 value. Depending on the tokenId formats defined above, the padding of the bytes32 value is different.

LSP8TokenIdFormat Left padded Right padded Padding rule to convert to bytes32
0 or 100 - uint256 - Number ✔️ For tokenId number 5 -> 0x0000000000000000000000000000000000000000000000000000000000000005
1 or 101 - string - String ✔️ For tokenId my-nft -> 0x6d792d6e66740000000000000000000000000000000000000000000000000000 (each character encoded as UTF-8 hex)
2 or 102 - address - Smart Contract ✔️ For tokenId metadata contract at address 0x8ae2dD3E422530b5c2FC1061e6b5f43f5677033f -> 0x0000000000000000000000008ae2dD3E422530b5c2FC1061e6b5f43f5677033f
3 or 103 - bytes32 - Unique Bytes ✔️ For any bytes less than 32 bytes like tokenId 0xaabbccddee -> 0xaabbccddee000000000000000000000000000000000000000000000000000000
4 or 104 - bytes32 - Hash Digest No padding applies, since the hash digest is always 32 bytes. For instance for tokenId keccak256('My NFT') -> 0x262a8c3566f2abe9247c206cf8d622e0a44ac99a7d54c23e212de32181cf185f

This value must be padded according to the padding rules specified in the table above to generate the bytes32 tokenId that will be passed as parameter to the functions below:

Requirements:

  • This MUST NOT be changeable, and set only during initialization of the LSP8 token contract.

LSP8TokenMetadataBaseURI

{
  "name": "LSP8TokenMetadataBaseURI",
  "key": "0x1a7628600c3bac7101f53697f48df381ddc36b9015e7d7c9c5633d1252aa2843",
  "keyType": "Singleton",
  "valueType": "bytes",
  "valueContent": "VerifiableURI"
}

This data key defines the base URI for the metadata of each tokenIds present in the LSP8 contract.

The complete URI that points to the metadata of a specific tokenId MUST be formed by concatenating this base URI with the tokenId. As {LSP8TokenMetadataBaseURI}{tokenId}. The protocol can be http, https, ipfs and so on similar to other VerifiableURI values.

⚠️ For the tokenId format address (2), the tokenId part SHOULD be in lower case to make it unique and avoid interfaces to have to know multiple versions of the URI with different casings (e.g: http://mybase.uri/0x43fb7ab43a3a32f1e2d5326b651bbae713b02429, or http://mybase.uri/0x43FB7AB43A3A32F1E2D5326B651BBAE713B02429, or http://mybase.uri/0x43fB7aB43A3a32F1E2d5326b651BBAe713B02429).

⚠️ Similarly for the bytes32 version of tokenId format (3 and 4), the tokenId part MUST be lowercase.

⚠️ However, for the string version of the tokenId (2), the tokenId part MUST be in the same casing as defined by the string that represents the tokenId. Otherwise, changing the casing is equivalent to using a different tokenId. The tokenId is not limited in casing but needs to contain valid UTF-8 and needs to be encoded using url-encoding i.e. encodeURI(). For example: A tokenId containing something/Veryሴ⍅ Cool should be encoded as something/Very%E1%88%B4%E2%8D%85%20Cool as in the following example.

> baseURL + encodeURI("something/Very\u1234\u2345 Cool")
'https://mybase.uri/something/Very%E1%88%B4%E2%8D%85%20Cool'
  • LSP8TokenIdFormat 0 (= uint256)
    e.g. https://mybase.uri/1234
  • LSP8TokenIdFormat 1 (= string)
    e.g. https://mybase.uri/name-of-the-nft
  • LSP8TokenIdFormat 2 (= address)
    e.g. https://mybase.uri/0x43fb7ab43a3a32f1e2d5326b651bbae713b02429
  • LSP8TokenIdFormat 3 or 4 (= bytes32)
    e.g. https://mybase.uri/e5fe3851d597a3aa8bbdf8d8289eb9789ca2c34da7a7c3d0a7c442a87b81d5c2

Some Base URIs could be alterable, for example in the case of NFTs that need their metadata to change over time.

ERC725Y Data Keys of external contract for tokenID format 2 (address)

When the LSP8 contract uses the tokenId format 2 (= address), each tokenId minted is an ERC725Y smart contract that can have its own metadata. We refer to this contract as the tokenId metadata contract.

In this case, each tokenId present in the LSP8 contract references another ERC725Y contract.

The tokenId metadata contract SHOULD contain the following ERC725Y data key in its storage.

LSP8ReferenceContract

This data key stores the address of the LSP8 contract that minted this specific tokenId (defined by the address of the tokenId metadata contract).

It is a reference back to the LSP8 Collection it comes from.

If the LSP8ReferenceContract data key is set, it MUST NOT be changeable.

{
  "name": "LSP8ReferenceContract",
  "key": "0x708e7b881795f2e6b6c2752108c177ec89248458de3bf69d0d43480b3e5034e6",
  "keyType": "Singleton",
  "valueType": "(address,bytes32)",
  "valueContent": "(Address,bytes32)"
}

LSP8 TokenId Metadata

The metadata for a specific of a uniquely identifiable digital asset (when this tokenId is represented by its own ERC725Y contract) can follow the JSON format of the LSP4Metadata data key.

This JSON format includes an "attributes" field to describe unique properties of the tokenId.

Rationale

There should be a base token standard that allows tracking unique assets for the LSP ecosystem of contracts, which will allow common tooling and clients to be built. Existing tools and clients that expect ERC721 can be made to work with this standard by using "compatibility" contract extensions that match the desired interface.

Token Identifier

Every token is identified by a unique bytes32 tokenId which SHALL NOT change for the life of the contract. The pair (contract address, uint256 tokenId) is globally unique and a fully-qualified identifier for a specific asset on-chain. While some implementations may find it convenient to use the tokenId as an uint256 that is incremented for each minted token, callers SHALL NOT assume that tokenIds have any specific pattern to them, and MUST treat the tokenId as a "black box". Also note that a tokenId MAY become invalid (when burned).

The choice of bytes32 tokenId allows a wide variety of applications including numbers, contract addresses, and hashed values (ie. serial numbers).

Operators

To clarify the ability of an address to access tokens from another address, operator was chosen as the name for functions, events and variables in all cases. This is originally from ERC777 standard and replaces the approve functionality from ERC721.

Token Transfers

There is only one transfer function, which is aware of operators. This deviates from ERC721 and ERC777 which added functions specifically for the token owner to use, and for those with access to tokens. By having a single function to call this makes it simple to move tokens, and the caller will be exposed in the Transfer event as an indexed value.

Usage of hooks

When a token is changing owners (minting, transferring, burning) an attempt is made to notify the token sender and receiver using LSP1 UniversalReceiver interface. The implementation uses _notifyTokenSender and _notifyTokenReceiver as the internal functions to process this.

The force parameter sent during function transfer SHOULD be used when notifying the token receiver, to determine if it must support LSP1 UniversalReceiver. This is used to prevent accidental token transfers, which may results in lost tokens: non-contract addresses could be a copy paste issue, contracts not supporting LSP1 UniversalReceiver might not be able to move tokens.

Implementation

An implementation can be found in the lukso-network/lsp-smart-contracts.

ERC725Y JSON Schema LSP8IdentifiableDigitalAsset:

[
  {
    "name": "LSP8TokenIdFormat",
    "key": "0xf675e9361af1c1664c1868cfa3eb97672d6b1a513aa5b81dec34c9ee330e818d",
    "keyType": "Singleton",
    "valueType": "uint256",
    "valueContent": "Number"
  },
  {
    "name": "LSP8TokenMetadataBaseURI",
    "key": "0x1a7628600c3bac7101f53697f48df381ddc36b9015e7d7c9c5633d1252aa2843",
    "keyType": "Singleton",
    "valueType": "bytes",
    "valueContent": "VerifiableURI"
  },
  {
    "name": "LSP8ReferenceContract",
    "key": "0x708e7b881795f2e6b6c2752108c177ec89248458de3bf69d0d43480b3e5034e6",
    "keyType": "Singleton",
    "valueType": "(address,bytes32)",
    "valueContent": "(Address,bytes32)"
  }
]

Interface Cheat Sheet

interface ILSP8 is /* IERC165 */ {

    // ERC173

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);


    function owner() external view returns (address);

    function transferOwnership(address newOwner) external; // onlyOwner

    function renounceOwnership() external; // onlyOwner


    // ERC725Y

    event DataChanged(bytes32 indexed dataKey, bytes dataValue);


    function getData(bytes32 dataKey) external view returns (bytes memory value);

    function setData(bytes32 dataKey, bytes memory value) external; // onlyOwner

    function getDataBatch(bytes32[] memory dataKeys) external view returns (bytes[] memory values);

    function setDataBatch(bytes32[] memory dataKeys, bytes[] memory values) external; // onlyOwner


    // LSP8

    event Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data);

    event OperatorAuthorizationChanged(address indexed operator, address indexed tokenOwner, bytes32 indexed tokenId, bytes operatorNotificationData);

    event OperatorRevoked(address indexed operator, address indexed tokenOwner, bytes32 indexed tokenId, bool notified, bytes operatorNotificationData);

    event TokenIdDataChanged(bytes32 indexed tokenId, bytes32 indexed dataKey, bytes dataValue);


    function getDataForTokenId(bytes32 tokenId, bytes32 dataKey) external view returns (bytes memory dataValue);

    function setDataForTokenId(bytes32 tokenId, bytes32 dataKey, bytes memory dataValue) external; // onlyOwner

    function getDataBatchForTokenIds(bytes32[] memory tokenIds, bytes32[] memory dataKeys) external view returns (bytes[] memory dataValues);

    function setDataBatchForTokenIds(bytes32[] memory tokenIds, bytes32[] memory dataKeys, bytes[] memory dataValues) external; // onlyOwner


    function totalSupply() external view returns (uint256);

    function balanceOf(address tokenOwner) external view returns (uint256);

    function tokenOwnerOf(bytes32 tokenId) external view returns (address);

    function tokenIdsOf(address tokenOwner) external view returns (bytes32[] memory);

    function authorizeOperator(address operator, bytes32 tokenId, bytes memory operatorNotificationData) external;

    function revokeOperator(address operator, bytes32 tokenId, bool notify, bytes memory operatorNotificationData) external;

    function isOperatorFor(address operator, bytes32 tokenId) external view returns (bool);

    function getOperatorsOf(bytes32 tokenId) external view returns (address[] memory);

    function transfer(address from, address to, bytes32 tokenId, bool force, bytes memory data) external;

    function transferBatch(address[] memory from, address[] memory to, bytes32[] memory tokenId, bool[] memory force, bytes[] memory data) external;

    function batchCalls(bytes[] memory data) external returns (bytes[] memory results);
}

Copyright

Copyright and related rights waived via CC0.