diff --git a/docs/learn/digital-assets/metadata-management/edit-token-metadata.md b/docs/learn/digital-assets/metadata-management/edit-token-metadata.md
index ad8bd1da5..6f91b65db 100644
--- a/docs/learn/digital-assets/metadata-management/edit-token-metadata.md
+++ b/docs/learn/digital-assets/metadata-management/edit-token-metadata.md
@@ -9,9 +9,13 @@ import TabItem from '@theme/TabItem';
# Set LSP7 Token Metadata
-In this guide, you will learn how to edit the [`LSP4Metadata`](../../../standards/tokens/LSP4-Digital-Asset-Metadata.md) of an [LSP7 Digital Asset](../../../standards/tokens/LSP7-Digital-Asset.md).
+> 👇🏻 Hands on 📽️ _ethers.js_ workshop video for the [**Oxford Blockchain Society**](https://x.com/oxfordblocksoc) from March 2024.
-To edit an LSP7 Digital Asset metadata, you will need to:
+
+
+
+
+In this guide, you will learn how to edit the [`LSP4Metadata`](../../../standards/tokens/LSP4-Digital-Asset-Metadata.md) of an [LSP7 Digital Asset](../../../standards/tokens/LSP7-Digital-Asset.md). You will need to:
1. get your assets ready (images, videos, etc.) and create a metadata JSON file
2. upload these files using a preferred storage provider
diff --git a/docs/learn/getting-started.mdx b/docs/learn/getting-started.mdx
index e05c00931..e21b87281 100644
--- a/docs/learn/getting-started.mdx
+++ b/docs/learn/getting-started.mdx
@@ -29,43 +29,63 @@ export const CardData = [
],
},
{
- image: ValidatorIcon,
- imageTitle: 'Validator Icon',
- cardHeading: 'Validators',
+ image: SmartContractDevIcon,
+ imageTitle: 'Smart Contract Developer Icon',
+ cardHeading: 'Smart Contract Developer',
cardContent: [
{
- linkText: 'Run a node for LUKSO',
- linkPath: '../../networks/mainnet/running-a-node',
+ linkText: 'Get started with Tokens and NFTs',
+ linkPath: '../learn/digital-assets/getting-started',
},
{
- linkText: 'Become a Validator',
- linkPath: '../../networks/mainnet/become-a-validator',
+ linkText: 'Create a token',
+ linkPath: '../learn/digital-assets/token/create-lsp7-token',
},
{
- linkText: 'Checkout the Network Parameters',
- linkPath: '../../networks/mainnet/parameters',
+ linkText: 'Create an Automatic Token Forwarder for your UP',
+ linkPath: '../learn/universal-profile/universal-receiver/create-receiver-forwarder',
},
],
},
{
image: SmartContractDevIcon,
- imageTitle: 'Smart Contract Developer Icon',
- cardHeading: 'Smart Contract Developer',
+ imageTitle: 'Quickstart Integration',
+ cardHeading: 'Quickstart Integration',
cardContent: [
{
- linkText: 'Get started with Tokens and NFTs',
- linkPath: '../learn/digital-assets/getting-started',
+ linkText: 'Migrate to LUKSO',
+ linkPath: '../learn/migrate/migrate-to-lukso',
},
{
- linkText: 'Create a token',
- linkPath: '../learn/digital-assets/token/create-lsp7-token',
+ linkText: 'Refactor a Solidity ERC20 token to LSP7',
+ linkPath: '../learn/migrate/migrate-erc20-to-lsp7',
},
{
- linkText: 'Migrate ERC20 a token to LSP7',
- linkPath: '../learn/migrate/migrate-erc20-to-lsp7',
+ linkText: 'Refactor a Solidity ERC721 NFT to LSP8',
+ linkPath: '../learn/migrate/migrate-erc721-to-lsp8',
+ },
+ ],
+ },
+ {
+ image: ValidatorIcon,
+ imageTitle: 'Validator Icon',
+ cardHeading: 'Validators',
+ cardContent: [
+ {
+ linkText: 'Run a node for LUKSO',
+ linkPath: '../../networks/mainnet/running-a-node',
+ },
+ {
+ linkText: 'Become a Validator',
+ linkPath: '../../networks/mainnet/become-a-validator',
+ },
+ {
+ linkText: 'Checkout the Network Parameters',
+ linkPath: '../../networks/mainnet/parameters',
},
],
},
+
];
# Quick Start
diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md
index ba60a2227..85e1b38b0 100644
--- a/docs/learn/migrate/migrate-erc20-to-lsp7.md
+++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md
@@ -4,21 +4,32 @@ sidebar_position: 2
description: Learn how to migrate your ERC20 token to the LSP7 Digital Asset standard on LUKSO.
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
import Erc20LSP7Table from '@site/src/components/Erc20LSP7Table';
# 🪙 Migrate ERC20 to LSP7
+> 👇🏻 Hands on 📽️ Solidity Workshop Video for the [**Oxford Blockchain Society**](https://x.com/oxfordblocksoc) from March 2024.
+
+
+
+
+
[LSP7DigitalAsset](../../standards/tokens/LSP7-Digital-Asset.md) is a new token standard that offers a wider range of functionality compared to [ERC20](https://eips.ethereum.org/EIPS/eip-20), as described in the [standard section](../../standards/tokens/LSP7-Digital-Asset.md). For migrating from ERC20 to LSP7, developers need to be aware of several key differences.
-:::info
+:::info Resources
-If you need more details about the interface differences between ERC20 and LSP7, please visit our [contract overview](../../contracts/overview/DigitalAssets#comparisons-with-erc20--erc721) page.
+See the [contract overview](../../contracts/overview/DigitalAssets#comparisons-with-erc20--erc721) page for the interface differences between ERC20 and LSP7.
:::
-## Smart Contract Building
+## Comparisons
-Usually, to create an ERC20 token, `ERC20` is imported from [@openzeppelin/contracts](https://www.npmjs.com/package/@openzeppelin/contracts) package, and inherited.
+### Solidity code
+
+Usually, to create an ERC20 token, we import and inherit the `ERC20` contract from the [@openzeppelin/contracts](https://www.npmjs.com/package/@openzeppelin/contracts) package.
```solidity title="ERC20 Token"
// SPDX-License-Identifier: MIT
@@ -33,9 +44,12 @@ contract MyERC20Token is ERC20 {
}
```
-To create an LSP7 token, `LSP7` is imported from [@lukso/lsp7-contracts](https://www.npmjs.com/package/@lukso/lsp7-contracts) package, and inherited.
+To create an LSP7 token, we should instead import `LSP7DigitalAsset` from the [`@lukso/lsp7-contracts`](https://www.npmjs.com/package/@lukso/lsp7-contracts) package, and replace it in the inheritance.
+
+To deploy an `LSP7DigitalAsset` we can use the same [`constructor`](../../contracts/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md#constructor) parameters. but we also need to specify 2 extra parameters (_explanations of params provided in the code comments below_).
-The constructor arguments definitions can be found explained in the [constructor API](../../contracts/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md#constructor) section.
+- the `lsp4TokenType`.
+- if the token `isNonDivisible`.
```solidity title="LSP7 Token"
// SPDX-License-Identifier: Apache-2.0
@@ -43,12 +57,15 @@ pragma solidity ^0.8.15;
import "@lukso/lsp7-contracts/contracts/LSP7DigitalAsset.sol";
+// highlight-next-line
contract MyLSP7Token is LSP7DigitalAsset {
constructor(
string memory name, // Name of the token
string memory symbol, // Symbol of the token
address tokenOwner, // Owner able to add extensions and change metadata
+ // highlight-next-line
uint256 lsp4tokenType, // 0 if representing a fungible token, 1 if representing an NFT
+ // highlight-next-line
bool isNonDivisible // false for decimals equal to 18, true for decimals equal to 0
) LSP7DigitalAsset(name, symbol, tokenOwner, lsp4tokenType, isNonDivisible) {
// _mint(to, amount, force, data)
@@ -59,21 +76,65 @@ contract MyLSP7Token is LSP7DigitalAsset {
}
```
-## Behavior
+### Functions & Behaviors
Below are the function signatures of the transfer functions for ERC20 and LSP7, respectively.
-ERC20: `function transferFrom(address from, address to, uint256 amount);`
+
+
+There are 3 main differences for LSP7 to note
+
+- **Additional `force` parameter**: for the [`mint(...)`](../../contracts/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md#mint) and [`transfer(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#ransfer) functions.
+
+For full compatibility with ERC20 behavior (where the recipient can be any address), set this to `true`. Setting it to `false` will only allow the transfer to smart contract addresses supporting the [**LSP1UniversalReceiver** interfaceId](../../contracts/interface-ids.md).
+
+> See the [**LSP7 Standard > `force` mint and transfer**](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks#force-mint-and-transfer) section for more details.
-LSP7: `function transfer(address from, address to, uint256 amount, bool force, bytes data);`
+- **Additional `data` field**: for the `mint(...)`, `transfer(...)`, and [`burn(...)`](../../contracts/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md#burn) functions.
-- For LSP7, **mint and transfer functions will have a `force` additional field**. For full compatibility with ERC20 behavior (where the recipient can be any address), set this to `true`. Setting it to `false` will only allow the transfer to smart contract addresses supporting the LSP1 interfaceId. (Check [LSP1UniversalReceiver section](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) in LSP7DigitalAsset for more info).
+For full compatibility with ERC20 behavior, set this to empty bytes `""`. This data is only relevant when the recipient is a smart contract that supports the LSP1 interfaceId, where the data will be sent and the recipient can act on it (_e.g., reject the transfer, forward the tokens to a vault, etc..._).
-- For LSP7, **mint, transfer, and burn functions will have `data` as an additional field**. For full compatibility with ERC20 behavior, set this to empty bytes. This data will only be relevant when the recipient is a smart contract address supporting the LSP1 interfaceId (Check [LSP1UniversalReceiver section](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) in LSP7DigitalAsset for more info), where the data will be sent and the recipient can act on it (e.g., reject the transfer, forward the tokens to a vault, etc.).
+> See the [**LSP7 Standard > LSP1 Token Hooks**](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) section for more details.
-- **LSP7 metadata is generic**, in contrast to ERC20 where the metadata is limited to name and symbol. The [generic key-value store](../../standards/lsp-background/erc725.md#erc725y-generic-data-keyvalue-store) in LSP7 allows for storing any possible data.
+- **LSP7 metadata is generic**: via a [flexible data key / value store](<(../../standards/lsp-background/erc725.md#erc725y-generic-data-keyvalue-store)>). It can be set and retrieved via [`setData(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#setdata) / [`setDataBatch(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#setdatabatch) and [`getData(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#getdata) / [`getDataBatch(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#getdatabatch).
-## Interacting with Contracts
+ERC20 metadata is limited to `name()` and `symbol()`. LSP7 allows to store any data after deployment without limitations.
+
+### Interact with the Token Contract
:::info
@@ -81,11 +142,11 @@ To check function definitions and explanations of behavior and each parameter, c
:::
-To interact with LSP7DigitalAsset contract, different functions should be called. This is a table comparing function definitions:
+To interact with the LSP7DigitalAsset contract, different functions should be called. This is a table comparing the different function definitions:
-## dApps and Indexers
+### Events
:::info
@@ -93,32 +154,51 @@ To check event definitions and explanations of behavior and each parameter, chec
:::
-The table below shows the different event definitions that should be used to track activity on an LSP7-DigitalAsset contract.
+Services like dApps and Indexers can use different events from LSP7 to listen to activities. The table below shows the different event definitions that should be used to track activity on an LSP7-DigitalAsset contract.
-| ERC20 Event | LSP7 Event |
-| ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
-| `Transfer(address indexed from, address indexed to, uint256 value)` | `Transfer(address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data)` |
-| `Approval(address indexed owner, address indexed spender, uint256 value)` | `OperatorAuthorizationChanged(address indexed operator, address indexed tokenOwner, uint256 indexed amount, bytes operatorNotificationData)` |
-| _No equivalent_ | `OperatorRevoked(address indexed operator, address indexed tokenOwner, bool indexed notified, bytes operatorNotificationData)` |
+| ERC20 Event | LSP7 Event |
+| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+|
Transfer( address indexed from, address indexed to, uint256 value );
|
Transfer( address indexed operator, address indexed from, address indexed to, uint256 amount, bool force, bytes data )
|
+|
Approval( address indexed owner, address indexed spender, uint256 value )
|
## Metadata Management
### Basic Token Information
-In ERC20, the name and symbol of a token can be retrieved by calling their own function:
+
+
+
+
+**ERC20**
```javascript
-// ERC20
const name = await token.name();
const symbol = await token.symbol();
```
-In LSP7, the token name and symbol can be retrieved with [getData](../../contracts/contracts/ERC725/ERC725.md#getdata) function, since LSP7 uses a generic metadata key value store:
+
+
+
+
+**How to retrieve?**
+
+In ERC20, the name and symbol of a token can be retrieved by calling their own function.
+
+
+
+**How to retrieve?**
+
+In LSP7, the token name and symbol can be retrieved with [`getData(bytes32)`](../../contracts/contracts/ERC725/ERC725.md#getdata). They are stored in the generic metadata key-value store under the data keys [`LSP4TokenName`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4tokenname) and [`LSP4TokenSymbol`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4tokensymbol).
+
+Once you have fetched the raw hex encoded value, you will need to decode it into a human readable string.
+
+
+
+
+You can import the list of data keys related to each individual LSP standard from one of our library. There are 2 options:
+
+
+
+
+
+For dApp developers, you can import the data keys from the `@lukso/lsp-smart-contracts` and use them directly in your scripts via _ethers.js_ or _web3.js_.
+
+```javascript
+import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts';
+
+const nameKey = ERC725YDataKeys.LSP4.LSP4TokenName;
+const symbolKey = ERC725YDataKeys.LSP4.LSP4TokenSymbol;
+
+const nameValue = await token.getData(nameKey); // 0x555020417374726f20373235
+const symbolValue = await token.getData(symbolKey); // 0x5550373235
+
+const name = ethers.toUtf8String(nameValue); // UP Astro 725
+const symbol = ethers.toUtf8String(symbolValue); // UP725
+```
+
+
+
+
+
+You can also obtain the full schema with all the definitions from our [`@erc725/erc725.js`](../../tools/erc725js/getting-started.md) library. **This library will also help you to [encode easily](../../tools/erc725js/methods.md#encodedata) data key value pairs.**
+
+You can also import the [full schema definition](../../tools/erc725js/schemas.md) of the LSP4 Metadata from `@erc725/erc725.js`. The library can also provide convenience for fetching, encoding and decoding.
+
+
+
+```javascript title="Example of decoding using the LSP4 schema and erc725.js"
+import { ERC725 } from '@erc725/erc725.js';
+import LSP4Schema from '@erc725/erc725.js/schemas/LSP4DigitalAssetMetadata.json';
+
+const nameKey = LSP4Schema.find((schema) => schema.name == 'LSP4TokenName').key;
+const symbolKey = LSP4Schema.find((schema) => schema.name == 'LSP4TokenSymbol').key;
+
+const nameValue = await token.getData(nameKey); // 0x555020417374726f20373235
+const symbolValue = await token.getData(symbolKey); // 0x5550373235
+
+const [name, symbol] = ERC725.decodeData([
+ {
+ keyName: 'LSP4TokenName',
+ value: nameValue,
+ },
+ {
+ keyName: 'LSP4TokenSymbol',
+ value: symbolValue,
+ },
+]);
+/**
+[
+ {
+ name: 'LSP4TokenName',
+ key: '0xdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1',
+ value: "UP Astro 725",
+ },
+ {
+ name: 'LSP4TokenSymbol',
+ key: '0x2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db932756',
+ value: "UP725",
+ },
+]
+*/
+```
+
+
+
+
+
+
+
### Extended Token Metadata
-:::info
+:::success Tutorial 🎥
-To learn more about setting and creating the LSP4Metadata JSON, check the [metadata](../digital-assets/metadata-management/metadata-preparation.md) section.
+See the [**Metadata Management**](../digital-assets/metadata-management/edit-token-metadata.md) guide + video for how to create and set the JSON metadata for your LSP7 Token.
:::
-LSP7 allows for more flexible and extensive metadata storage. You can store a JSON object containing additional token information:
+LSP7 allows for more flexible and extensible metadata. The [`LSP4Metadata`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata) is a JSON object that can contain many information about the token, including:
+
+- 🌐 **official link to websites** (_e.g: project website, social medias, community channels, etc..._).
+- 🖼️ **images** (token icon and backgrounds) to display the token in dApps, explorers, or decentralised exchanges.
+- 🏷️ **custom attributes** (can be displayed as badges on UIs).
```javascript
const metadataKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4Metadata'));
diff --git a/docs/learn/migrate/migrate-erc721-to-lsp8.md b/docs/learn/migrate/migrate-erc721-to-lsp8.md
index 58fbb05b1..1fff31f5f 100644
--- a/docs/learn/migrate/migrate-erc721-to-lsp8.md
+++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md
@@ -1,24 +1,35 @@
---
-sidebar_label: '🌅 ERC721 to LSP8'
+sidebar_label: '🖼️ ERC721 to LSP8'
sidebar_position: 3
description: Learn how to migrate your ERC721 token to the LSP8 Identifiable Digital Asset standard on LUKSO.
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
import Erc721LSP8Table from '@site/src/components/Erc721LSP8Table';
# 🖼️ Migrate ERC721 to LSP8
+> 👇🏻 Hands on 📽️ Solidity Workshop Video for the [**Oxford Blockchain Society**](https://x.com/oxfordblocksoc) from March 2024.
+
+
+
+
+
[LSP8IdentifiableDigitalAsset](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md) is a new token standard that offers a wider range of functionality compared to [ERC721](https://eips.ethereum.org/EIPS/eip-721), as described in the [standard section](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md). For migrating from ERC721 to LSP8, developers need to be aware of several key differences.
-:::info
+:::info Resources
-If you need more details about the interface differences between ERC721 and LSP8, please visit our [contract overview](../../contracts/overview/DigitalAssets#comparisons-with-erc20--erc721) page.
+See the [contract overview](../../contracts/overview/DigitalAssets#comparisons-with-erc20--erc721) page for the interface differences between ERC721 and LSP8.
:::
-## Smart Contract Building
+## Comparisons
+
+### Solidity code
-Usually, to create an ERC721 token, `ERC721` is imported from [@openzeppelin/contracts](https://www.npmjs.com/package/@openzeppelin/contracts) package, and inherited.
+Usually, to create an ERC721 token, we import and inherit the `ERC721` contract from the [@openzeppelin/contracts](https://www.npmjs.com/package/@openzeppelin/contracts) package.
```solidity title="ERC721 Token"
// SPDX-License-Identifier: MIT
@@ -33,48 +44,97 @@ contract MyERC721Token is ERC721 {
}
```
-To create an LSP8 NFT, `LSP8` is imported from [@lukso/lsp8-contracts](https://www.npmjs.com/package/@lukso/lsp8-contracts) package, and inherited.
+To create an LSP8 token, we should instead import `LSP8IdentifiableDigitalAsset` from the [`@lukso/lsp8-contracts`](https://www.npmjs.com/package/@lukso/lsp8-contracts) package, and replace it in the inheritance.
+
+To deploy an `LSP8IdentifiableDigitalAsset` we can use the same [`constructor`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md#constructor) parameters, but we also need to specify 2 extra parameters (_explanations of params provided in the code comments below_).
-The constructor arguments definitions can be found explained in the [constructor API](../../contracts/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md#constructor) section.
+- the `lsp4TokenType_`.
+- the `lsp8TokenIdFormat_`.
-```js
+```solidity title="LSP8 Token"
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.15;
import "@lukso/lsp8-contracts/contracts/LSP8IdentifiableDigitalAsset.sol";
+// highlight-next-line
contract MyLSP8Token is LSP8IdentifiableDigitalAsset {
constructor(
string memory name, // Name of the token
string memory symbol, // Symbol of the token
address tokenOwner, // Owner able to add extensions and change metadata
- uint256 lsp4TokenType_, // 1 if representing an NFT, 2 if representing an advanced collection of multiple NFTs
+ // highlight-next-line
+ uint256 lsp4TokenType_, // 1 if NFT, 2 if an advanced collection of multiple NFTs
+ // highlight-next-line
uint256 lsp8TokenIdFormat_ // 0 for compatibility with ERC721, check LSP8 specs for other values
) LSP8IdentifiableDigitalAsset(name, symbol, tokenOwner, lsp4TokenType_, lsp8TokenIdFormat_) {
- // Your constructor logic
- bytes32 tokenId = bytes32(uint256(1));
- _mint(tokenOwner, tokenId, true, "");
+ // _mint(to, tokenId, force, data)
+ // force: should be set to true to allow EOA to receive tokens
+ // data: only relevant if the `to` is a smart contract supporting LSP1.
+ _mint(tokenOwner, bytes32(uint256(1)), true, "");
}
}
```
-## Behavior
-
-- For LSP8, the tokenId is represented as `bytes32` in contrast with ERC721 where its represented as `uint256`. This design decision allow for more representation of tokenIds.
+### Functions & Behaviors
Below are the function signatures of the transfer functions for ERC721 and LSP8, respectively.
-ERC721: `function transferFrom(address from, address to, uint256 tokenId);`
+
+
+There are 4 main differences for LSP8 to note:
+
+- **TokenId representation**: In LSP8, the `tokenId` is represented as `bytes32` instead of `uint256` in ERC721. This allows for more flexible token identification schemes.
+
+- **Additional `force` parameter**: for the [`mint(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/presets/LSP8Mintable.md#mint) and [`transfer(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#transfer) functions.
+
+For full compatibility with ERC721 behavior (where the recipient can be any address), set this to `true`. Setting it to `false` will only allow the transfer to smart contract addresses supporting the [**LSP1UniversalReceiver** interfaceId](../../contracts/interface-ids.md).
+
+> See the [**LSP8 Standard > `force` mint and transfer**](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md#lsp1-token-hooks#force-mint-and-transfer) section for more details.
-LSP8: `function transfer(address from, address to, bytes32 tokenId, bool force, bytes data);`
+- **Additional `data` field**: for the `mint(...)`, `transfer(...)`, and [`burn(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md#burn) functions.
-- For LSP8, **mint and transfer functions will have a `force` additional field**. For full compatibility with ERC721 behavior (where the recipient can be any address), set this to `true`. Setting it to `false` will only allow the transfer to smart contract addresses supporting the LSP1 interfaceId. (Check [LSP1UniversalReceiver section](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md#lsp1-token-hooks) in LSP8IdentifiableDigitalAsset for more info).
+For full compatibility with ERC721 behavior, set this to empty bytes `""`. This data is only relevant when the recipient is a smart contract that supports the LSP1 interfaceId, where the data will be sent and the recipient can act on it (_e.g., reject the transfer, forward the tokens to a vault, etc..._).
-- For LSP8, **mint, transfer, and burn functions will have `data` as an additional field**. For full compatibility with ERC721 behavior, set this to empty bytes. This data will only be relevant when the recipient is a smart contract address supporting the LSP1 interfaceId (Check [LSP1UniversalReceiver section](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md#lsp1-token-hooks)in LSP8IdentifiableDigitalAsset for more info), where the data will be sent and the recipient can act on it (e.g., reject the transfer, forward the tokens to a vault, etc.).
+> See the [**LSP8 Standard > LSP1 Token Hooks**](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md#lsp1-token-hooks) section for more details.
-- **LSP8 metadata is generic**, in contrast to ERC721 where the metadata is limited to name and symbol and tokenURI. The [generic key-value store](../../standards/lsp-background/erc725.md#erc725y-generic-data-keyvalue-store) in LSP8 allows for storing any possible data.
+- **LSP8 metadata is generic**: via a [flexible data key / value store](<(../../standards/lsp-background/erc725.md#erc725y-generic-data-keyvalue-store)>). It can be set and retrieved via [`setData(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdata) / [`setDataBatch(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatabatch) and [`getData(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#getdata) / [`getDataBatch(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#getdatabatch).
-## Interacting with Contracts
+### Interact with the Token Contract
:::info
@@ -82,46 +142,65 @@ To check function definitions and explanations of behavior and each parameter, c
:::
-To interact with LSP8IdentifiableDigitalAsset contract, different functions should be called. This is a table comparing function definitions:
+To interact with the LSP8IdentifiableDigitalAsset contract, different functions should be called. This is a table comparing the different function definitions:
-## dApps and Indexers
+### Events
:::info
-To check event definitions and explanations of behavior and each parameter, check [API Reference](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md) section.
+To check event definitions and explanations of behavior and each parameter, check [API Reference](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#events) section.
:::
-The table below shows the different event definitions that should be used to track activity on an LSP8-IdentifiableDigitalAsset contract.
+Services like dApps and Indexers can use different events from LSP8 to listen to activities. The table below shows the different event definitions that should be used to track activity on an LSP8-IdentifiableDigitalAsset contract.
-| ERC721 Event | LSP8 Event |
-| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
-| `Transfer(address indexed from, address indexed to, uint256 indexed tokenId)` | `Transfer(address operator, address indexed from, address indexed to, bytes32 indexed tokenId, bool force, bytes data)` |
-| `Approval(address indexed owner, address indexed approved, uint256 indexed tokenId)` | `OperatorAuthorizationChanged(address indexed operator, address indexed tokenOwner, bytes32 indexed tokenId, bytes operatorNotificationData)` |
-| `ApprovalForAll(address indexed owner, address indexed operator, bool approved)` | _No direct equivalent_ |
-| _No equivalent_ | `OperatorRevoked(address indexed operator, address indexed tokenOwner, bytes32 indexed tokenId, bool notified, bytes operatorNotificationData)` |
+| ERC721 Event | LSP8 Event |
+| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+|
|
## Metadata Management
### Basic Token Information
-In ERC721, the name, symbol and the tokenURI of a tokenId can be retrieved by calling their own function:
+
+
+
+
+**ERC721**
```javascript
-// ERC721
const name = await token.name();
const symbol = await token.symbol();
const tokenURI = await token.tokenURI(tokenId);
```
-In LSP8, the token name and symbol can be retrieved with [getData](../../contracts/contracts/ERC725/ERC725.md#getdata) function, since LSP8 uses a generic metadata key value store:
+
+
+
+
+**How to retrieve?**
+
+In ERC721, the name, symbol, and tokenURI of a token can be retrieved by calling their own functions.
+
+
+
+**How to retrieve?**
-To learn more about setting and creating the LSP4Metadata JSON, check the [metadata](../digital-assets/metadata-management/metadata-preparation.md) section.
+In LSP8, the token name, symbol and base URI can be retrieved with [`getData(bytes32)`](../../contracts/contracts/ERC725/ERC725.md#getdata). They are stored in the generic metadata key-value store under the data keys [`LSP4TokenName`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4tokenname), [`LSP4TokenSymbol`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4tokensymbol) and [`LSP8TokenMetadataBaseURI`](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-8-IdentifiableDigitalAsset.md#lsp8tokenmetadatabaseuri).
+
+Once you have fetched the raw hex encoded value, you will need to decode it into a human readable string.
+
+
+
+
+You can import the list of data keys related to each individual LSP standard from one of our library. There are 2 options:
+
+
+
+
+
+For dApp developers, you can import the data keys from the `@lukso/lsp-smart-contracts` and use them directly in your scripts via _ethers.js_ or _web3.js_.
+
+```javascript
+import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts';
+
+const nameKey = ERC725YDataKeys.LSP4.LSP4TokenName;
+const symbolKey = ERC725YDataKeys.LSP4.LSP4TokenSymbol;
+
+const nameValue = await token.getData(nameKey); // 0x4c5350382050726f66696c65
+const symbolValue = await token.getData(symbolKey); // 0x4c5350382050726f66696c65
+
+const name = ethers.toUtf8String(nameValue); // Cool NFT
+const symbol = ethers.toUtf8String(symbolValue); // COOL
+```
+
+
+
+
+
+You can also obtain the [full schema definition](../../tools/erc725js/schemas.md) of the LSP4 Metadata from [`@erc725/erc725.js`](../../tools/erc725js/getting-started.md) library. **This library will also help you to [encode easily](../../tools/erc725js/methods.md#encodedata) data key value pairs.**
+
+```javascript
+import { ERC725 } from '@erc725/erc725.js';
+import LSP4Schema from '@erc725/erc725.js/schemas/LSP4DigitalAssetMetadata.json';
+
+const nameKey = LSP4Schema.find((schema) => schema.name == 'LSP4TokenName').key;
+const symbolKey = LSP4Schema.find(
+ (schema) => schema.name == 'LSP4TokenSymbol',
+).key;
+
+const nameValue = await token.getData(nameKey); // 0x4c5350382050726f66696c65
+const symbolValue = await token.getData(symbolKey); // 0x4c5350382050726f66696c65
+
+const [name, symbol] = ERC725.decodeData([
+ {
+ keyName: 'LSP4TokenName',
+ value: nameValue,
+ },
+ {
+ keyName: 'LSP4TokenSymbol',
+ value: symbolValue,
+ },
+]);
+/**
+[
+ {
+ name: 'LSP4TokenName',
+ key: '0xdeba1e292f8ba88238e10ab3c7f88bd4be4fac56cad5194b6ecceaf653468af1',
+ value: "Cool NFT",
+ },
+ {
+ name: 'LSP4TokenSymbol',
+ key: '0x2f0a68ab07768e01943a599e73362a0e17a63a72e94dd2e384d2c1d4db932756',
+ value: "COOL",
+ },
+]
+*/
+```
+
+
+
+
+
+### Extended Collection Metadata
+
+:::success Tutorial 🎥
+
+See the [**Metadata Management**](../digital-assets/metadata-management/edit-token-metadata.md) guide + video for how to create and set the JSON metadata for your LSP8 Token.
:::
-LSP8 allows for more flexible and extensive metadata storage directly on-chain. You can store a JSON object containing information about the whole NFT contract and for each individual tokenId.
+[LSP8 allows for more flexible and extensible metadata](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md#lsp8-collection-vs-tokenid-metadata). You can store a JSON object containing information about:
+
+- the whole NFT Collection contract
+- and for each individual NFT `tokenId`.
-#### For the NFT contract
+The [`LSP4Metadata`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata) is a JSON object that can contain many information about the token, including:
-```js
+- 🌐 **official link to websites** (_e.g: project website, social medias, community channels, etc..._).
+- 🖼️ **images** (token icon and backgrounds) to display the token in dApps, explorers, or decentralised exchanges.
+- 🏷️ **custom attributes** (for each specific NFTs for instance, can be displayed as badges on UIs).
+
+```javascript
const metadataKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4Metadata'));
const storedMetadata = await token.getData(metadataKey);
const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata));
@@ -151,22 +319,37 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata));
{
LSP4Metadata: {
- description: 'A unique digital artwork.',
+ description: 'A unique digital artwork collection.',
links: [
- { title: 'Artist Website', url: 'https://artist.com' },
- { title: 'Gallery', url: 'https://gallery.com/artwork' }
+ { title: 'Website', url: 'https://myawesomenft.com' },
+ { title: 'Twitter', url: 'https://twitter.com/myawesomenft' }
],
- images: [
+ icon: [
{
- width: 1024,
- height: 1024,
- url: 'ipfs://QmW4wM4r9yWeY1gUCtt7c6v3ve7Fzdg8CKvTS96NU9Uiwr',
+ width: 256,
+ height: 256,
+ url: 'ipfs://QmW5cF4r9yWeY1gUCtt7c6v3ve7Fzdg8CKvTS96NU9Uiwr',
verification: {
method: 'keccak256(bytes)',
- data: '0xa9399df007997de92a820c6c2ec1cb2d3f5aa5fc1adf294157de563eba39bb6e',
+ data: '0x01299df007997de92a820c6c2ec1cb2d3f5aa5fc1adf294157de563eba39bb6f',
}
}
],
+ images: [
+ [
+ {
+ width: 1024,
+ height: 974,
+ url: 'ipfs://QmW4wM4r9yWeY1gUCtt7c6v3ve7Fzdg8CKvTS96NU9Uiwr',
+ verification: {
+ method: 'keccak256(bytes)',
+ data: '0xa9399df007997de92a820c6c2ec1cb2d3f5aa5fc1adf294157de563eba39bb6e',
+ }
+ },
+ // ... more image sizes
+ ],
+ // ... more images
+ ],
assets: [{
verification: {
method: 'keccak256(bytes)',
@@ -182,12 +365,12 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata));
type: "string"
},
{
- key: 'Year',
- value: 2023,
+ key: 'Edition',
+ value: 1,
type: "number"
},
{
- key: 'Unique',
+ key: 'Original',
value: true,
type: "boolean"
}
@@ -196,58 +379,41 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata));
}
```
-#### For each individual tokenId
+### NFT-specific Metadata
-```js
+LSP8 allows you to set and retrieve metadata for individual tokens using the [`setDataForTokenId(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#setdatafortokenid) and [`getDataForTokenId(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#getdatafortokenid) functions. This is particularly useful for NFTs where each token might have unique properties.
+```javascript
+// Setting token-specific metadata
+const tokenId = '0x1234...'; // your token ID in bytes32 format
const metadataKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4Metadata'));
-const storedMetadata = await token.getDataForTokenId(metadataKey);
+const metadataValue = ethers.toUtf8Bytes(JSON.stringify({
+ // Your token-specific metadata here
+}));
+
+await token.setDataForTokenId(tokenId, metadataKey, metadataValue);
+
+// Retrieving token-specific metadata
+const storedMetadata = await token.getDataForTokenId(tokenId, metadataKey);
const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata));
-// JSON Stored:
+// Example of token-specific metadata
{
LSP4Metadata: {
- description: 'A unique digital artwork.',
- links: [
- { title: 'Artist Website', url: 'https://artist.com' },
- { title: 'Gallery', url: 'https://gallery.com/artwork' }
- ],
- images: [
- {
- width: 1024,
- height: 1024,
- url: 'ipfs://QmW4wM4r9yWeY1gUCtt7c6v3ve7Fzdg8CKvTS96NU9Uiwr',
- verification: {
- method: 'keccak256(bytes)',
- data: '0xa9399df007997de92a820c6c2ec1cb2d3f5aa5fc1adf294157de563eba39bb6e',
- }
- }
- ],
- assets: [{
- verification: {
- method: 'keccak256(bytes)',
- data: '0x98fe032f81c43426fbcfb21c780c879667a08e2a65e8ae38027d4d61cdfe6f55',
- },
- url: 'ipfs://QmPJESHbVkPtSaHntNVY5F6JDLW8v69M2d6khXEYGUMn7N',
- fileType: 'json'
- }],
+ description: 'Unique NFT #1234',
+ image: 'ipfs://QmYourImageCID',
attributes: [
{
- key: 'Artist',
- value: 'Jane Doe',
- type: "string"
+ trait_type: 'Rarity',
+ value: 'Legendary'
},
{
- key: 'Year',
- value: 2023,
- type: "number"
- },
- {
- key: 'Unique',
- value: true,
- type: "boolean"
+ trait_type: 'Power Level',
+ value: 9000
}
]
}
}
```
+
+This feature allows for much more flexible and dynamic NFTs compared to the static `tokenURI` approach in ERC721.
diff --git a/docs/learn/universal-profile/universal-receiver/create-receiver-forwarder.md b/docs/learn/universal-profile/universal-receiver/create-receiver-forwarder.md
index 50757679c..7ef594e6c 100644
--- a/docs/learn/universal-profile/universal-receiver/create-receiver-forwarder.md
+++ b/docs/learn/universal-profile/universal-receiver/create-receiver-forwarder.md
@@ -1,5 +1,5 @@
---
-sidebar_label: 'Create a LSP1 Forwarder'
+sidebar_label: 'Create a Token Forwarder'
sidebar_position: 2
description: This smart contract tutorial guides you on how to create a LSP1 Delegate contract that forwards portion of received tokens automatically to any address.
---
@@ -7,7 +7,7 @@ description: This smart contract tutorial guides you on how to create a LSP1 Del
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
-# Create a LSP1 Forwarder
+# Create a Token Forwarder
This guide will teach you how to create a basic custom [Universal Receiver Delegate](../../../standards/generic-standards/lsp1-universal-receiver-delegate.md) contract for the following use-case:
diff --git a/src/components/Erc20LSP7Table/index.js b/src/components/Erc20LSP7Table/index.js
index f32d3828a..897b2aa5b 100644
--- a/src/components/Erc20LSP7Table/index.js
+++ b/src/components/Erc20LSP7Table/index.js
@@ -2,7 +2,7 @@ import React from 'react';
export default function Erc20LSP7Table() {
return (
-
+
ERC20 Function
@@ -12,78 +12,105 @@ export default function Erc20LSP7Table() {