From 7928ab7de993dc0a215977e2bf7627b448655074 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Wed, 9 Oct 2024 12:21:56 +0100 Subject: [PATCH 1/6] (wip): improve digital assets sections in Contracts --- docs/contracts/overview/DigitalAssets.md | 40 ++++------- .../overview/IdentifiableDigitalAssets.md | 71 +++++++++++++++++-- docs/standards/tokens/introduction.md | 4 ++ 3 files changed, 81 insertions(+), 34 deletions(-) diff --git a/docs/contracts/overview/DigitalAssets.md b/docs/contracts/overview/DigitalAssets.md index 4290b8ae5..cdde3df4d 100644 --- a/docs/contracts/overview/DigitalAssets.md +++ b/docs/contracts/overview/DigitalAssets.md @@ -6,19 +6,25 @@ sidebar_position: 4 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -# Digital Assets +# LSP7 Digital Asset -The **Digital Asset (Token and NFT 2.0)** contracts are the newest advanced version of the existing token standards. They come with many features that enhance the security and the overall user experience and compatibility with [ERC725Accounts](/standards/accounts/lsp0-erc725account.md) and [Universal Receivers](/standards/accounts/lsp1-universal-receiver.md). +The **LSP7 Digital Asset** contract is the newest advanced version of the existing ERC token standards, such as ERC20 and ERC1155. -## Comparisons with ERC20 / ERC721 +They come with many features that enhance the security and the overall user experience and compatibility with [ERC725Accounts](/standards/accounts/lsp0-erc725account.md) and [Universal Receivers](/standards/accounts/lsp1-universal-receiver.md). -:::danger beware +An LSP7 Digital Asset uses -The LSP7 compatible with ERC20 contracts and LSP8 compatible with ERC721 contracts are being deprecated and will be deleted from [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) repository. However if you want to still use/maintain them, they will remain available in the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). +## Comparisons with ERC20 + +:::danger Deprecation of `LSP7CompatibleERC20` + +The `LSP7CompatibleERC20` contracts have been deprecated and deleted from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package since version `0.15.0`, because of their unsafe nature and [security considerations (See PR #845 for more details)](https://github.com/lukso-network/lsp-smart-contracts/pull/845#issuecomment-1888671461). + +They are not recommended to be used. However, if you want to still use them, they remain available in the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). ::: -The interfaces of LSP7 and LSP8 have some differences compared to ERC20 and ERC721. Their functions are simpler, more straight forward and unified. +The interface of LSP7 has some differences compared to ERC20. **Similar function names** @@ -46,28 +52,6 @@ The table below highlights these differences: approve(address,uint256) authorizeOperator(address,uint256) - - Description - ERC721 - LSP8 - - - Transferring tokens as an owner. - - transferFrom(address,address,uint256)
- safeTransferFrom(address,address,uint256)
- safeTransferFrom(address,address,uint256,bytes) - - transfer(address,address,bytes32,bool,bytes) - - - Transferring tokens as an operator. - - - Approving an operator to spend tokens on behalf of the owner. - approve(address,uint256) - authorizeOperator(address,bytes32) - In ERC20 the function `transfer(address,uint256)` is used to transfer ERC20 tokens from the caller, this can only be used by the holder of the ERC20 tokens. There is also `transferFrom(address,address,uint256)` which can also be used by the ERC20 tokens operator. diff --git a/docs/contracts/overview/IdentifiableDigitalAssets.md b/docs/contracts/overview/IdentifiableDigitalAssets.md index de6d4a2d6..4d95e5ace 100644 --- a/docs/contracts/overview/IdentifiableDigitalAssets.md +++ b/docs/contracts/overview/IdentifiableDigitalAssets.md @@ -6,20 +6,79 @@ sidebar_position: 5 import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -## LSP8 Identifiable Digital Asset +# LSP8 Identifiable Digital Asset -The **LSP8IdentifiableDigitalAsset** contract represents identifiable digital assets (NFTs) that can be uniquely traded and given metadata using the **[ERC725Y Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md#erc725y)**. +The **LSP8 Identifiable Digital Asset** contract is the newest advanced version of the existing ERC NFT standards, such as ERC721. + +LSP8 identifiable digital assets represent **N**on **F**ungible **T**okens (NFTs) that can be uniquely traded. + +and given metadata using the **[ERC725Y Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md#erc725y)**. Each NFT is identified with a tokenId, based on **[ERC721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol)**. A **bytes32** value is used for tokenId to allow many uses of token identification, including numbers, contract addresses, and hashed values (i.e., serial numbers). -### Setting metadata for one or multiple tokenIds +## Comparisons with ERC721 + +:::danger Deprecation of `LSP8CompatibleERC721` + +The `LSP8CompatibleERC721` contracts have been deprecated and deleted from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package since version `0.15.0`, because of their unsafe nature and [security considerations (See PR #845 for more details)](https://github.com/lukso-network/lsp-smart-contracts/pull/845#issuecomment-1888671461). + +They are not recommended to be used. However, if you want to still use them, they remain available in the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). + +::: + +The interface of LSP8 has some differences compared to ERC721. + +**Similar function names** + +Both functions in LSP7 and LSP8 have the same name (`transfer`) to transfer assets. This is easier compared to ERC20 and ERC721 that use different naming (`transfer` for ERC20 vs `transferFrom` in ERC721 to transfer tokens as the token owner). + +The table below highlights these differences: + + + + + + + + + + + + + + + + + + + + +
DescriptionERC721LSP8
Transferring tokens as an owner. + transferFrom(address,address,uint256)
+ safeTransferFrom(address,address,uint256)
+ safeTransferFrom(address,address,uint256,bytes) +
transfer(address,address,bytes32,bool,bytes)
Transferring tokens as an operator.
Approving an operator to spend tokens on behalf of the owner.approve(address,uint256)authorizeOperator(address,bytes32)
+ +In ERC20 the function `transfer(address,uint256)` is used to transfer ERC20 tokens from the caller, this can only be used by the holder of the ERC20 tokens. There is also `transferFrom(address,address,uint256)` which can also be used by the ERC20 tokens operator. + +In comparison ERC721 has: + +- `safeTransferFrom(address,address,uint256,bytes)` +- `safeTransferFrom(address,address,uint256)` +- `transferFrom(address,address,uint256)` + +All of the above functions can be used by both the owner of the token id or by the operator of the token id in order to transfer the ERC721 token. To be mentioned, both functions `safeTransferFrom(...)` have a hook that calls the recipient contract. + +Looking at LSP7 & LSP8 we have unified `transfer(...)` & `transferBatch(...)` functions in both contracts. Those functions contain a hook which is executed conditionally and can be used in any of the above cases. + +## Setting metadata for one or multiple tokenIds The function [`setDataBatchForTokenIds(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatchfortokenids) can be used to set multiple data key-value pairs at once for one or multiple tokenIds. This function is flexible enough to enable to set one or multiple [data key-value](/standards/erc725).md#erc725y-generic-data-keyvalue-store) pairs for: -#### case 1: a single tokenId +### Case 1: a single tokenId To set for instance 3 x data key-value pairs for the same `tokenId`, the parameters of `setDataBatchForTokenIds(bytes32[],bytes32[],bytes[])` will be as follow: @@ -123,7 +182,7 @@ async function setMultipleDataForSingleTokenId( -#### Case 2: different tokenIds +### Case 2: different tokenIds To set for instance the same data key-value pair (_e.g: `LSP4Metadata`_) for 3 x different `tokenId`s, the parameters of `setDataBatchForTokenIds(bytes32[],bytes32[],bytes[])` will be as follow: @@ -227,7 +286,7 @@ async function setMultipleDataForSingleTokenId( -### Checking if the Metadata of a tokenId changed +## Checking if the Metadata of a tokenId changed Since LSP8 uses [ERC725Y](/standards/erc725#erc725y-generic-data-keyvalue-store) under the hood, the URI pointing to the metadata of a specific tokenId can be changed inside the ERC725Y storage of the LSP8 contract. diff --git a/docs/standards/tokens/introduction.md b/docs/standards/tokens/introduction.md index a55f04c34..91df8bafb 100644 --- a/docs/standards/tokens/introduction.md +++ b/docs/standards/tokens/introduction.md @@ -34,6 +34,10 @@ As for features, these standards are just representing **incremental tokenIds** ![Tokens & NFT Standards LSP4, LSP7 and LSP8](/img/standards/LUKSO-Tokens-NFT-Standards.jpeg) +## Random Notes taken from other places + +Their functions are simpler, more straight forward and unified. + ## References - [NFT NYC - Building Blocks for the New Creative Economy (Fabian Vogelsteller, Youtube)](https://www.youtube.com/watch?v=skA4Y-vvt5s) From 0f06d0185e87dc32a97211162867cbab151e232d Mon Sep 17 00:00:00 2001 From: CJ42 Date: Thu, 10 Oct 2024 12:01:54 +0100 Subject: [PATCH 2/6] create sub-sections in contracts for LSP7/8 + add Solidity snippets to create a token --- docs/contracts/overview/DigitalAssets.md | 133 ------------- docs/contracts/overview/NFT/_category_.yml | 4 + .../overview/NFT/create-nft-collection.md | 6 + .../NFT/customise-transfer-behaviour.md | 6 + .../index.md} | 22 ++- .../overview/NFT/set-nft-metadata.md | 6 + docs/contracts/overview/Token/_category_.yml | 4 + docs/contracts/overview/Token/create-token.md | 178 ++++++++++++++++++ .../Token/customise-transfer-behaviour.md | 8 + docs/contracts/overview/Token/index.md | 103 ++++++++++ .../overview/Token/transfer-events.md | 6 + docs/standards/tokens/introduction.md | 6 + 12 files changed, 339 insertions(+), 143 deletions(-) delete mode 100644 docs/contracts/overview/DigitalAssets.md create mode 100644 docs/contracts/overview/NFT/_category_.yml create mode 100644 docs/contracts/overview/NFT/create-nft-collection.md create mode 100644 docs/contracts/overview/NFT/customise-transfer-behaviour.md rename docs/contracts/overview/{IdentifiableDigitalAssets.md => NFT/index.md} (89%) create mode 100644 docs/contracts/overview/NFT/set-nft-metadata.md create mode 100644 docs/contracts/overview/Token/_category_.yml create mode 100644 docs/contracts/overview/Token/create-token.md create mode 100644 docs/contracts/overview/Token/customise-transfer-behaviour.md create mode 100644 docs/contracts/overview/Token/index.md create mode 100644 docs/contracts/overview/Token/transfer-events.md diff --git a/docs/contracts/overview/DigitalAssets.md b/docs/contracts/overview/DigitalAssets.md deleted file mode 100644 index cdde3df4d..000000000 --- a/docs/contracts/overview/DigitalAssets.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -title: 🪙 Digital Asset (Token) -sidebar_position: 4 ---- - -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - -# LSP7 Digital Asset - -The **LSP7 Digital Asset** contract is the newest advanced version of the existing ERC token standards, such as ERC20 and ERC1155. - -They come with many features that enhance the security and the overall user experience and compatibility with [ERC725Accounts](/standards/accounts/lsp0-erc725account.md) and [Universal Receivers](/standards/accounts/lsp1-universal-receiver.md). - -An LSP7 Digital Asset uses - -## Comparisons with ERC20 - -:::danger Deprecation of `LSP7CompatibleERC20` - -The `LSP7CompatibleERC20` contracts have been deprecated and deleted from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package since version `0.15.0`, because of their unsafe nature and [security considerations (See PR #845 for more details)](https://github.com/lukso-network/lsp-smart-contracts/pull/845#issuecomment-1888671461). - -They are not recommended to be used. However, if you want to still use them, they remain available in the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). - -::: - -The interface of LSP7 has some differences compared to ERC20. - -**Similar function names** - -Both functions in LSP7 and LSP8 have the same name (`transfer`) to transfer assets. This is easier compared to ERC20 and ERC721 that use different naming (`transfer` for ERC20 vs `transferFrom` in ERC721 to transfer tokens as the token owner). - -The table below highlights these differences: - - - - - - - - - - - - - - - - - - - - - -
DescriptionERC20LSP7
Transferring tokens as an owner.transfer(address,uint256)transfer(address,address,uint256,bool,bytes)
Transferring tokens as an operator.transferFrom(address,address,uint256)
Approving an operator to spend tokens on behalf of the owner.approve(address,uint256)authorizeOperator(address,uint256)
- -In ERC20 the function `transfer(address,uint256)` is used to transfer ERC20 tokens from the caller, this can only be used by the holder of the ERC20 tokens. There is also `transferFrom(address,address,uint256)` which can also be used by the ERC20 tokens operator. - -In comparison ERC721 has: - -- `safeTransferFrom(address,address,uint256,bytes)` -- `safeTransferFrom(address,address,uint256)` -- `transferFrom(address,address,uint256)` - -All of the above functions can be used by both the owner of the token id or by the operator of the token id in order to transfer the ERC721 token. To be mentioned, both functions `safeTransferFrom(...)` have a hook that calls the recipient contract. - -Looking at LSP7 & LSP8 we have unified `transfer(...)` & `transferBatch(...)` functions in both contracts. Those functions contain a hook which is executed conditionally and can be used in any of the above cases. - -## LSP4 Digital Asset Metadata - -The **LSP4DigitalAssetMetadata** is a contract that sets the **Token-Metadata** (name and symbol) for the **LSP7DigitalAsset** and **LSP8IdentifiableDigitalAsset** token contracts. - -Since it uses **[ERC725Y General Data Key/Value Store](https://eips.ethereum.org/EIPS/eip-725)** to set the metadata, any information can be added (_e.g: **list of creators, JSON files**, etc_). - -## LSP7 Digital Asset - -The **LSP7DigitalAsset** contract represents digital assets for fungible tokens where minting and transferring are specified with an amount of tokens. Their functions were inspired from **[ERC20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)** and **[ERC1155](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol)** with more upgraded features. - -An LSP7 can serves as: - -- a **Divisible Token Contract** when `isNonDivisible` bool is set to `false` in the [`constructor(...)`](#constructor) -- otherwise serves as a **Non-Divisible Token Contract**. - -This can be useful to set `isNonDivisible` to `true`, rather than deploying a LSP8 contract to achieve the same goal. - -### Create a Fungible Token - -```solidity -// MyToken.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@lukso/lsp-smart-contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.sol"; - -contract MyToken is LSP7DigitalAsset { - // 4th argument (false) marks that this contract serves as a Fungible Token and not as a NFT. - constructor() LSP7DigitalAsset("MyToken","MTKN",msg.sender,false) { - // .. - } - - function mint() public { - _mint(...); - } -} -``` - -## Extensions - -The smart contracts packages for `@lukso/lsp7-contracts` and `@lukso/lsp8-contracts` include token extensions (similarly to OpenZeppelin contracts) that enables to include functionalities for building your token through inheritance. - -**LSP7 Tokens extensions:** - -- [`LSP7Burnable.sol`](../contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md): exposes a public `burn(...)` function that allows any token holder or operator to burn any amount of tokens. -- [`LSP7CappedSupply.sol`](../contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md): enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of tokens that can be minted. - -**LSP8 NFTs extensions:** - -- [`LSP8Burnable.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md)`: exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. -- [`LSP8CappedSupply.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md)`: enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. -- [`LSP8Enumerable.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md)`: functionality to enumerate the list of NFTs in a collection. - -If your token contract uses the proxy pattern with initialize functions, use the `InitAbstract` version of these extension contracts (\_e.g: `LSP7Burnable` -> `LSP7BurnableInitAbstract`). - -## Custom logic for transfers - -The LSP7 and LSP8 implementations provide the `_beforeTokenTransfer` and `_afterTokenTransfer` function that offer the ability to specify custom logic that can run before or after the token transfer has happen (= before or after the balances in the contract state have been updated). - -## Note on LSP7 and LSP8 implementations - -`LSP7DigitalAsset.sol` and `LSP8IdentifiableDigitalAsset.sol` are `abstract` contracts that are not deployable as they are, because they do not contain any public functions by default to manage token supply (_e.g: no public `mint(...)` or `burn(...)` functions_). You can either: - -- use `LSP7Mintable` or `LSP8Mintable`, a preset contract that contains a public `mint(...)` function callable only by the contract's owner. -- or extend the `LSP7DigitalAsset` / `LSP8IdentifiableDigitalAsset` contract and create your own supply mechanism by defining public methods that use the internal `_mint(...)` and `_burn(...)` functions. diff --git a/docs/contracts/overview/NFT/_category_.yml b/docs/contracts/overview/NFT/_category_.yml new file mode 100644 index 000000000..57092f5c8 --- /dev/null +++ b/docs/contracts/overview/NFT/_category_.yml @@ -0,0 +1,4 @@ +label: 🖼️ Identifiable Digital Asset (NFT) +position: 5 +collapsible: true +collapsed: true diff --git a/docs/contracts/overview/NFT/create-nft-collection.md b/docs/contracts/overview/NFT/create-nft-collection.md new file mode 100644 index 000000000..8ec0de0f4 --- /dev/null +++ b/docs/contracts/overview/NFT/create-nft-collection.md @@ -0,0 +1,6 @@ +--- +title: Create a Non Fungible Token +sidebar_position: 1 +--- + +# Create a Non Fungible Token diff --git a/docs/contracts/overview/NFT/customise-transfer-behaviour.md b/docs/contracts/overview/NFT/customise-transfer-behaviour.md new file mode 100644 index 000000000..2d9669be4 --- /dev/null +++ b/docs/contracts/overview/NFT/customise-transfer-behaviour.md @@ -0,0 +1,6 @@ +--- +title: Customize transfer behaviour +sidebar_position: 2 +--- + +# Customize transfer behaviour diff --git a/docs/contracts/overview/IdentifiableDigitalAssets.md b/docs/contracts/overview/NFT/index.md similarity index 89% rename from docs/contracts/overview/IdentifiableDigitalAssets.md rename to docs/contracts/overview/NFT/index.md index 4d95e5ace..f3a0263d8 100644 --- a/docs/contracts/overview/IdentifiableDigitalAssets.md +++ b/docs/contracts/overview/NFT/index.md @@ -27,14 +27,6 @@ They are not recommended to be used. However, if you want to still use them, the ::: -The interface of LSP8 has some differences compared to ERC721. - -**Similar function names** - -Both functions in LSP7 and LSP8 have the same name (`transfer`) to transfer assets. This is easier compared to ERC20 and ERC721 that use different naming (`transfer` for ERC20 vs `transferFrom` in ERC721 to transfer tokens as the token owner). - -The table below highlights these differences: - @@ -60,8 +52,6 @@ The table below highlights these differences:
Description
-In ERC20 the function `transfer(address,uint256)` is used to transfer ERC20 tokens from the caller, this can only be used by the holder of the ERC20 tokens. There is also `transferFrom(address,address,uint256)` which can also be used by the ERC20 tokens operator. - In comparison ERC721 has: - `safeTransferFrom(address,address,uint256,bytes)` @@ -72,6 +62,18 @@ All of the above functions can be used by both the owner of the token id or by t Looking at LSP7 & LSP8 we have unified `transfer(...)` & `transferBatch(...)` functions in both contracts. Those functions contain a hook which is executed conditionally and can be used in any of the above cases. +## LSP8 NFT extensions + +The `@lukso/lsp8-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that enables to include functionalities for building your token through inheritance. + +- [`LSP8Burnable.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md)`: exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. +- [`LSP8CappedSupply.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md)`: enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. +- [`LSP8Enumerable.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md)`: functionality to enumerate the list of NFTs in a collection. + +## Custom logic for transfers + +The `LSP8IdenfitiableDigitalAsset` contract implementation includes the `_beforeTokenTransfer` and `_afterTokenTransfer` functions that offer the ability to specify custom logic that can run before or after the token transfer has happen (= before or after the balances in the contract state have been updated). + ## Setting metadata for one or multiple tokenIds The function [`setDataBatchForTokenIds(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatchfortokenids) can be used to set multiple data key-value pairs at once for one or multiple tokenIds. diff --git a/docs/contracts/overview/NFT/set-nft-metadata.md b/docs/contracts/overview/NFT/set-nft-metadata.md new file mode 100644 index 000000000..cd49d6765 --- /dev/null +++ b/docs/contracts/overview/NFT/set-nft-metadata.md @@ -0,0 +1,6 @@ +--- +title: Set NFT Metadata +sidebar_position: 3 +--- + +# Set NFT Metadata diff --git a/docs/contracts/overview/Token/_category_.yml b/docs/contracts/overview/Token/_category_.yml new file mode 100644 index 000000000..67672d02e --- /dev/null +++ b/docs/contracts/overview/Token/_category_.yml @@ -0,0 +1,4 @@ +label: 🪙 Digital Asset (Token) +position: 4 +collapsible: true +collapsed: true diff --git a/docs/contracts/overview/Token/create-token.md b/docs/contracts/overview/Token/create-token.md new file mode 100644 index 000000000..097fad1fc --- /dev/null +++ b/docs/contracts/overview/Token/create-token.md @@ -0,0 +1,178 @@ +--- +title: Create a Fungible Token +sidebar_position: 1 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Create a Fungible Token + + + + +```solidity title="MyToken.sol" {8-14} showLineNumbers +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import {_LSP4_TOKEN_TYPE_TOKEN} from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol"; +import {LSP7DigitalAsset} from "@lukso/lsp7-contracts/contracts/LSP7DigitalAsset.sol"; + +contract MyToken is + LSP7DigitalAsset( + "MyToken", // token name + "MTKN", // token symbol + msg.sender, // contract owner + _LSP4_TOKEN_TYPE_TOKEN, // token type as uint256 (0 for Token, 1 for NFT, 2 for Collection) + false // make the token non divisible (true = 0 decimals, false = 18 decimals) + ) +{ + // Custom logic for your token... +} +``` + + + + +```solidity title="MyToken.sol" {18-24} showLineNumbers +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import {_LSP4_TOKEN_TYPE_TOKEN} from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol"; +import {LSP7DigitalAsset} from "@lukso/lsp7-contracts/contracts/LSP7DigitalAsset.sol"; + +contract MyToken is LSP7DigitalAsset { + /// @dev Available options for 4th parameter token type (uint256) + /// - 0 for Token + /// - 1 for NFT + /// - 2 for Collection + constructor( + string memory name_, + string memory symbol_, + address contractOwner_, + bool isNonDivisible_ + ) + LSP7DigitalAsset( + name_, + symbol_, + contractOwner_, + _LSP4_TOKEN_TYPE_TOKEN, + isNonDivisible_ + ) + { + // constructor logic ... + } + + // Custom logic for your token... +} + +``` + + + + +## LSP7 Tokens extensions + +The `@lukso/lsp7-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that enables to include functionalities for building your token through inheritance. + +| Extension contract | Description | +| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| [`LSP7Burnable.sol`](../contracts/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md) | Exposes a public `burn(...)` function that allows any token holder or operator to burn any amount of tokens. | +| [`LSP7CappedSupply.sol`](../contracts/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md) | Enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of tokens that can be minted. | + +If your token contract uses the proxy pattern with initialize functions, use the `InitAbstract` version of these extension contracts (_e.g: `LSP7Burnable` -> `LSP7BurnableInitAbstract`_). + + + + +```solidity title="MyToken.sol" {19-20} showLineNumbers +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { _LSP4_TOKEN_TYPE_TOKEN } from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol"; +import { LSP7DigitalAsset } from "@lukso/lsp7-contracts/contracts/LSP7DigitalAsset.sol"; + +// extensions +import { LSP7Burnable } from "@lukso/lsp7-contracts/contracts/extensions/LSP7Burnable.sol"; +import { LSP7CappedSupply } from "@lukso/lsp7-contracts/contracts/extensions/LSP7CappedSupply.sol"; + +contract MyToken is + LSP7DigitalAsset( + "MyToken", // token name + "MTKN", // token symbol + msg.sender, // contract owner + _LSP4_TOKEN_TYPE_TOKEN, // token type as uint256 (0 for Token, 1 for NFT, 2 for Collection) + false // make the token non divisible (true = 0 decimals, false = 18 decimals) + ), + LSP7Burnable, + LSP7CappedSupply(42_000_000 * 10 ** super.decimals()) +{ + function _mint( + address to, + uint256 amount, + bool force, + bytes memory data + ) + internal + virtual + override(LSP7CappedSupply, LSP7DigitalAsset) + { + LSP7CappedSupply._mint(to, amount, force, data); + } + + // Custom logic for your token... +} +``` + + + + +```solidity title="MyToken.sol" {23-25} showLineNumbers +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +import { _LSP4_TOKEN_TYPE_TOKEN } from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol"; +import { LSP7DigitalAsset } from "@lukso/lsp7-contracts/contracts/LSP7DigitalAsset.sol"; + +// extensions +import { LSP7Burnable } from "@lukso/lsp7-contracts/contracts/extensions/LSP7Burnable.sol"; +import { LSP7CappedSupply } from "@lukso/lsp7-contracts/contracts/extensions/LSP7CappedSupply.sol"; + +contract MyToken is LSP7DigitalAsset, LSP7Burnable, LSP7CappedSupply { + /// @dev Available options for 4th parameter token type (uint256) + /// - 0 for Token + /// - 1 for NFT + /// - 2 for Collection + constructor( + string memory name_, + string memory symbol_, + address contractOwner_, + bool isNonDivisible_, + uint256 maxSupply_ + ) + LSP7DigitalAsset(name_, symbol_, contractOwner_, _LSP4_TOKEN_TYPE_TOKEN, isNonDivisible_) + LSP7Burnable() + LSP7CappedSupply(maxSupply_) + { + // constructor logic ... + } + + function _mint( + address to, + uint256 amount, + bool force, + bytes memory data + ) + internal + virtual + override(LSP7CappedSupply, LSP7DigitalAsset) + { + LSP7CappedSupply._mint(to, amount, force, data); + } + + // Custom logic for your token... +} +``` + + + diff --git a/docs/contracts/overview/Token/customise-transfer-behaviour.md b/docs/contracts/overview/Token/customise-transfer-behaviour.md new file mode 100644 index 000000000..826dc0716 --- /dev/null +++ b/docs/contracts/overview/Token/customise-transfer-behaviour.md @@ -0,0 +1,8 @@ +--- +title: Customize transfer behaviour +sidebar_position: 2 +--- + +# Customize transfer behaviour + +The `LSP7DigitalAsset` contract implementation includes the `_beforeTokenTransfer` and `_afterTokenTransfer` functions that offer the ability to specify custom logic that can run before or after the token transfer has happen (= before or after the balances in the contract state have been updated). diff --git a/docs/contracts/overview/Token/index.md b/docs/contracts/overview/Token/index.md new file mode 100644 index 000000000..ade1a2eb8 --- /dev/null +++ b/docs/contracts/overview/Token/index.md @@ -0,0 +1,103 @@ +--- +title: 🪙 Digital Asset (Token) +sidebar_position: 4 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# LSP7 Digital Asset + +:::danger Deprecation of `LSP7CompatibleERC20` + +The `LSP7CompatibleERC20` contracts have been deprecated and deleted from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package since version `0.15.0`, because of their [unsafe nature and security considerations](https://github.com/lukso-network/lsp-smart-contracts/pull/845#issuecomment-1888671461). They are not recommended to be used. However, if you want to still use them, they remain available up to the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). + +::: + +The **LSP7 Digital Asset** contract is the newest advanced version of the existing ERC token standards, such as ERC20 and ERC1155. It comes with many features that enhance the security and the overall user experience and compatibility with [ERC725Accounts](/standards/accounts/lsp0-erc725account.md) and [Universal Receivers](/standards/accounts/lsp1-universal-receiver.md). + +The **LSP7DigitalAsset** contract represents digital assets for fungible tokens where minting and transferring are specified with an amount of tokens. Their functions were inspired from **[ERC20](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol)** and **[ERC1155](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol)** with more upgraded features. + +## Installation & Usage + +The LSP7 smart contracts and their ABIs are available are available as their own individual package. To use them, install `@lukso/lsp7-contracts` as a dependency in your project. + + + + +``` +npm install @lukso/lsp7-contracts +``` + + + + +``` +yarn add @lukso/lsp7-contracts +``` + + + + +``` +pnpm add @lukso/lsp7-contracts +``` + + + + +`LSP7DigitalAsset.sol` is an `abstract` contracts that is not deployable as is, because it does not contain any public functions by default to manage token supply (_e.g: no public `mint(...)` or `burn(...)` functions_). You can either: + +- the `LSP7Mintable` preset contract that contains a public `mint(...)` function callable only by the contract's owner. +- or extend the `LSP7DigitalAsset` contract (_see below_) and create your own supply mechanism by defining public methods that use the internal `_mint(...)` and `_burn(...)` functions. + +## Token Metadata + +LSP7 uses the **LSP4DigitalAssetMetadata** standard under the hood. Since LSP4 uses an **[ERC725Y General Data Key/Value Store](https://eips.ethereum.org/EIPS/eip-725)**, it allows any form of metadata to be defined and set. This could include things such as **list of creators, JSON files, exchanges where the token is listed, etc...** + +It is within this contract that the **Token-Metadata** (name and symbol) is set for the **LSP7DigitalAsset** on deployment / initialization. + +## Example use cases + +An LSP7 can serves as: + +- a **Divisible Token Contract** when `isNonDivisible` bool is set to `false` in the [`constructor(...)`](#constructor) +- otherwise serves as a **Non-Divisible Token Contract**. + +This can be useful to set `isNonDivisible` to `true`, rather than deploying a LSP8 contract to achieve the same goal. + +## Comparisons with ERC20 + + + + + + + + + + + + + + + + + + + + + +
DescriptionERC20LSP7
Transferring tokens as an owner.transfer(address,uint256)transfer(address,address,uint256,bool,bytes)
Transferring tokens as an operator.transferFrom(address,address,uint256)
Approving an operator to spend tokens on behalf of the owner.approve(address,uint256)authorizeOperator(address,uint256)
+ +In ERC20 the following functions can be used to transfer tokens from the token holder: + +- `transfer(address,uint256)` can only be used by the token holder. Therefore, the caller must be token holder. +- `transferFrom(address,address,uint256)` can be used by operator to transfer tokens on behalf of a token holder (as long as this token holder has been approved and given an allowance). + +In comparison in LSP7, a single function `transfer(address,address,uint256,bool,bytes)` can be used by both operator and token owner. + +- if a token holder want to transfer its own token, it can call directly the function (be the caller) and specify its address for the first parameter `from`. +- if an operator want to transfer tokens for a token holder that it has been approved for (via the `authorizeOperator(...)` function), it can call the function and specify the address of the token holder as the `from` address as well. + +Therefore as you can see from the table above, the only thing that changes when transferring token as a token owner or an operator is **the caller** of the function. **The parameters remain the same**. diff --git a/docs/contracts/overview/Token/transfer-events.md b/docs/contracts/overview/Token/transfer-events.md new file mode 100644 index 000000000..b59811b53 --- /dev/null +++ b/docs/contracts/overview/Token/transfer-events.md @@ -0,0 +1,6 @@ +--- +title: Listen for Transfer events +sidebar_position: 3 +--- + +# Listen for Transfer events diff --git a/docs/standards/tokens/introduction.md b/docs/standards/tokens/introduction.md index 91df8bafb..532c75e2b 100644 --- a/docs/standards/tokens/introduction.md +++ b/docs/standards/tokens/introduction.md @@ -38,6 +38,12 @@ As for features, these standards are just representing **incremental tokenIds** Their functions are simpler, more straight forward and unified. +**Similar function names** + +Both functions in LSP7 and LSP8 have the same name (`transfer`) to transfer assets. This is easier compared to ERC20 and ERC721 that use different naming (`transfer` for ERC20 vs `transferFrom` in ERC721 to transfer tokens as the token owner). + +Looking at LSP7 & LSP8 we have unified `transfer(...)` & `transferBatch(...)` functions in both contracts. Those functions contain a hook which is executed conditionally and can be used in any of the above cases. + ## References - [NFT NYC - Building Blocks for the New Creative Economy (Fabian Vogelsteller, Youtube)](https://www.youtube.com/watch?v=skA4Y-vvt5s) From 2b96030df143508043b13a5fcb6a7a771e6de099 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 11 Oct 2024 13:35:57 +0100 Subject: [PATCH 3/6] add content for LSP7 to customise transfer before via internal hooks --- .../Token/customise-transfer-behaviour.md | 97 ++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/docs/contracts/overview/Token/customise-transfer-behaviour.md b/docs/contracts/overview/Token/customise-transfer-behaviour.md index 826dc0716..0aa76c1f9 100644 --- a/docs/contracts/overview/Token/customise-transfer-behaviour.md +++ b/docs/contracts/overview/Token/customise-transfer-behaviour.md @@ -5,4 +5,99 @@ sidebar_position: 2 # Customize transfer behaviour -The `LSP7DigitalAsset` contract implementation includes the `_beforeTokenTransfer` and `_afterTokenTransfer` functions that offer the ability to specify custom logic that can run before or after the token transfer has happen (= before or after the balances in the contract state have been updated). + + +## `_beforeTokenTransfer` and `_afterTokenTransfer` hooks + +`The LSP7DigitalAsset contract` implementation includes two hooks to add custom behaviour to run logic before or after the total supply of tokens has been updated in the contract's storage. This can be done via the [`_beforeTokenTransfer(...)`](../../contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_beforetokentransfer) and [`_afterTokenTransfer(...)`](../../contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_aftertokentransfer) functions. + +### Solidity example + +Below is a simple pseudo-code example in Solidity where the `_afterTokenTransfer(...)` internal hook **registers the number of token transactions sent and received by any address**. Since a LSP7 token uses ERC725Y as storage under the hood, it provides a flexible way to add metadata. + +This example leverages this feature and provides a way to get a simple count of token transactions performed by each user in terms of tokens sent and received. It uses the following functions and libraries: + +- `_afterTokenTransfer(...)` hook to register the token transfer after it occurred. +- The [ERC725Y](../../../standards/erc725.md#erc725y-data-representation) storage of the token contract where the transfer count will be stored (reading via [`_getData(...)`](../../contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_getdata), updating it via [`_setData(...)`](../../contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_setdata)). +- We defined a specific data key where to store this info and used the [`LSP2Utils`](../../contracts/../libraries/LSP2Utils.md#generatemappingkey-2) library to encode this as a [`Mapping`](../../../standards/metadata/lsp2-json-schema.md#mapping) data key easily. + +```solidity +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.20; + +// tokens +import { _LSP4_TOKEN_TYPE_TOKEN } from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol"; +import { LSP7DigitalAsset } from "@lukso/lsp7-contracts/contracts/LSP7DigitalAsset.sol"; + +// libraries +import { LSP2Utils } from "@lukso/lsp2-contracts/contracts/LSP2Utils.sol"; + +contract MyToken is LSP7DigitalAsset { + /// @dev Available options for 4th parameter token type (uint256) + /// - 0 for Token + /// - 1 for NFT + /// - 2 for Collection + constructor( + string memory name_, + string memory symbol_, + address contractOwner_, + bool isNonDivisible_ + ) + LSP7DigitalAsset(name_, symbol_, contractOwner_, _LSP4_TOKEN_TYPE_TOKEN, isNonDivisible_) + { + // constructor logic ... + } + + function _afterTokenTransfer( + address from, + address to, + uint256, /* amount */ + bytes memory /* data */ + ) + internal + virtual + override + { + // TokensSentTx:
+ bytes32 tokensSentTxDataKey = + LSP2Utils.generateMappingKey({ keyPrefix: bytes10(keccak256("TokensSentTx")), bytes20Value: bytes20(from) }); + + // TokensReceivedTx:
+ bytes32 tokensReceivedTxDataKey = LSP2Utils.generateMappingKey({ + keyPrefix: bytes10(keccak256("TokensReceivedTx")), + bytes20Value: bytes20(to) + }); + + bytes memory tokensSentTxValue = _getData(tokensSentTxDataKey); + bytes memory tokensReceivedTxValue = _getData(tokensReceivedTxDataKey); + + // sanity check to ensure we can abi-decode correctly + require(tokensSentTxValue.length == 32, "Invalid uint256 encoded value under `TokensSentTx:
data key"); + require( + tokensReceivedTxValue.length == 32, + "Invalid uint256 encoded value under `TokensReceivedTx:
data key" + ); + + uint256 tokensSentTxCount = abi.decode(tokensSentTxValue, (uint256)); + uint256 tokensReceivedTxCount = abi.decode(tokensReceivedTxValue, (uint256)); + + // increment the counter + set data in the storage + tokensSentTxCount++; + tokensReceivedTxCount++; + + _setData(tokensSentTxDataKey, abi.encode(tokensSentTxCount)); + _setData(tokensReceivedTxDataKey, abi.encode(tokensReceivedTxCount)); + } +} + +``` + +This example is minimalist and only stores a counter as a number. Still, any info related to the token transfer could be stored during the transfer (_e.g: the amount, the data passed, the gas price, the balance before and after, etc..._). This way, the storage of the token contract can act, for instance, as: 💡 + +- A _"mini explorer"_ for the token contract (without relying on a block explorer and reviewing the complete list of transactions). +- To query the transactions for a user and provide an analytical view of their balance changes, demonstrating its data analysis capabilities. +- Showcase which user, smart contract address or protocol are the most active users and traders for this token (being the ones with the higher count under the ) From fc1366668b049dc58363a5c0754a6481f005b0a9 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Fri, 18 Oct 2024 15:06:46 +0200 Subject: [PATCH 4/6] improve contracts section for LSP8 --- .../overview/NFT/create-nft-collection.md | 46 +++ .../NFT/customise-transfer-behaviour.md | 2 + docs/contracts/overview/NFT/index.md | 280 +++--------------- .../overview/NFT/set-nft-metadata.md | 223 ++++++++++++++ docs/contracts/overview/Token/create-token.md | 2 +- docs/contracts/overview/Token/index.md | 4 +- .../overview/Token/transfer-events.md | 6 - 7 files changed, 311 insertions(+), 252 deletions(-) delete mode 100644 docs/contracts/overview/Token/transfer-events.md diff --git a/docs/contracts/overview/NFT/create-nft-collection.md b/docs/contracts/overview/NFT/create-nft-collection.md index 8ec0de0f4..b33036c4b 100644 --- a/docs/contracts/overview/NFT/create-nft-collection.md +++ b/docs/contracts/overview/NFT/create-nft-collection.md @@ -4,3 +4,49 @@ sidebar_position: 1 --- # Create a Non Fungible Token + +```solidity +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +// modules +import { + LSP8IdentifiableDigitalAsset +} from "@lukso/lsp8-contracts/contracts/LSP8IdentifiableDigitalAsset.sol"; + +// constants +import { + _LSP8_TOKENID_FORMAT_NUMBER +} from "@lukso/lsp8-contracts/contracts/LSP8Constants.sol"; +import { + _LSP4_TOKEN_TYPE_COLLECTION +} from "@lukso/lsp4-contracts/contracts/LSP4Constants.sol"; + +contract BasicNFTCollection is LSP8IdentifiableDigitalAsset { + constructor( + string memory nftCollectionName, + string memory nftCollectionSymbol, + address contractOwner + ) + LSP8IdentifiableDigitalAsset( + nftCollectionName, + nftCollectionSymbol, + contractOwner, + _LSP4_TOKEN_TYPE_COLLECTION, + _LSP8_TOKENID_FORMAT_NUMBER + ) + { + // contract logic goes here... + } +} +``` + +## LSP8 NFT extensions + +The `@lukso/lsp8-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that can be added through inheritance. This enables to include specific functionalities for building your token. + +| Extension contract | Description | +| :------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | +| [`LSP8Burnable.sol`](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md) | exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. | +| [`LSP8CappedSupply.sol`](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md) | enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. | +| [`LSP8Enumerable.sol`](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md) | functionality to enumerate the list of NFTs in a collection. | diff --git a/docs/contracts/overview/NFT/customise-transfer-behaviour.md b/docs/contracts/overview/NFT/customise-transfer-behaviour.md index 2d9669be4..5ba93b91e 100644 --- a/docs/contracts/overview/NFT/customise-transfer-behaviour.md +++ b/docs/contracts/overview/NFT/customise-transfer-behaviour.md @@ -4,3 +4,5 @@ sidebar_position: 2 --- # Customize transfer behaviour + +The `LSP8IdenfitiableDigitalAsset` contract implementation includes the `_beforeTokenTransfer` and `_afterTokenTransfer` functions that offer the ability to specify custom logic that can run before or after the token transfer has happen (= before or after the balances in the contract state have been updated). diff --git a/docs/contracts/overview/NFT/index.md b/docs/contracts/overview/NFT/index.md index f3a0263d8..05ae5e053 100644 --- a/docs/contracts/overview/NFT/index.md +++ b/docs/contracts/overview/NFT/index.md @@ -8,24 +8,52 @@ import TabItem from '@theme/TabItem'; # LSP8 Identifiable Digital Asset -The **LSP8 Identifiable Digital Asset** contract is the newest advanced version of the existing ERC NFT standards, such as ERC721. +:::danger Deprecation of `LSP8CompatibleERC721` + +The `LSP8CompatibleERC721` contracts have been deprecated and deleted from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package since version `0.15.0`, because of their unsafe nature and [security considerations (See PR #845 for more details)](https://github.com/lukso-network/lsp-smart-contracts/pull/845#issuecomment-1888671461). -LSP8 identifiable digital assets represent **N**on **F**ungible **T**okens (NFTs) that can be uniquely traded. +They are not recommended to be used. However, if you want to still use them, they remain available in the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). + +::: -and given metadata using the **[ERC725Y Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-725.md#erc725y)**. -Each NFT is identified with a tokenId, based on **[ERC721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol)**. +The **LSP8 Identifiable Digital Asset** contract is the newest advanced version of the existing ERC NFT standards, such as ERC721. LSP8 identifiable digital assets represent **N**on **F**ungible **T**okens (NFTs) that can be uniquely traded. Each NFT is identified with a tokenId, based on **[ERC721](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol)** and can also have its own metadata set using the **[`setDataForTokenId(...)`](../../contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatafortokenid)** function. A **bytes32** value is used for tokenId to allow many uses of token identification, including numbers, contract addresses, and hashed values (i.e., serial numbers). -## Comparisons with ERC721 +## Installation & Usage -:::danger Deprecation of `LSP8CompatibleERC721` +The LSP8 smart contracts and their ABIs are available are available in their own individual package. To use them, install `@lukso/lsp8-contracts` as a dependency in your project. -The `LSP8CompatibleERC721` contracts have been deprecated and deleted from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package since version `0.15.0`, because of their unsafe nature and [security considerations (See PR #845 for more details)](https://github.com/lukso-network/lsp-smart-contracts/pull/845#issuecomment-1888671461). + + -They are not recommended to be used. However, if you want to still use them, they remain available in the version [`0.14.0`](https://github.com/lukso-network/lsp-smart-contracts/releases/tag/lsp-smart-contracts-v0.14.0). +``` +npm install @lukso/lsp8-contracts +``` -::: + + + +``` +yarn add @lukso/lsp8-contracts +``` + + + + +``` +pnpm add @lukso/lsp8-contracts +``` + + + + +`LSP8IdentifiableDigitalAsset.sol` is an `abstract` contract that is not deployable as is, because it does not contain any public functions by default to manage token supply (_e.g: no public `mint(...)` or `burn(...)` functions_). You can either: + +- the `LSP8Mintable` preset contract that contains a public `mint(...)` function callable only by the contract's owner. +- or extend the `LSP8IdentifiableDigitalAsset` contract (_see below_) and create your own supply mechanism by defining public methods that use the internal `_mint(...)` and `_burn(...)` functions. + +## Comparisons with ERC721 @@ -61,237 +89,3 @@ In comparison ERC721 has: All of the above functions can be used by both the owner of the token id or by the operator of the token id in order to transfer the ERC721 token. To be mentioned, both functions `safeTransferFrom(...)` have a hook that calls the recipient contract. Looking at LSP7 & LSP8 we have unified `transfer(...)` & `transferBatch(...)` functions in both contracts. Those functions contain a hook which is executed conditionally and can be used in any of the above cases. - -## LSP8 NFT extensions - -The `@lukso/lsp8-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that enables to include functionalities for building your token through inheritance. - -- [`LSP8Burnable.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md)`: exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. -- [`LSP8CappedSupply.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md)`: enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. -- [`LSP8Enumerable.sol](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md)`: functionality to enumerate the list of NFTs in a collection. - -## Custom logic for transfers - -The `LSP8IdenfitiableDigitalAsset` contract implementation includes the `_beforeTokenTransfer` and `_afterTokenTransfer` functions that offer the ability to specify custom logic that can run before or after the token transfer has happen (= before or after the balances in the contract state have been updated). - -## Setting metadata for one or multiple tokenIds - -The function [`setDataBatchForTokenIds(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatchfortokenids) can be used to set multiple data key-value pairs at once for one or multiple tokenIds. - -This function is flexible enough to enable to set one or multiple [data key-value](/standards/erc725).md#erc725y-generic-data-keyvalue-store) pairs for: - -### Case 1: a single tokenId - -To set for instance 3 x data key-value pairs for the same `tokenId`, the parameters of `setDataBatchForTokenIds(bytes32[],bytes32[],bytes[])` will be as follow: - - - - - -```solidity -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; - -import { - ILSP8IdentifiableDigitalAsset as ILSP8 -} from "@lukso/lsp-smart-contracts/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol"; -import { - _LSP4_METADATA_KEY -} from "@lukso/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol"; - -bytes32 constant _NFT_ICON_DATA_KEY = keccak256("NFTIcon"); -bytes32 constant _NFT_MARKET_PLACE_URLS__DATA_KEY = keccak256("NFTMarketplaceURLs"); - -bytes32 constant _TOKEN_ID_TO_SET = 0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe; - -function setMultipleDataForSingleTokenId( - ILSP8 lsp8Contract, - bytes memory lsp4MetadataValue, - bytes memory nftIconValue, - bytes memory nftMarketPlaceURLsValue -) { - bytes32[] memory tokenIdsToUpdate = new bytes32[](3); - bytes32[] memory dataKeysToSet = new bytes32[](3); - bytes[] memory dataValuesToSet = new bytes[](3); - - // we are setting 3 x data key-value pairs for the same tokenid - tokenIdsToUpdate[0] = _TOKEN_ID_TO_SET; - tokenIdsToUpdate[1] = _TOKEN_ID_TO_SET; - tokenIdsToUpdate[2] = _TOKEN_ID_TO_SET; - - dataKeysToSet[0] = _LSP4_METADATA_KEY; - dataKeysToSet[1] = _NFT_ICON_DATA_KEY; - dataKeysToSet[2] = _NFT_MARKET_PLACE_URLS__DATA_KEY; - - dataValuesToSet[0] = lsp4MetadataValue; - dataValuesToSet[1] = nftIconValue; - dataValuesToSet[2] = nftMarketPlaceURLsValue; - - lsp8Contract.setDataBatchForTokenIds( - tokenIdsToUpdate, - dataKeysToSet, - dataValuesToSet - ); -} -``` - - - - - -```js -import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'; - -const _NFT_ICON_DATA_KEY = keccak256('NFTIcon'); -const _NFT_MARKET_PLACE_URLS__DATA_KEY = keccak256('NFTMarketplaceURLs'); - -const _TOKEN_ID_TO_SET = - '0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe'; - -async function setMultipleDataForSingleTokenId( - lsp8Contract, - lsp4MetadataValue, - nftIconValue, - nftMarketPlaceURLsValue, -) { - const tokenIdsToUpdate = [ - _TOKEN_ID_TO_SET, - _TOKEN_ID_TO_SET, - _TOKEN_ID_TO_SET, - ]; - - const dataKeysToSet = [ - ERC725YDataKeys.LSP4.LSP4Metadata, - _NFT_ICON_DATA_KEY, - _NFT_MARKET_PLACE_URLS__DATA_KEY, - ]; - - const dataValuesToSet = [ - lsp4MetadataValue, - nftIconValue, - nftMarketPlaceURLsValue, - ]; - - await lsp8Contract.setDataBatchForTokenIds( - tokenIdsToUpdate, - dataKeysToSet, - dataValuesToSet, - ); -} -``` - - - - - -### Case 2: different tokenIds - -To set for instance the same data key-value pair (_e.g: `LSP4Metadata`_) for 3 x different `tokenId`s, the parameters of `setDataBatchForTokenIds(bytes32[],bytes32[],bytes[])` will be as follow: - - - - - -```solidity -// SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.12; - -import { - ILSP8IdentifiableDigitalAsset as ILSP8 -} from "@lukso/lsp-smart-contracts/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol"; -import { - _LSP4_METADATA_KEY -} from "@lukso/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol"; - -bytes32 constant _FIRST_TOKEN_ID_TO_SET = 0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe; -bytes32 constant _SECOND_TOKEN_ID_TO_SET = 0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef; -bytes32 constant _THIRD_TOKEN_ID_TO_SET = 0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d; - -function setMultipleDataForSingleTokenId( - ILSP8 lsp8Contract, - bytes memory firstTokenIdLsp4MetadataValue, - bytes memory secondTokenIdLsp4MetadataValue, - bytes memory thirdTokenIdLsp4MetadataValue -) { - bytes32[] memory tokenIdsToUpdate = new bytes32[](3); - bytes32[] memory dataKeysToSet = new bytes32[](3); - bytes[] memory dataValuesToSet = new bytes[](3); - - tokenIdsToUpdate[0] = _FIRST_TOKEN_ID_TO_SET; - tokenIdsToUpdate[1] = _SECOND_TOKEN_ID_TO_SET; - tokenIdsToUpdate[2] = _THIRD_TOKEN_ID_TO_SET; - - // we are setting the metadata for 3 x different tokenIds - dataKeysToSet[0] = _LSP4_METADATA_KEY; - dataKeysToSet[1] = _LSP4_METADATA_KEY; - dataKeysToSet[2] = _LSP4_METADATA_KEY; - - dataValuesToSet[0] = firstTokenIdLsp4MetadataValue; - dataValuesToSet[1] = secondTokenIdLsp4MetadataValue; - dataValuesToSet[2] = thirdTokenIdLsp4MetadataValue; - - lsp8Contract.setDataBatchForTokenIds( - tokenIdsToUpdate, - dataKeysToSet, - dataValuesToSet - ); -} -``` - - - - - -```js -import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'; - -const _FIRST_TOKEN_ID_TO_SET = - '0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe'; -const _SECOND_TOKEN_ID_TO_SET = - '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef'; -const _THIRD_TOKEN_ID_TO_SET = - '0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d'; - -async function setMultipleDataForSingleTokenId( - lsp8Contract, - firstTokenIdLsp4MetadataValue, - secondTokenIdLsp4MetadataValue, - thirdTokenIdLsp4MetadataValue, -) { - const tokenIdsToUpdate = [ - _FIRST_TOKEN_ID_TO_SET, - _SECOND_TOKEN_ID_TO_SET, - _THIRD_TOKEN_ID_TO_SET, - ]; - - const dataKeysToSet = [ - ERC725YDataKeys.LSP4.LSP4Metadata, - ERC725YDataKeys.LSP4.LSP4Metadata, - ERC725YDataKeys.LSP4.LSP4Metadata, - ]; - - const dataValuesToSet = [ - firstTokenIdLsp4MetadataValue, - secondTokenIdLsp4MetadataValue, - thirdTokenIdLsp4MetadataValue, - ]; - - await lsp8Contract.setDataBatchForTokenIds( - tokenIdsToUpdate, - dataKeysToSet, - dataValuesToSet, - ); -} -``` - - - - - -## Checking if the Metadata of a tokenId changed - -Since LSP8 uses [ERC725Y](/standards/erc725#erc725y-generic-data-keyvalue-store) under the hood, the URI pointing to the metadata of a specific tokenId can be changed inside the ERC725Y storage of the LSP8 contract. - -We have seen in the previous section [**how to set metadata for one or multiple tokenIds**](#setting-metadata-for-one-or-multiple-tokenids). - -The two functions `setDataForTokenId(...)` and `setDataBatchForTokenIds(...)` emit a [`TokenIdDataChanged`](../contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#tokeniddatachanged) event. You can listen for this event in the LSP8 contract from your dApp, filtering for the `LSP4Metadata` data key to check if the metadata of a tokenId has been changed. You can do so by filtering the first parameter with the `tokenId` and the second parameter with the [bytes32 value of the `LSP4Metadata` data key](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata). diff --git a/docs/contracts/overview/NFT/set-nft-metadata.md b/docs/contracts/overview/NFT/set-nft-metadata.md index cd49d6765..f8b8cead9 100644 --- a/docs/contracts/overview/NFT/set-nft-metadata.md +++ b/docs/contracts/overview/NFT/set-nft-metadata.md @@ -3,4 +3,227 @@ title: Set NFT Metadata sidebar_position: 3 --- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + # Set NFT Metadata + +The function [`setDataBatchForTokenIds(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatchfortokenids) can be used to set multiple [data key-value](/standards/erc725.md#erc725y-generic-data-keyvalue-store) pairs at once for one or multiple tokenIds. + +## Examples + +### Set multiple metadata at once on the same tokenId + +To set for instance 3 x data key-value pairs for the same `tokenId`, the parameters of `setDataBatchForTokenIds(bytes32[],bytes32[],bytes[])` can be used as follow: + + + + + +```solidity +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.12; + +import { + ILSP8IdentifiableDigitalAsset as ILSP8 +} from "@lukso/lsp-smart-contracts/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol"; +import { + _LSP4_METADATA_KEY +} from "@lukso/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol"; + +bytes32 constant _NFT_ICON_DATA_KEY = keccak256("NFTIcon"); +bytes32 constant _NFT_MARKET_PLACE_URLS__DATA_KEY = keccak256("NFTMarketplaceURLs"); + +bytes32 constant _TOKEN_ID_TO_SET = 0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe; + +function setMultipleDataForSingleTokenId( + ILSP8 lsp8Contract, + bytes memory lsp4MetadataValue, + bytes memory nftIconValue, + bytes memory nftMarketPlaceURLsValue +) { + bytes32[] memory tokenIdsToUpdate = new bytes32[](3); + bytes32[] memory dataKeysToSet = new bytes32[](3); + bytes[] memory dataValuesToSet = new bytes[](3); + + // we are setting 3 x data key-value pairs for the same tokenid + tokenIdsToUpdate[0] = _TOKEN_ID_TO_SET; + tokenIdsToUpdate[1] = _TOKEN_ID_TO_SET; + tokenIdsToUpdate[2] = _TOKEN_ID_TO_SET; + + dataKeysToSet[0] = _LSP4_METADATA_KEY; + dataKeysToSet[1] = _NFT_ICON_DATA_KEY; + dataKeysToSet[2] = _NFT_MARKET_PLACE_URLS__DATA_KEY; + + dataValuesToSet[0] = lsp4MetadataValue; + dataValuesToSet[1] = nftIconValue; + dataValuesToSet[2] = nftMarketPlaceURLsValue; + + lsp8Contract.setDataBatchForTokenIds( + tokenIdsToUpdate, + dataKeysToSet, + dataValuesToSet + ); +} +``` + + + + + +```js +import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'; + +const _NFT_ICON_DATA_KEY = keccak256('NFTIcon'); +const _NFT_MARKET_PLACE_URLS__DATA_KEY = keccak256('NFTMarketplaceURLs'); + +const _TOKEN_ID_TO_SET = + '0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe'; + +async function setMultipleDataForSingleTokenId( + lsp8Contract, + lsp4MetadataValue, + nftIconValue, + nftMarketPlaceURLsValue, +) { + const tokenIdsToUpdate = [ + _TOKEN_ID_TO_SET, + _TOKEN_ID_TO_SET, + _TOKEN_ID_TO_SET, + ]; + + const dataKeysToSet = [ + ERC725YDataKeys.LSP4.LSP4Metadata, + _NFT_ICON_DATA_KEY, + _NFT_MARKET_PLACE_URLS__DATA_KEY, + ]; + + const dataValuesToSet = [ + lsp4MetadataValue, + nftIconValue, + nftMarketPlaceURLsValue, + ]; + + await lsp8Contract.setDataBatchForTokenIds( + tokenIdsToUpdate, + dataKeysToSet, + dataValuesToSet, + ); +} +``` + + + + + +### Set metadata on different tokenIds + +To set for instance the same data key-value pair (_e.g: `LSP4Metadata`_) for 3 x different `tokenId`s, the parameters of `setDataBatchForTokenIds(bytes32[],bytes32[],bytes[])` can be used as follow: + + + + + +```solidity +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.12; + +import { + ILSP8IdentifiableDigitalAsset as ILSP8 +} from "@lukso/lsp-smart-contracts/contracts/LSP8IdentifiableDigitalAsset/ILSP8IdentifiableDigitalAsset.sol"; +import { + _LSP4_METADATA_KEY +} from "@lukso/lsp-smart-contracts/contracts/LSP4DigitalAssetMetadata/LSP4Constants.sol"; + +bytes32 constant _FIRST_TOKEN_ID_TO_SET = 0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe; +bytes32 constant _SECOND_TOKEN_ID_TO_SET = 0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef; +bytes32 constant _THIRD_TOKEN_ID_TO_SET = 0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d; + +function setMultipleDataForSingleTokenId( + ILSP8 lsp8Contract, + bytes memory firstTokenIdLsp4MetadataValue, + bytes memory secondTokenIdLsp4MetadataValue, + bytes memory thirdTokenIdLsp4MetadataValue +) { + bytes32[] memory tokenIdsToUpdate = new bytes32[](3); + bytes32[] memory dataKeysToSet = new bytes32[](3); + bytes[] memory dataValuesToSet = new bytes[](3); + + tokenIdsToUpdate[0] = _FIRST_TOKEN_ID_TO_SET; + tokenIdsToUpdate[1] = _SECOND_TOKEN_ID_TO_SET; + tokenIdsToUpdate[2] = _THIRD_TOKEN_ID_TO_SET; + + // we are setting the metadata for 3 x different tokenIds + dataKeysToSet[0] = _LSP4_METADATA_KEY; + dataKeysToSet[1] = _LSP4_METADATA_KEY; + dataKeysToSet[2] = _LSP4_METADATA_KEY; + + dataValuesToSet[0] = firstTokenIdLsp4MetadataValue; + dataValuesToSet[1] = secondTokenIdLsp4MetadataValue; + dataValuesToSet[2] = thirdTokenIdLsp4MetadataValue; + + lsp8Contract.setDataBatchForTokenIds( + tokenIdsToUpdate, + dataKeysToSet, + dataValuesToSet + ); +} +``` + + + + + +```js +import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'; + +const _FIRST_TOKEN_ID_TO_SET = + '0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe'; +const _SECOND_TOKEN_ID_TO_SET = + '0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef'; +const _THIRD_TOKEN_ID_TO_SET = + '0xf00df00df00df00df00df00df00df00df00df00df00df00df00df00df00df00d'; + +async function setMultipleDataForSingleTokenId( + lsp8Contract, + firstTokenIdLsp4MetadataValue, + secondTokenIdLsp4MetadataValue, + thirdTokenIdLsp4MetadataValue, +) { + const tokenIdsToUpdate = [ + _FIRST_TOKEN_ID_TO_SET, + _SECOND_TOKEN_ID_TO_SET, + _THIRD_TOKEN_ID_TO_SET, + ]; + + const dataKeysToSet = [ + ERC725YDataKeys.LSP4.LSP4Metadata, + ERC725YDataKeys.LSP4.LSP4Metadata, + ERC725YDataKeys.LSP4.LSP4Metadata, + ]; + + const dataValuesToSet = [ + firstTokenIdLsp4MetadataValue, + secondTokenIdLsp4MetadataValue, + thirdTokenIdLsp4MetadataValue, + ]; + + await lsp8Contract.setDataBatchForTokenIds( + tokenIdsToUpdate, + dataKeysToSet, + dataValuesToSet, + ); +} +``` + + + + + +## Check if the metadata of a specific NFT (tokenId) has changed + +Since LSP8 uses [ERC725Y](/standards/erc725#erc725y-generic-data-keyvalue-store) under the hood, the URI pointing to the metadata of a specific tokenId can be changed inside the ERC725Y storage of the LSP8 contract. + +We have seen in the previous section [**how to set metadata for one or multiple tokenIds**](#setting-metadata-for-one-or-multiple-tokenids). + +The two functions `setDataForTokenId(...)` and `setDataBatchForTokenIds(...)` emit a [`TokenIdDataChanged`](../contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#tokeniddatachanged) event. You can listen for this event in the LSP8 contract from your dApp, filtering for the `LSP4Metadata` data key to check if the metadata of a tokenId has been changed. You can do so by filtering the first parameter with the `tokenId` and the second parameter with the [bytes32 value of the `LSP4Metadata` data key](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata). diff --git a/docs/contracts/overview/Token/create-token.md b/docs/contracts/overview/Token/create-token.md index 097fad1fc..087b8da7e 100644 --- a/docs/contracts/overview/Token/create-token.md +++ b/docs/contracts/overview/Token/create-token.md @@ -73,7 +73,7 @@ contract MyToken is LSP7DigitalAsset { ## LSP7 Tokens extensions -The `@lukso/lsp7-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that enables to include functionalities for building your token through inheritance. +The `@lukso/lsp7-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that can be added through inheritance. This enables to include specific functionalities for building your token. | Extension contract | Description | | :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | diff --git a/docs/contracts/overview/Token/index.md b/docs/contracts/overview/Token/index.md index ade1a2eb8..938589115 100644 --- a/docs/contracts/overview/Token/index.md +++ b/docs/contracts/overview/Token/index.md @@ -20,7 +20,7 @@ The **LSP7DigitalAsset** contract represents digital assets for fungible tokens ## Installation & Usage -The LSP7 smart contracts and their ABIs are available are available as their own individual package. To use them, install `@lukso/lsp7-contracts` as a dependency in your project. +The LSP7 smart contracts and their ABIs are available are available in their own individual package. To use them, install `@lukso/lsp7-contracts` as a dependency in your project. @@ -46,7 +46,7 @@ pnpm add @lukso/lsp7-contracts -`LSP7DigitalAsset.sol` is an `abstract` contracts that is not deployable as is, because it does not contain any public functions by default to manage token supply (_e.g: no public `mint(...)` or `burn(...)` functions_). You can either: +`LSP7DigitalAsset.sol` is an `abstract` contract that is not deployable as is, because it does not contain any public functions by default to manage token supply (_e.g: no public `mint(...)` or `burn(...)` functions_). You can either: - the `LSP7Mintable` preset contract that contains a public `mint(...)` function callable only by the contract's owner. - or extend the `LSP7DigitalAsset` contract (_see below_) and create your own supply mechanism by defining public methods that use the internal `_mint(...)` and `_burn(...)` functions. diff --git a/docs/contracts/overview/Token/transfer-events.md b/docs/contracts/overview/Token/transfer-events.md deleted file mode 100644 index b59811b53..000000000 --- a/docs/contracts/overview/Token/transfer-events.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Listen for Transfer events -sidebar_position: 3 ---- - -# Listen for Transfer events From 172c585fbdde12c5c9c9b4c6b51fce58c8a05960 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Mon, 21 Oct 2024 08:51:44 +0200 Subject: [PATCH 5/6] fix broken links --- docs/contracts/overview/NFT/create-nft-collection.md | 10 +++++----- docs/contracts/overview/NFT/set-nft-metadata.md | 4 ++-- docs/contracts/overview/Token/create-token.md | 8 ++++---- docs/learn/migrate/migrate-erc20-to-lsp7.md | 2 +- docs/learn/migrate/migrate-erc721-to-lsp8.md | 2 +- docs/learn/migrate/migrate-to-lukso.md | 2 +- src/components/ContractCardsGallery/index.tsx | 8 ++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/contracts/overview/NFT/create-nft-collection.md b/docs/contracts/overview/NFT/create-nft-collection.md index b33036c4b..0361dc88f 100644 --- a/docs/contracts/overview/NFT/create-nft-collection.md +++ b/docs/contracts/overview/NFT/create-nft-collection.md @@ -45,8 +45,8 @@ contract BasicNFTCollection is LSP8IdentifiableDigitalAsset { The `@lukso/lsp8-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that can be added through inheritance. This enables to include specific functionalities for building your token. -| Extension contract | Description | -| :------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | -| [`LSP8Burnable.sol`](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md) | exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. | -| [`LSP8CappedSupply.sol`](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md) | enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. | -| [`LSP8Enumerable.sol`](../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md) | functionality to enumerate the list of NFTs in a collection. | +| Extension contract | Description | +| :---------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | +| [`LSP8Burnable.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md) | exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. | +| [`LSP8CappedSupply.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md) | enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. | +| [`LSP8Enumerable.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md) | functionality to enumerate the list of NFTs in a collection. | diff --git a/docs/contracts/overview/NFT/set-nft-metadata.md b/docs/contracts/overview/NFT/set-nft-metadata.md index f8b8cead9..fee3c11f6 100644 --- a/docs/contracts/overview/NFT/set-nft-metadata.md +++ b/docs/contracts/overview/NFT/set-nft-metadata.md @@ -8,7 +8,7 @@ import TabItem from '@theme/TabItem'; # Set NFT Metadata -The function [`setDataBatchForTokenIds(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatchfortokenids) can be used to set multiple [data key-value](/standards/erc725.md#erc725y-generic-data-keyvalue-store) pairs at once for one or multiple tokenIds. +The function [`setDataBatchForTokenIds(...)`](../../contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatchfortokenids) can be used to set multiple [data key-value](/standards/erc725.md#erc725y-generic-data-keyvalue-store) pairs at once for one or multiple tokenIds. ## Examples @@ -226,4 +226,4 @@ Since LSP8 uses [ERC725Y](/standards/erc725#erc725y-generic-data-keyvalue-store) We have seen in the previous section [**how to set metadata for one or multiple tokenIds**](#setting-metadata-for-one-or-multiple-tokenids). -The two functions `setDataForTokenId(...)` and `setDataBatchForTokenIds(...)` emit a [`TokenIdDataChanged`](../contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#tokeniddatachanged) event. You can listen for this event in the LSP8 contract from your dApp, filtering for the `LSP4Metadata` data key to check if the metadata of a tokenId has been changed. You can do so by filtering the first parameter with the `tokenId` and the second parameter with the [bytes32 value of the `LSP4Metadata` data key](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata). +The two functions `setDataForTokenId(...)` and `setDataBatchForTokenIds(...)` emit a [`TokenIdDataChanged`](../../contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#tokeniddatachanged) event. You can listen for this event in the LSP8 contract from your dApp, filtering for the `LSP4Metadata` data key to check if the metadata of a tokenId has been changed. You can do so by filtering the first parameter with the `tokenId` and the second parameter with the [bytes32 value of the `LSP4Metadata` data key](../../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata). diff --git a/docs/contracts/overview/Token/create-token.md b/docs/contracts/overview/Token/create-token.md index 087b8da7e..19f39a695 100644 --- a/docs/contracts/overview/Token/create-token.md +++ b/docs/contracts/overview/Token/create-token.md @@ -75,10 +75,10 @@ contract MyToken is LSP7DigitalAsset { The `@lukso/lsp7-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that can be added through inheritance. This enables to include specific functionalities for building your token. -| Extension contract | Description | -| :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | -| [`LSP7Burnable.sol`](../contracts/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md) | Exposes a public `burn(...)` function that allows any token holder or operator to burn any amount of tokens. | -| [`LSP7CappedSupply.sol`](../contracts/contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md) | Enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of tokens that can be minted. | +| Extension contract | Description | +| :---------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| [`LSP7Burnable.sol`](../../contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md) | Exposes a public `burn(...)` function that allows any token holder or operator to burn any amount of tokens. | +| [`LSP7CappedSupply.sol`](../../contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md) | Enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of tokens that can be minted. | If your token contract uses the proxy pattern with initialize functions, use the `InitAbstract` version of these extension contracts (_e.g: `LSP7Burnable` -> `LSP7BurnableInitAbstract`_). diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md index fccf82d91..726e90f1e 100644 --- a/docs/learn/migrate/migrate-erc20-to-lsp7.md +++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md @@ -21,7 +21,7 @@ import Erc20LSP7Table from '@site/src/components/Erc20LSP7Table'; :::info Resources -See the [contract overview](../../contracts/overview/DigitalAssets#comparisons-with-erc20--erc721) page for the interface differences between ERC20 and LSP7. +See the [contract overview](../../contracts/overview/Token/index.md#comparisons-with-erc20--erc721) page for the interface differences between ERC20 and LSP7. ::: diff --git a/docs/learn/migrate/migrate-erc721-to-lsp8.md b/docs/learn/migrate/migrate-erc721-to-lsp8.md index f3a68da0d..a61e608ef 100644 --- a/docs/learn/migrate/migrate-erc721-to-lsp8.md +++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md @@ -21,7 +21,7 @@ import Erc721LSP8Table from '@site/src/components/Erc721LSP8Table'; :::info Resources -See the [contract overview](../../contracts/overview/DigitalAssets#comparisons-with-erc20--erc721) page for the interface differences between ERC721 and LSP8. +See the [contract overview](../../contracts/overview/NFT/index.md#comparisons-with-erc20--erc721) page for the interface differences between ERC721 and LSP8. ::: diff --git a/docs/learn/migrate/migrate-to-lukso.md b/docs/learn/migrate/migrate-to-lukso.md index 4daed41b4..0d51a8623 100644 --- a/docs/learn/migrate/migrate-to-lukso.md +++ b/docs/learn/migrate/migrate-to-lukso.md @@ -62,7 +62,7 @@ Some real-life examples for a user's Universal Profile could be: :::info -For more details on the different functions and features between ERC20 and LSP7 or ERC721 and LSP8, check the [**Contracts > Digital Assets**](../../contracts/overview/DigitalAssets.md) section. +For more details on the different functions and features between ERC20 and LSP7 or ERC721 and LSP8, check the [**Contracts > Token**](../../contracts/overview/Token/index.md)or [**Contracts > NFT**](../../contracts/overview/NFT/index.md) sections. ::: diff --git a/src/components/ContractCardsGallery/index.tsx b/src/components/ContractCardsGallery/index.tsx index 3eac101b4..f65f9c45b 100644 --- a/src/components/ContractCardsGallery/index.tsx +++ b/src/components/ContractCardsGallery/index.tsx @@ -58,21 +58,21 @@ const Contracts_AccountsInteraction = [ const Contracts_DigitalAssets = [ { name: '🔍 LSP4 Digital Asset Metadata', - url: '/contracts/overview/DigitalAssets/#lsp4-digital-asset-metadata', - urlABI: '/contracts/contracts/LSP6KeyManager', + url: '', + urlABI: '/contracts/contracts/LSP4DigitalAssetMetadata', description: 'Enables to add metadata to any digital asset contract (token or NFT).', }, { name: '🪙 LSP7 Digital Asset', - url: '/contracts/overview/DigitalAssets/#lsp7-digital-asset', + url: '/contracts/overview/Token', urlABI: '/contracts/contracts/LSP7DigitalAsset', description: 'Creates your own fungible token with the possibility to make it divisible or not.', }, { name: '🎨 LSP8 Identifiable Digital Asset', - url: '/contracts/overview/DigitalAssets/#lsp8-identifiable-digital-asset', + url: '/contracts/overview/NFT', urlABI: '/contracts/contracts/LSP8IdentifiableDigitalAsset', description: 'Creates a non-fungible token where each NFT can be represented differently (numbers, serial numbers, an ERC725Y contract per NFT...).', From 7d25ed32ddc3261917278dc7744d88dd72615cb4 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Mon, 21 Oct 2024 18:04:21 +0200 Subject: [PATCH 6/6] address review comments --- docs/contracts/overview/NFT/create-nft-collection.md | 10 +++++----- docs/contracts/overview/NFT/index.md | 2 +- docs/contracts/overview/Token/create-token.md | 8 ++++---- .../overview/Token/customise-transfer-behaviour.md | 12 +++--------- docs/standards/tokens/introduction.md | 6 +----- 5 files changed, 14 insertions(+), 24 deletions(-) diff --git a/docs/contracts/overview/NFT/create-nft-collection.md b/docs/contracts/overview/NFT/create-nft-collection.md index 0361dc88f..bb6285352 100644 --- a/docs/contracts/overview/NFT/create-nft-collection.md +++ b/docs/contracts/overview/NFT/create-nft-collection.md @@ -45,8 +45,8 @@ contract BasicNFTCollection is LSP8IdentifiableDigitalAsset { The `@lukso/lsp8-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that can be added through inheritance. This enables to include specific functionalities for building your token. -| Extension contract | Description | -| :---------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | -| [`LSP8Burnable.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md) | exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. | -| [`LSP8CappedSupply.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md) | enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of NFT that can be minted in the collection. | -| [`LSP8Enumerable.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md) | functionality to enumerate the list of NFTs in a collection. | +| Extension contract | Description | +| :---------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | +| [`LSP8Burnable.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md) | exposes a public `burn(...)` function that allows any NFT holder or operator to burn a specific NFT tokenId. | +| [`LSP8CappedSupply.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8CappedSupply.md) | enable to specify a maximum supply on deployment / initialization, which caps the maximum amount of NFT that can be minted in the collection. | +| [`LSP8Enumerable.sol`](../../contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Enumerable.md) | functionality to enumerate the list of NFTs in a collection. | diff --git a/docs/contracts/overview/NFT/index.md b/docs/contracts/overview/NFT/index.md index 05ae5e053..1c4628172 100644 --- a/docs/contracts/overview/NFT/index.md +++ b/docs/contracts/overview/NFT/index.md @@ -50,7 +50,7 @@ pnpm add @lukso/lsp8-contracts `LSP8IdentifiableDigitalAsset.sol` is an `abstract` contract that is not deployable as is, because it does not contain any public functions by default to manage token supply (_e.g: no public `mint(...)` or `burn(...)` functions_). You can either: -- the `LSP8Mintable` preset contract that contains a public `mint(...)` function callable only by the contract's owner. +- use the `LSP8Mintable` preset contract that contains a public `mint(...)` function callable only by the contract's owner. - or extend the `LSP8IdentifiableDigitalAsset` contract (_see below_) and create your own supply mechanism by defining public methods that use the internal `_mint(...)` and `_burn(...)` functions. ## Comparisons with ERC721 diff --git a/docs/contracts/overview/Token/create-token.md b/docs/contracts/overview/Token/create-token.md index 19f39a695..1e47c3672 100644 --- a/docs/contracts/overview/Token/create-token.md +++ b/docs/contracts/overview/Token/create-token.md @@ -75,10 +75,10 @@ contract MyToken is LSP7DigitalAsset { The `@lukso/lsp7-contracts` package includes token extensions (similarly to OpenZeppelin contracts) that can be added through inheritance. This enables to include specific functionalities for building your token. -| Extension contract | Description | -| :---------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | -| [`LSP7Burnable.sol`](../../contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md) | Exposes a public `burn(...)` function that allows any token holder or operator to burn any amount of tokens. | -| [`LSP7CappedSupply.sol`](../../contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md) | Enable to specify a maximum supply on deployment / initialization, which cap the maximum amount of tokens that can be minted. | +| Extension contract | Description | +| :---------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------- | +| [`LSP7Burnable.sol`](../../contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md) | Exposes a public `burn(...)` function that allows any token holder or operator to burn any amount of tokens. | +| [`LSP7CappedSupply.sol`](../../contracts/LSP7DigitalAsset/extensions/LSP7CappedSupply.md) | Enable to specify a maximum supply on deployment / initialization, which caps the maximum amount of tokens that can be minted. | If your token contract uses the proxy pattern with initialize functions, use the `InitAbstract` version of these extension contracts (_e.g: `LSP7Burnable` -> `LSP7BurnableInitAbstract`_). diff --git a/docs/contracts/overview/Token/customise-transfer-behaviour.md b/docs/contracts/overview/Token/customise-transfer-behaviour.md index 0aa76c1f9..ad42a760c 100644 --- a/docs/contracts/overview/Token/customise-transfer-behaviour.md +++ b/docs/contracts/overview/Token/customise-transfer-behaviour.md @@ -5,12 +5,6 @@ sidebar_position: 2 # Customize transfer behaviour - - ## `_beforeTokenTransfer` and `_afterTokenTransfer` hooks `The LSP7DigitalAsset contract` implementation includes two hooks to add custom behaviour to run logic before or after the total supply of tokens has been updated in the contract's storage. This can be done via the [`_beforeTokenTransfer(...)`](../../contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_beforetokentransfer) and [`_afterTokenTransfer(...)`](../../contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_aftertokentransfer) functions. @@ -76,7 +70,7 @@ contract MyToken is LSP7DigitalAsset { bytes memory tokensReceivedTxValue = _getData(tokensReceivedTxDataKey); // sanity check to ensure we can abi-decode correctly - require(tokensSentTxValue.length == 32, "Invalid uint256 encoded value under `TokensSentTx:
data key"); + require(tokensSentTxValue.length == 32, "Invalid uint256 encoded value under `TokensSentTx:
` data key"); require( tokensReceivedTxValue.length == 32, "Invalid uint256 encoded value under `TokensReceivedTx:
data key" @@ -96,8 +90,8 @@ contract MyToken is LSP7DigitalAsset { ``` -This example is minimalist and only stores a counter as a number. Still, any info related to the token transfer could be stored during the transfer (_e.g: the amount, the data passed, the gas price, the balance before and after, etc..._). This way, the storage of the token contract can act, for instance, as: 💡 +This example is minimalist and only stores a counter as a number. Still, any info related to the token transfer could be stored during the transfer (_e.g: the amount, the data passed, the gas price, the balance before and after, etc..._). This way, the storage of the token contract can act, for instance, as: - A _"mini explorer"_ for the token contract (without relying on a block explorer and reviewing the complete list of transactions). - To query the transactions for a user and provide an analytical view of their balance changes, demonstrating its data analysis capabilities. -- Showcase which user, smart contract address or protocol are the most active users and traders for this token (being the ones with the higher count under the ) +- Showcase which user, smart contract address or protocol are the most active users and traders for this token (being the ones with the higher count under the `TokensSentTx:
` data key). diff --git a/docs/standards/tokens/introduction.md b/docs/standards/tokens/introduction.md index 532c75e2b..51dac1990 100644 --- a/docs/standards/tokens/introduction.md +++ b/docs/standards/tokens/introduction.md @@ -34,11 +34,7 @@ As for features, these standards are just representing **incremental tokenIds** ![Tokens & NFT Standards LSP4, LSP7 and LSP8](/img/standards/LUKSO-Tokens-NFT-Standards.jpeg) -## Random Notes taken from other places - -Their functions are simpler, more straight forward and unified. - -**Similar function names** +The functions of the LSP7 and LSP8 standards are overall simpler, more straightforward and unified, with a **similar function names** for both LSP7 and LSP8.yarn Both functions in LSP7 and LSP8 have the same name (`transfer`) to transfer assets. This is easier compared to ERC20 and ERC721 that use different naming (`transfer` for ERC20 vs `transferFrom` in ERC721 to transfer tokens as the token owner).