From 3ca03ddbd00c8b9ab023744bea0b6e255f1e8b65 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 20 Aug 2024 11:14:07 +0100 Subject: [PATCH 01/10] improve page to migrate from ERC20 to LSP7 --- docs/learn/migrate/migrate-erc20-to-lsp7.md | 166 ++++++++++++++++--- docs/learn/migrate/migrate-erc721-to-lsp8.md | 8 +- src/css/custom.css | 32 ++++ static/img/learn/javascript-logo.png | Bin 0 -> 1842 bytes static/img/learn/solidity-logo.png | Bin 0 -> 1932 bytes 5 files changed, 182 insertions(+), 24 deletions(-) create mode 100644 static/img/learn/javascript-logo.png create mode 100644 static/img/learn/solidity-logo.png diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md index ba60a2227..38d0348ca 100644 --- a/docs/learn/migrate/migrate-erc20-to-lsp7.md +++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md @@ -4,10 +4,19 @@ 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 @@ -16,9 +25,11 @@ If you need more details about 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 [@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,51 @@ 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);` +ERC20: + +```solidity +function transferFrom( + address from, + address to, + uint256 amount +) external; +``` + +LSP7: + +```solidity +function transfer( + address from, + address to, + uint256 amount, + // highlight-next-line + bool force, + // highlight-next-line + bytes data +); +``` + +There are 3 main differences for LSP7 to note -LSP7: `function transfer(address from, address to, uint256 amount, bool force, bytes data);` +- **Additional `force` parameter**: for the [`mint(...)`](../../contracts/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md#mint) and [`transfer(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#ransfer) 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 (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 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.). +- **Additional `data` field**: for the `mint(...)`, `transfer(...)`, and [`burn(...)`](../../contracts/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md#burn) functions. -- **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. +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..._). -## Interacting with Contracts +> Check the [**LSP7 > LSP1 Token Hooks**](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) section in the LSP7DigitalAsset standard page for more details. + +- **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). + +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 +128,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,13 +140,13 @@ 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
)
|
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
)
| ## Metadata Management @@ -113,7 +160,9 @@ 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: +In LSP7, the token name and symbol can be retrieved with [getData](../../contracts/contracts/ERC725/ERC725.md#getdata) function. They are stored encoded 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 the raw hex encoded value fetched, you will need to decode it into a human readable string. See the code sample below. + +You can import the list of data keys related to each individual LSP standard from one of our library. There are 2 options: ```javascript // LSP7 @@ -127,15 +176,86 @@ const name = ethers.toUtf8String(nameValue); const symbol = ethers.toUtf8String(symbolValue); ``` + + + + +For dApp developers, you can import the data keys from the `@lukso/lsp-smart-contracts`: + +Or you can obtain the full schema with all the definitions from our [`@erc725/erc725.js`](../../tools/erc725js/getting-started.md) librarie. **This library will also help you to [encode easily](../../tools/erc725js/methods.md#encodedata) data key value pairs.** + +```javascript +// LSP7 +import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'; +const nameKey = ERC725YDataKeys.LSP4.LSP4TokenName; +const symbolKey = ERC725YDataKeys.LSP4.LSP4TokenSymbol; + +const nameValue = await token.getData(nameKey); +const symbolValue = await token.getData(symbolKey); + +const name = ethers.toUtf8String(nameValue); +const symbol = ethers.toUtf8String(symbolValue); +``` + +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" +// LSP7 +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 [name, symbol] = ERC725.decodeData([ + { + keyName: 'LSP4TokenName', + value: '0x555020417374726f20373235', // obtained via `await token.getData(nameKey)` + }, + { + keyName: 'LSP4TokenSymbol', + value: '0x5550373235', // obtained via `await token.getData(symbolKey)` + }, +]); +/** +[ + { + 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..a4d233b6d 100644 --- a/docs/learn/migrate/migrate-erc721-to-lsp8.md +++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md @@ -8,6 +8,12 @@ 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) in 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 @@ -16,7 +22,7 @@ If you need more details about the interface differences between ERC721 and LSP8 ::: -## Smart Contract Building +## Comparison of Solidity code Usually, to create an ERC721 token, `ERC721` is imported from [@openzeppelin/contracts](https://www.npmjs.com/package/@openzeppelin/contracts) package, and inherited. diff --git a/src/css/custom.css b/src/css/custom.css index 568975039..0806c299b 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -34,6 +34,13 @@ --ifm-alert-padding-horizontal: 1.2rem; --ifm-navbar-padding-vertical: calc(var(--ifm-spacing-vertical) * 0.2); --ifm-navbar-padding-horizontal: calc(var(--ifm-spacing-horizontal) * 0.5); + /* snippets */ + --docusaurus-highlighted-code-line-bg: rgba(161, 243, 153, 0.261); + /* If you have a different syntax highlighting theme for dark mode. */ + [data-theme='dark'] { + /* Color which works with dark mode syntax highlighting theme */ + --docusaurus-highlighted-code-line-bg: rgba(161, 243, 153, 0.261); + } } .markdown { @@ -260,6 +267,31 @@ table.lsp-features td { margin-right: 1em; } +.tab_javascript[aria-selected='true'] { + border-bottom-color: #f1dd30; +} +.tab_javascript { + color: #1e1e1e; +} +.tab_javascript:before { + content: url('/static/img/learn/javascript-logo.png'); + position: relative; /*or absolute*/ + z-index: 100000; /*a number that's more than the modal box*/ + margin-right: 1em; +} +.tab_solidity[aria-selected='true'] { + border-bottom-color: #4a4a4a; +} +.tab_solidity { + color: #1e1e1e; +} +.tab_solidity:before { + content: url('/static/img/learn/solidity-logo.png'); + position: relative; /*or absolute*/ + z-index: 100000; /*a number that's more than the modal box*/ + margin-right: 1em; +} + #guides-links li { list-style-type: '\1f517' !important; } diff --git a/static/img/learn/javascript-logo.png b/static/img/learn/javascript-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ff27bd2f821a4b31233efbde0838b3ef382744ac GIT binary patch literal 1842 zcmY*a4LH+l8-K=V<|AsnLdPsG*~NxRZH>bk`I?5w5;F3!!;Eb{5-&#`Mn0m>NtsB< zIX;@tw+}RxO5~#ty7azTbV6w@$|QBpf92?$=eh3x{d?~FcmM9^{$Ky=`sdKRc55OH zkN^NpH&==e`RbJ`VBZuglvdg33gvHDQFfqXtqgK%ajyG#0I0857z~^d z>O*S#Sab%TLG>htao9NKK~88mE}0#tr~;&9A_Uptd?q@X9TUqVCfj4aFo+OVgz*^k z7YaYx9>bv0(7QO?aI_uH8fT4hK%&uT68B&P(TC!)QVyN$F;RSe91)LCN=m{dZNYK4 zk$4*dfq=KR#oO9iK@2P2p;$gM*(#Q|>8r?JI+So;7?%~tXK`ZD3SDL>CxLH|!6+K7 zuCMpxvm(BAish}01r3N-WbigPYy7G%LaHz9F-@%6Th53)zN*@wl(fn_h z`8w&BC^V`Al7wGPd%ZV0%E%A(S=#T=(i>5C)or^;n~q0) zkIVfbvxZRJb2`I%#x&WfT6T}1T3fA_qMf^U*<6=Cl)uKa@YJvw z>f5&e>kDs+dm*YJeV{nFXOpXsRoPU>!=8^9r`4Kv~az8 z|HiWu7NVk`Lxo-nwPJ^}y+aGfVy?pyt zL)jm5ukRjCtQ<(vG+w|X07v>BS)055ku}@W^0BQz-M!17S9@pN)c8m$*8>;U$pl7@ zem_3*-uS@6Hx`ALpW9l$4q>o`@>{l&`Sd3mIlE^6W{bVvop%eLV7^;=4H9%vK%6yt zzHipTx+il>uzO;>e@LbD4X?K#UE7{>Whd%po$f<6O{Wo6a;8ltS%9Z}oO&j=2uW`@ z9LP9Q`a=I=Irl$=Rz#Jcc!3icFDI@Icat2GS2B2!;6h476K@cum8R|7@jvyEygR?P zhX9;*m#v=OXy6E$J4SvZ$UkM+@wmB(;?vBIhIa;;)c^MGM@DhxvN7s;cB1sqmI1Q( zVnr*ZdkL#@dvJR3?L!Uzjm+}t3CTSCc%8|$gX%-#M}XlSm{q?})8M@LyD;Z&iQ|I- zwT}0n5nl4DqO&bDlw z5&7QC9`a=tV9

q05@vE*l+4)7#bI+5IL>Puk!Yzu>Q2YHWBbM|wJ)-kq)_7Bsv{ zBNngaMQcwXE#`)^F^h|i|1M}d#Z>m|;j2bP$wEd;-SR$#)6A>!VFA4VV2%qtCLgXtDO`e`7SxCk7$j7T$_q{CFtPKqQ+wp7pbhv8Pm6 zEO7p8b3LQbZfi`c{07R_v})ow_K2vm`cTkquT zjUMg}eYP+=R=GhUA<>rBv?R+V@UECqSz=w*1>-_AfmJzq$HjrXyz>Sh7ytZj2hDfWP*QizFPgq)39aUvA0*D2 zy%xSm5$Q$GOYAibY2x-7kJhG3S-ZF8dFh+FV5#@XD)%yw22W;hgzb0CruFHI*N;|- zRmA={r_ZXA`{#IWVOk06E|79QT2J+j!%2CUuz`~=ndx=}fj~*s5fezymIiD_35z1z y`U;EtkG8=4kxxJ~KzIap@VSw2bo!lYwl-pTN!8i_%CA$@~*kujNGm literal 0 HcmV?d00001 diff --git a/static/img/learn/solidity-logo.png b/static/img/learn/solidity-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2f89d52da74a3a8fab74931539465ce25ef5308c GIT binary patch literal 1932 zcmY*acU)6h7JeZxKnPWks`Ct@fRF@HN(fm35h)@qS;HVDLK2EVARz<<1wx6t&LFrH zF(O6jUED<+hvpyy3&@WF1{5VDFotTSDY!4nGQ0Qv&O6^d@B6-U&;93J_Bee~5ut+s z06@{%iR1-k5DFu?Z=g3h_6QzI(oCWo5dfO96h6^ppgkDm1S9Ai8pw+{AIZk?Y*AkrI0#G1 z7!>%0!U?xUQQbU1ho~4jXo1F}u_yup1VMaEFazgBa@>(aJ6lu;hr_~QFmZ8l=s0t9 zR16biW^HYa!5+mNJ!%RuOxf{~92(CwlCA&M7Iy)#Pl*I{+iUcLTv~y9h99tAh z(r9;mJtrrW@n@$<_Rd()fEdXaj2Rk>+4Y8`cu5uK9urE3I!pWsX8146|Eulv!DA%N z|K~7YC;d`|MkOHdnB8k5Ahi8OvH&2X=u9G#sq(X9HUdA2de56jalh-Eg*`bKVswsH zA}A%=yJ(oGFPTVZgD4cN)5TRmRbG&eq8e5HR!NjA>{~ZPI&#z>^&GUnl2x$2`f+L^ zeC`>0=pkFyRr3>bf&k^7rIJblh%*O@xp8dd*@7|3)pXYt!9bZ zgNUT;<6GWDmQD9_iy^GZJ85w9Lf0zm7Synj~p_Qx?{zJ+`Qn zpY{R{pC)SzMzJlV`{Tu|gDQ1x7H9VeYpNM-h7K_7;B>60-XmWy+?Q+?;Sm;&uGp)} zq${(Z?G`A>|748)JBCU*>lzMRk&UEkIak*IQsWYivmCZh*8 zX%|>kS}N96{ITlCQH*ULs-|$sMJzv;3I_gBn|1y==Z?As^Ua+`gUaL&YRp8T*39}c zw!y@@9v-ySTl(rf#W?`kTsmTqRn`~UxnEgzc4Zzpa9C*L)PzX|8`9kEAHEwCELvtf z6m8kn8eJ;+@pwbiWPTl88_@xyfJfEiFWYXt&yKG*ttO50EJv0n$_WIdjGcqy>S|^j z|4Lo-%+@7aJ%n&vW`HA(@hjZew7bMmnd;Y=GE)WM0hu6Pv@w$mlDW>XI#zw z@^Yn$eSRPe3fZW}oHl{)-Pgg56*$5$TL0URPpSWW+iFN@ODHmpf2G5#6`y7_C^=E1{=S83YYC$Iu(%E zu^w-gsMX?hwQTGIyi&29lO>&k#geN`vW%l$d)Ry~Qf%GclubLk2^0J+d!@UA7?9hz zStxcQr;AKGiyBJ7mU83roZApo9OZwwn?-X^l~aa`zW*N4ap5BV$6*WcHdDKgyT9y6k*{aT%k<@1 n*QcKQ+$cefD@i|pUVGO*I%BgYb6~<(@{e&oahg Date: Tue, 20 Aug 2024 11:14:23 +0100 Subject: [PATCH 02/10] add Youtube to guide to set LSP7 Token Metadata --- .../metadata-management/edit-token-metadata.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 From 3da6463fbe590012e2225992edcd5ab33ad4ef93 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 20 Aug 2024 12:43:08 +0100 Subject: [PATCH 03/10] add new section for quickstart guides Co-authored-by: mvstvfv --- docs/learn/getting-started.mdx | 54 +++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/docs/learn/getting-started.mdx b/docs/learn/getting-started.mdx index e05c00931..314bc800d 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: 'Migrate ERC20 a token to LSP7', + linkPath: '../learn/migrate/migrate-erc20-to-lsp7', }, ], }, { image: SmartContractDevIcon, - imageTitle: 'Smart Contract Developer Icon', - cardHeading: 'Smart Contract Developer', + imageTitle: 'Quickstart Integration', + cardHeading: 'Migrate to LUKSO', cardContent: [ { - linkText: 'Get started with Tokens and NFTs', - linkPath: '../learn/digital-assets/getting-started', - }, - { - linkText: 'Create a token', - linkPath: '../learn/digital-assets/token/create-lsp7-token', + linkText: 'Migrate to LUKSO', + linkPath: '../learn/migrate/migrate-to-lukso', }, { linkText: 'Migrate ERC20 a token to LSP7', linkPath: '../learn/migrate/migrate-erc20-to-lsp7', }, + { + linkText: 'Migrate ERC721 an 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 From fc50754ee1f3ca24f7841daaddddfbfa9dea4ed5 Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 20 Aug 2024 12:43:20 +0100 Subject: [PATCH 04/10] make two column layouts --- docs/learn/migrate/migrate-erc20-to-lsp7.md | 66 +++-- src/components/Erc20LSP7Table/index.js | 281 +++++++++++++++----- src/css/custom.css | 5 + 3 files changed, 262 insertions(+), 90 deletions(-) diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md index 38d0348ca..9881ba9e3 100644 --- a/docs/learn/migrate/migrate-erc20-to-lsp7.md +++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md @@ -80,7 +80,11 @@ contract MyLSP7Token is LSP7DigitalAsset { Below are the function signatures of the transfer functions for ERC20 and LSP7, respectively. -ERC20: +
+ +
+ +**ERC20** ```solidity function transferFrom( @@ -90,7 +94,11 @@ function transferFrom( ) external; ``` -LSP7: +
+ +
+ +**LSP7** ```solidity function transfer( @@ -101,9 +109,13 @@ function transfer( bool force, // highlight-next-line bytes data -); +) external; ``` +
+ +
+ 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. @@ -162,8 +174,6 @@ const symbol = await token.symbol(); In LSP7, the token name and symbol can be retrieved with [getData](../../contracts/contracts/ERC725/ERC725.md#getdata) function. They are stored encoded 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 the raw hex encoded value fetched, you will need to decode it into a human readable string. See the code sample below. -You can import the list of data keys related to each individual LSP standard from one of our library. There are 2 options: - ```javascript // LSP7 const nameKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4TokenName')); @@ -176,47 +186,55 @@ const name = ethers.toUtf8String(nameValue); const symbol = ethers.toUtf8String(symbolValue); ``` - +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`: + -Or you can obtain the full schema with all the definitions from our [`@erc725/erc725.js`](../../tools/erc725js/getting-started.md) librarie. **This library will also help you to [encode easily](../../tools/erc725js/methods.md#encodedata) data key value pairs.** +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 -// LSP7 import { ERC725YDataKeys } from '@lukso/lsp-smart-contracts'; + const nameKey = ERC725YDataKeys.LSP4.LSP4TokenName; const symbolKey = ERC725YDataKeys.LSP4.LSP4TokenSymbol; -const nameValue = await token.getData(nameKey); -const symbolValue = await token.getData(symbolKey); +const nameValue = await token.getData(nameKey); // 0x555020417374726f20373235 +const symbolValue = await token.getData(symbolKey); // 0x5550373235 -const name = ethers.toUtf8String(nameValue); -const symbol = ethers.toUtf8String(symbolValue); +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) librarie. **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" -// LSP7 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 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: '0x555020417374726f20373235', // obtained via `await token.getData(nameKey)` + value: nameValue, }, { keyName: 'LSP4TokenSymbol', - value: '0x5550373235', // obtained via `await token.getData(symbolKey)` + value: symbolValue, }, ]); /** @@ -235,9 +253,7 @@ const [name, symbol] = ERC725.decodeData([ */ ``` - - - + @@ -325,3 +341,7 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata)); } } ``` + +``` + +``` diff --git a/src/components/Erc20LSP7Table/index.js b/src/components/Erc20LSP7Table/index.js index f32d3828a..6ee7719c7 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 ( - +
@@ -10,80 +10,110 @@ export default function Erc20LSP7Table() { - + - + - + - + - + @@ -91,25 +121,47 @@ export default function Erc20LSP7Table() { No equivalent - + @@ -117,57 +169,152 @@ export default function Erc20LSP7Table() { No equivalent - + - + - + + + + + diff --git a/src/css/custom.css b/src/css/custom.css index 0806c299b..46205639e 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -317,3 +317,8 @@ div.cardwithimage { #token-nft-combinations td { text-align: center; } + +table#erc20-to-lsp7-table pre { + margin-bottom: 1rem; + margin-top: 1rem; +} From 88c72cdc273bfa08e5a639407463722671f9ce5d Mon Sep 17 00:00:00 2001 From: CJ42 Date: Tue, 20 Aug 2024 13:12:36 +0100 Subject: [PATCH 05/10] final adjustments for the section --- docs/learn/migrate/migrate-erc20-to-lsp7.md | 60 +++++++++++++++------ 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md index 9881ba9e3..c3f500dd7 100644 --- a/docs/learn/migrate/migrate-erc20-to-lsp7.md +++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md @@ -19,9 +19,9 @@ import Erc20LSP7Table from '@site/src/components/Erc20LSP7Table'; [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. ::: @@ -44,7 +44,7 @@ contract MyERC20Token is ERC20 { } ``` -To create an LSP7 token, we should instead import `LSP7DigitalAsset` from [@lukso/lsp7-contracts](https://www.npmjs.com/package/@lukso/lsp7-contracts) package, and replace it in the inheritance. +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_). @@ -120,13 +120,15 @@ 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 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 (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. - **Additional `data` field**: for the `mint(...)`, `transfer(...)`, and [`burn(...)`](../../contracts/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.md#burn) functions. 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..._). -> Check the [**LSP7 > LSP1 Token Hooks**](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) section in the LSP7DigitalAsset standard page for more details. +> See the [**LSP7 Standard > LSP1 Token Hooks**](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) section for more details. - **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). @@ -164,20 +166,39 @@ Services like dApps and Indexers can use different events from LSP7 to listen to ### 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. They are stored encoded 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 the raw hex encoded value fetched, you will need to decode it into a human readable string. See the code sample below. +
+ +
+ +**How to retrieve?** + +In ERC20, the name and symbol of a token can be retrieved by calling their own function. + +
+
+ +
+ +
+ +**LSP7** ```javascript -// LSP7 -const nameKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4TokenName')); -const symbolKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4TokenSymbol')); +import { keccak256, toUtf8Bytes } from 'ethers'; + +const nameKey = keccak256(toUtf8Bytes('LSP4TokenName')); +const symbolKey = keccak256(toUtf8Bytes('LSP4TokenSymbol')); const nameValue = await token.getData(nameKey); const symbolValue = await token.getData(symbolKey); @@ -186,6 +207,19 @@ const name = ethers.toUtf8String(nameValue); const symbol = ethers.toUtf8String(symbolValue); ``` +
+ +
+ +**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: @@ -341,7 +375,3 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata)); } } ``` - -``` - -``` From a33752a1cd64c0090e99093bf365b7df5f1ef27e Mon Sep 17 00:00:00 2001 From: mustafademiray Date: Tue, 20 Aug 2024 15:43:09 +0300 Subject: [PATCH 06/10] added abi links --- src/components/Erc20LSP7Table/index.js | 38 +++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/components/Erc20LSP7Table/index.js b/src/components/Erc20LSP7Table/index.js index 6ee7719c7..2e944f478 100644 --- a/src/components/Erc20LSP7Table/index.js +++ b/src/components/Erc20LSP7Table/index.js @@ -103,7 +103,9 @@ export default function Erc20LSP7Table() {
  • - 🔍 Function details + + 🔍 Function details +
    • - 🔍 Function details + + 🔍 Function details +
    • 🔀 Example Transaction @@ -156,7 +160,9 @@ export default function Erc20LSP7Table() {
      • - 🔍 Function details + + 🔍 Function details +
      • 🔀 Example Transaction @@ -181,7 +187,9 @@ export default function Erc20LSP7Table() {
        • - 🔍 Function details + + 🔍 Function details +
        • 🔀 Example Transaction @@ -214,7 +222,9 @@ export default function Erc20LSP7Table() {

          • - 🔍 Function details + + 🔍 Function details +
          • 🔀 Example Transaction @@ -257,7 +267,9 @@ export default function Erc20LSP7Table() {

            • - 🔍 Function details + + 🔍 Function details +
            • 🔀 Example Transaction @@ -291,7 +303,9 @@ export default function Erc20LSP7Table() {

              • - 🔍 Function details + + 🔍 Function details +
              • 🔀 Example Transaction @@ -314,6 +328,16 @@ export default function Erc20LSP7Table() {
              • Update the token contract metadata.
              • etc...
              • +

                From 452725245047ccfdacd4f16fbbaeec6f70079981 Mon Sep 17 00:00:00 2001 From: mustafademiray Date: Tue, 20 Aug 2024 15:47:45 +0300 Subject: [PATCH 07/10] quickstart title --- docs/learn/getting-started.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/learn/getting-started.mdx b/docs/learn/getting-started.mdx index 314bc800d..87f8aacb5 100644 --- a/docs/learn/getting-started.mdx +++ b/docs/learn/getting-started.mdx @@ -50,7 +50,7 @@ export const CardData = [ { image: SmartContractDevIcon, imageTitle: 'Quickstart Integration', - cardHeading: 'Migrate to LUKSO', + cardHeading: 'Quickstart Integration', cardContent: [ { linkText: 'Migrate to LUKSO', From 0d61015530ac1f4c4468660adc475b32369ddc79 Mon Sep 17 00:00:00 2001 From: mustafademiray Date: Tue, 20 Aug 2024 18:37:33 +0300 Subject: [PATCH 08/10] improve migrate pages --- docs/learn/migrate/migrate-erc20-to-lsp7.md | 2 +- docs/learn/migrate/migrate-erc721-to-lsp8.md | 337 ++++++++++++++----- src/components/Erc20LSP7Table/index.js | 116 ++----- src/components/Erc721LSP8Table/index.js | 200 +++++++---- 4 files changed, 417 insertions(+), 238 deletions(-) diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md index c3f500dd7..85e1b38b0 100644 --- a/docs/learn/migrate/migrate-erc20-to-lsp7.md +++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md @@ -245,7 +245,7 @@ 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) librarie. **This library will also help you to [encode easily](../../tools/erc725js/methods.md#encodedata) data key value pairs.** +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. diff --git a/docs/learn/migrate/migrate-erc721-to-lsp8.md b/docs/learn/migrate/migrate-erc721-to-lsp8.md index a4d233b6d..466a53dca 100644 --- a/docs/learn/migrate/migrate-erc721-to-lsp8.md +++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md @@ -1,14 +1,17 @@ --- -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) in March 2024. +> 👇🏻 Hands on 📽️ Solidity Workshop Video for the [**Oxford Blockchain Society**](https://x.com/oxfordblocksoc) from March 2024.
                @@ -16,15 +19,17 @@ import Erc721LSP8Table from '@site/src/components/Erc721LSP8Table'; [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. ::: -## Comparison of Solidity code +## Comparisons -Usually, to create an ERC721 token, `ERC721` is imported from [@openzeppelin/contracts](https://www.npmjs.com/package/@openzeppelin/contracts) package, and inherited. +### Solidity code + +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 @@ -39,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 + // highlight-next-line uint256 lsp4TokenType_, // 1 if representing an NFT, 2 if representing 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);` +
                + +
                + +**ERC721** + +```solidity +function transferFrom( + address from, + address to, + uint256 tokenId +) external; +``` + +
                + +
                + +**LSP8** + +```solidity +function transfer( + address from, + address to, + bytes32 tokenId, + // highlight-next-line + bool force, + // highlight-next-line + bytes data +) external; +``` + +
                + +
                + +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 @@ -88,11 +142,11 @@ 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 @@ -100,34 +154,53 @@ 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 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 | +| ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|
                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
                )
                | ## 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. + +
                +
                + +
                + +
                + +**LSP8** ```javascript -// LSP8 -const nameKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4TokenName')); -const symbolKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4TokenSymbol')); +import { keccak256, toUtf8Bytes } from 'ethers'; + +const nameKey = keccak256(toUtf8Bytes('LSP4TokenName')); +const symbolKey = keccak256(toUtf8Bytes('LSP4TokenSymbol')); const nameValue = await token.getData(nameKey); const symbolValue = await token.getData(symbolKey); @@ -136,19 +209,103 @@ const name = ethers.toUtf8String(nameValue); const symbol = ethers.toUtf8String(symbolValue); ``` +
                + +
                + +**How to retrieve?** + +In LSP8, 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); // 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 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 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. You can store a JSON object containing information about the whole NFT contract and for each individual tokenId. The [`LSP4Metadata`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata) is a JSON object that can contain many information about the token, including: -#### For the NFT contract +- 🌐 **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). -```js +```javascript const metadataKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4Metadata')); const storedMetadata = await token.getData(metadataKey); const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata)); @@ -157,22 +314,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)', @@ -188,12 +360,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" } @@ -202,58 +374,41 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata)); } ``` -#### For each individual tokenId +### Token-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" - }, - { - key: 'Year', - value: 2023, - type: "number" + trait_type: 'Rarity', + value: 'Legendary' }, { - 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/src/components/Erc20LSP7Table/index.js b/src/components/Erc20LSP7Table/index.js index 2e944f478..90fa3cdae 100644 --- a/src/components/Erc20LSP7Table/index.js +++ b/src/components/Erc20LSP7Table/index.js @@ -101,21 +101,16 @@ export default function Erc20LSP7Table() {
                ); - + + 🔍 Function details + {' '} +
                + + 🔀 Example Transaction +
@@ -131,16 +126,9 @@ export default function Erc20LSP7Table() { {' '}bytes memory data
) - + + 🔍 Function details + @@ -158,16 +146,9 @@ export default function Erc20LSP7Table() { {' '}bytes memory data
) - + + 🔍 Function details + @@ -185,16 +166,9 @@ export default function Erc20LSP7Table() { {' '}bytes memory data
) - + + 🔍 Function details + @@ -220,16 +194,9 @@ export default function Erc20LSP7Table() { Pass the msg.sender address as from{' '} parameter.

- + + 🔍 Function details + @@ -265,16 +232,9 @@ export default function Erc20LSP7Table() { Use msg.sender as an operator and use a different{' '} from address to transfer tokens from.

- + + 🔍 Function details + @@ -301,16 +261,9 @@ export default function Erc20LSP7Table() {

- + + 🔍 Function details + @@ -328,16 +281,9 @@ export default function Erc20LSP7Table() {
  • Update the token contract metadata.
  • etc...
  • - + + 🔍 Function details +

    diff --git a/src/components/Erc721LSP8Table/index.js b/src/components/Erc721LSP8Table/index.js index f87f5b19b..d1ce92ecf 100644 --- a/src/components/Erc721LSP8Table/index.js +++ b/src/components/Erc721LSP8Table/index.js @@ -2,7 +2,7 @@ import React from 'react'; export default function Erc721LSP8Table() { return ( -
    ERC20 Function
    - name() +
    name()
    - getData(bytes32 dataKey) with
    {' '} - dataKey = keccak256('LSP4TokenName') +
    +              const dataKey = keccak256('LSP4TokenName')
    +              
    + getData(bytes32 dataKey) +
    - symbol() +
    symbol()
    - getData(bytes32 dataKey) with
    {' '} - dataKey = keccak256('LSP4TokenSymbol') +
    +              const dataKey = keccak256('LSP4TokenSymbol')
    +              
    + getData(bytes32 dataKey) +
    - decimals() +
    decimals()
    - decimals() +
    decimals()
    - totalSupply() +
    totalSupply()
    - totalSupply() +
    totalSupply()
    - balanceOf(address account) +
    balanceOf(address account)
    - balanceOf(address account) +
    balanceOf(address account)
    - approve(address spender, uint256 amount) +
    +              allowance(address owner, address spender)
    +            
    - - authorizeOperator(address spender, +
    +              authorizedAmountFor(
                   
    - uint256 amount, + {' '} address spender,
    - bytes memory data) -
    + {' '} address owner +
    ) +
    - allowance(address owner, address spender) + No equivalent - - authorizedAmountFor(address spender, -
    - address owner) -
    +
    getOperatorsOf(address owner)
    - No equivalent +
    +              approve(address spender, uint256 amount)
    +            
    - getOperatorsOf(address owner) +
    +              authorizeOperator(
    +              
    + {' '}address spender, +
    + {' '}uint256 amount, +
    + {' '}bytes memory data +
    + ); +
    +
    - - revokeOperator(address spender, +
    +              revokeOperator(
    +              
    + {' '}address spender,
    - bytes memory data) -
    + {' '}bytes memory data +
    ) +
    +
    No equivalent - - increaseAllowance(address spender, +
    +              increaseAllowance(
    +              
    + {' '}address spender,
    - uint256 addedAmount, + {' '}uint256 addedAmount,
    - bytes memory data) -
    + {' '}bytes memory data +
    ) +
    +
    - - decreaseAllowance(address spender, +
    +              decreaseAllowance(
                   
    - uint256 subtractedAmount, + {' '}address spender,
    - bytes memory data) -
    + {' '}uint256 subtractedAmount, +
    + {' '}bytes memory data +
    ) +
    +
    - transfer(address to, uint256 amount) +
    transfer(address to, uint256 amount)
    - - transfer(address from, +
    +              transfer(
    +              
    + {' '}address from,
    - address to, + {' '}address to,
    - uint256 amount, + {' '}uint256 amount,
    - bool force + {' '}bool force
    - bytes memory data) -
    + {' '}bytes memory data +
    ) +
    +

    + Pass the msg.sender address as from{' '} + parameter. +

    +
    - transferFrom(address from, address to, uint256 amount) +
    +              transferFrom(
    +              
    + {' '}address from, +
    + {' '} address to, +
    + {' '} uint256 amount +
    + {' '}) +
    - - transfer(address from, +
    +              transfer(
    +              
    + {' '}address from,
    - address to, + {' '}address to,
    - uint256 amount, + {' '}uint256 amount,
    - bool force + {' '}bool force
    - bytes memory data) -
    + {' '}bytes memory data +
    ) +
    +

    + Use msg.sender as an operator and use a different{' '} + from address to transfer tokens from. +

    +
    + No equivalent + +
    +              function transferBatch(
    +              
    {' '} address[] from, +
    {' '} address[] to, +
    {' '} uint256[] amount, +
    {' '} bool[] force, +
    {' '} bytes[] data +
    + ); +
    +

    + Transfer the same token to multiple recipients in a single + transaction.{' '} + + + See our examples code snippets. + + +

    + +
    No equivalent - batchCalls(bytes[] memory data) +
    batchCalls(bytes[] memory data)
    +

    + Allows to pass multiple calls into a single transaction. For + instance: +

      +
    1. Transfer tokens to an address.
    2. +
    3. Authorize an operator.
    4. +
    5. Update the token contract metadata.
    6. +
    7. etc...
    8. +
    +

    +
    @@ -10,65 +10,82 @@ export default function Erc721LSP8Table() { - + - + - + - + - + - + - + - + - + - + - + From e8a43f3c384a4c5d8a73968e047c8ff4fba53e71 Mon Sep 17 00:00:00 2001 From: mustafademiray Date: Tue, 20 Aug 2024 18:44:46 +0300 Subject: [PATCH 09/10] fix one line --- docs/learn/migrate/migrate-erc721-to-lsp8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/learn/migrate/migrate-erc721-to-lsp8.md b/docs/learn/migrate/migrate-erc721-to-lsp8.md index 466a53dca..72063f2e8 100644 --- a/docs/learn/migrate/migrate-erc721-to-lsp8.md +++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md @@ -64,7 +64,7 @@ contract MyLSP8Token is LSP8IdentifiableDigitalAsset { string memory symbol, // Symbol of the token address tokenOwner, // Owner able to add extensions and change metadata // highlight-next-line - uint256 lsp4TokenType_, // 1 if representing an NFT, 2 if representing an advanced collection of multiple NFTs + 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_) { From cd286e0d1a87b2514e53345b041fc5dc72e85412 Mon Sep 17 00:00:00 2001 From: mustafademiray Date: Wed, 21 Aug 2024 00:54:43 +0300 Subject: [PATCH 10/10] address comments --- docs/learn/getting-started.mdx | 8 ++--- docs/learn/migrate/migrate-erc721-to-lsp8.md | 25 +++++++++------- .../create-receiver-forwarder.md | 4 +-- src/components/Erc20LSP7Table/index.js | 22 +++++++------- src/components/Erc721LSP8Table/index.js | 28 ++++++++++-------- src/css/custom.css | 25 ++++++++-------- static/img/learn/solidity-logo.png | Bin 1932 -> 0 bytes 7 files changed, 60 insertions(+), 52 deletions(-) delete mode 100644 static/img/learn/solidity-logo.png diff --git a/docs/learn/getting-started.mdx b/docs/learn/getting-started.mdx index 87f8aacb5..e21b87281 100644 --- a/docs/learn/getting-started.mdx +++ b/docs/learn/getting-started.mdx @@ -42,8 +42,8 @@ export const CardData = [ linkPath: '../learn/digital-assets/token/create-lsp7-token', }, { - linkText: 'Migrate ERC20 a token to LSP7', - linkPath: '../learn/migrate/migrate-erc20-to-lsp7', + linkText: 'Create an Automatic Token Forwarder for your UP', + linkPath: '../learn/universal-profile/universal-receiver/create-receiver-forwarder', }, ], }, @@ -57,11 +57,11 @@ export const CardData = [ linkPath: '../learn/migrate/migrate-to-lukso', }, { - linkText: 'Migrate ERC20 a token to LSP7', + linkText: 'Refactor a Solidity ERC20 token to LSP7', linkPath: '../learn/migrate/migrate-erc20-to-lsp7', }, { - linkText: 'Migrate ERC721 an NFT to LSP8', + linkText: 'Refactor a Solidity ERC721 NFT to LSP8', linkPath: '../learn/migrate/migrate-erc721-to-lsp8', }, ], diff --git a/docs/learn/migrate/migrate-erc721-to-lsp8.md b/docs/learn/migrate/migrate-erc721-to-lsp8.md index 72063f2e8..1fff31f5f 100644 --- a/docs/learn/migrate/migrate-erc721-to-lsp8.md +++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md @@ -150,7 +150,7 @@ To interact with the LSP8IdentifiableDigitalAsset contract, different functions :::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. ::: @@ -169,7 +169,7 @@ Services like dApps and Indexers can use different events from LSP8 to listen to
    -
    +
    **ERC721** @@ -181,7 +181,7 @@ const tokenURI = await token.tokenURI(tokenId);
    -
    +
    **How to retrieve?** @@ -192,7 +192,7 @@ In ERC721, the name, symbol, and tokenURI of a token can be retrieved by calling
    -
    +
    **LSP8** @@ -211,11 +211,11 @@ const symbol = ethers.toUtf8String(symbolValue);
    -
    +
    **How to retrieve?** -In LSP8, 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). +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. @@ -291,7 +291,7 @@ const [name, symbol] = ERC725.decodeData([ -### Extended Token Metadata +### Extended Collection Metadata :::success Tutorial 🎥 @@ -299,11 +299,16 @@ See the [**Metadata Management**](../digital-assets/metadata-management/edit-tok ::: -LSP8 allows for more flexible and extensible metadata. You can store a JSON object containing information about the whole NFT contract and for each individual tokenId. The [`LSP4Metadata`](../../standards/tokens/LSP4-Digital-Asset-Metadata.md#lsp4metadata) is a JSON object that can contain many information about the token, including: +[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`. + +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). +- 🏷️ **custom attributes** (for each specific NFTs for instance, can be displayed as badges on UIs). ```javascript const metadataKey = ethers.keccak256(ethers.toUtf8Bytes('LSP4Metadata')); @@ -374,7 +379,7 @@ const retrievedJsonMetadata = JSON.parse(ethers.toUtf8String(storedMetadata)); } ``` -### Token-specific Metadata +### NFT-specific Metadata 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. 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 90fa3cdae..897b2aa5b 100644 --- a/src/components/Erc20LSP7Table/index.js +++ b/src/components/Erc20LSP7Table/index.js @@ -10,7 +10,7 @@ export default function Erc20LSP7Table() {
    - + @@ -22,7 +22,7 @@ export default function Erc20LSP7Table() { - + @@ -58,7 +58,7 @@ export default function Erc20LSP7Table() {
    balanceOf(address account)
    - + - + @@ -83,7 +83,7 @@ export default function Erc20LSP7Table() {
    getOperatorsOf(address owner)
    - + - + @@ -171,7 +171,7 @@ export default function Erc20LSP7Table() { - + @@ -199,7 +199,7 @@ export default function Erc20LSP7Table() { - + - + @@ -266,7 +266,7 @@ export default function Erc20LSP7Table() { - + diff --git a/src/components/Erc721LSP8Table/index.js b/src/components/Erc721LSP8Table/index.js index d1ce92ecf..507f85c99 100644 --- a/src/components/Erc721LSP8Table/index.js +++ b/src/components/Erc721LSP8Table/index.js @@ -10,7 +10,7 @@ export default function Erc721LSP8Table() { - + @@ -22,7 +22,7 @@ export default function Erc721LSP8Table() { - + @@ -42,7 +42,7 @@ export default function Erc721LSP8Table() {
    balanceOf(address tokenOwner)
    - + @@ -50,7 +50,7 @@ export default function Erc721LSP8Table() {
    tokenOwnerOf(bytes32 tokenId)
    - + @@ -70,7 +70,7 @@ export default function Erc721LSP8Table() { - + @@ -81,7 +81,7 @@ export default function Erc721LSP8Table() { - + - + - + - + - + @@ -204,7 +204,7 @@ export default function Erc721LSP8Table() { - + @@ -215,8 +215,10 @@ export default function Erc721LSP8Table() { instance:
    1. Transfer an NFT to an address.
    2. -
    3. Authorize an operator for a specific token.
    4. -
    5. Update the token contract metadata.
    6. +
    7. + Authorize an operator for a specific tokenId. +
    8. +
    9. Update the NFT metadata.
    10. etc...

    diff --git a/src/css/custom.css b/src/css/custom.css index 46205639e..2f3c25df9 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -279,18 +279,6 @@ table.lsp-features td { z-index: 100000; /*a number that's more than the modal box*/ margin-right: 1em; } -.tab_solidity[aria-selected='true'] { - border-bottom-color: #4a4a4a; -} -.tab_solidity { - color: #1e1e1e; -} -.tab_solidity:before { - content: url('/static/img/learn/solidity-logo.png'); - position: relative; /*or absolute*/ - z-index: 100000; /*a number that's more than the modal box*/ - margin-right: 1em; -} #guides-links li { list-style-type: '\1f517' !important; @@ -322,3 +310,16 @@ table#erc20-to-lsp7-table pre { margin-bottom: 1rem; margin-top: 1rem; } + +table#erc20-to-lsp7-table tr { + background-color: transparent; +} + +table#erc721-to-lsp8-table pre { + margin-bottom: 1rem; + margin-top: 1rem; +} + +table#erc721-to-lsp8-table tr { + background-color: transparent; +} diff --git a/static/img/learn/solidity-logo.png b/static/img/learn/solidity-logo.png deleted file mode 100644 index 2f89d52da74a3a8fab74931539465ce25ef5308c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1932 zcmY*acU)6h7JeZxKnPWks`Ct@fRF@HN(fm35h)@qS;HVDLK2EVARz<<1wx6t&LFrH zF(O6jUED<+hvpyy3&@WF1{5VDFotTSDY!4nGQ0Qv&O6^d@B6-U&;93J_Bee~5ut+s z06@{%iR1-k5DFu?Z=g3h_6QzI(oCWo5dfO96h6^ppgkDm1S9Ai8pw+{AIZk?Y*AkrI0#G1 z7!>%0!U?xUQQbU1ho~4jXo1F}u_yup1VMaEFazgBa@>(aJ6lu;hr_~QFmZ8l=s0t9 zR16biW^HYa!5+mNJ!%RuOxf{~92(CwlCA&M7Iy)#Pl*I{+iUcLTv~y9h99tAh z(r9;mJtrrW@n@$<_Rd()fEdXaj2Rk>+4Y8`cu5uK9urE3I!pWsX8146|Eulv!DA%N z|K~7YC;d`|MkOHdnB8k5Ahi8OvH&2X=u9G#sq(X9HUdA2de56jalh-Eg*`bKVswsH zA}A%=yJ(oGFPTVZgD4cN)5TRmRbG&eq8e5HR!NjA>{~ZPI&#z>^&GUnl2x$2`f+L^ zeC`>0=pkFyRr3>bf&k^7rIJblh%*O@xp8dd*@7|3)pXYt!9bZ zgNUT;<6GWDmQD9_iy^GZJ85w9Lf0zm7Synj~p_Qx?{zJ+`Qn zpY{R{pC)SzMzJlV`{Tu|gDQ1x7H9VeYpNM-h7K_7;B>60-XmWy+?Q+?;Sm;&uGp)} zq${(Z?G`A>|748)JBCU*>lzMRk&UEkIak*IQsWYivmCZh*8 zX%|>kS}N96{ITlCQH*ULs-|$sMJzv;3I_gBn|1y==Z?As^Ua+`gUaL&YRp8T*39}c zw!y@@9v-ySTl(rf#W?`kTsmTqRn`~UxnEgzc4Zzpa9C*L)PzX|8`9kEAHEwCELvtf z6m8kn8eJ;+@pwbiWPTl88_@xyfJfEiFWYXt&yKG*ttO50EJv0n$_WIdjGcqy>S|^j z|4Lo-%+@7aJ%n&vW`HA(@hjZew7bMmnd;Y=GE)WM0hu6Pv@w$mlDW>XI#zw z@^Yn$eSRPe3fZW}oHl{)-Pgg56*$5$TL0URPpSWW+iFN@ODHmpf2G5#6`y7_C^=E1{=S83YYC$Iu(%E zu^w-gsMX?hwQTGIyi&29lO>&k#geN`vW%l$d)Ry~Qf%GclubLk2^0J+d!@UA7?9hz zStxcQr;AKGiyBJ7mU83roZApo9OZwwn?-X^l~aa`zW*N4ap5BV$6*WcHdDKgyT9y6k*{aT%k<@1 n*QcKQ+$cefD@i|pUVGO*I%BgYb6~<(@{e&oahg
    ERC721 Function
    - name() +
    name()
    - getData(bytes32 dataKey) with
    {' '} - dataKey = keccak256('LSP4TokenName') +
    +              const dataKey = keccak256('LSP4TokenName')
    +              
    + getData(bytes32 dataKey) +
    - symbol() +
    symbol()
    - getData(bytes32 dataKey) with
    {' '} - dataKey = keccak256('LSP4TokenSymbol') +
    +              const dataKey = keccak256('LSP4TokenSymbol')
    +              
    + getData(bytes32 dataKey) +
    - balanceOf(address owner) +
    balanceOf(address owner)
    - balanceOf(address tokenOwner) +
    balanceOf(address tokenOwner)
    - ownerOf(uint256 tokenId) +
    ownerOf(uint256 tokenId)
    - tokenOwnerOf(bytes32 tokenId) +
    tokenOwnerOf(bytes32 tokenId)
    - approve(address to, uint256 tokenId) +
    approve(address to, uint256 tokenId)
    - - authorizeOperator(address operator, +
    +              authorizeOperator(
                   
    - bytes32 tokenId, + {' '}address operator,
    - bytes memory data) -
    + {' '}bytes32 tokenId, +
    + {' '}bytes memory data +
    ) +
    + + 🔍 Function details +
    - getApproved(uint256 tokenId) +
    getApproved(uint256 tokenId)
    - getOperatorsOf(bytes32 tokenId) +
    getOperatorsOf(bytes32 tokenId)
    + + 🔍 Function details +
    - setApprovalForAll(address operator, bool approved) +
    +              setApprovalForAll(address operator, bool approved)
    +            
    @@ -76,78 +93,139 @@ export default function Erc721LSP8Table() {
    - isApprovedForAll(address owner, address operator) +
    +              isApprovedForAll(address owner, address operator)
    +            
    - - isOperatorFor(address operator, +
    +              isOperatorFor(
    +              
    + {' '}address operator,
    - bytes32 tokenId) -
    + {' '}bytes32 tokenId +
    ) +
    + + 🔍 Function details +
    - transferFrom(address from, address to, uint256 tokenId) +
    +              transferFrom(
    +              
    + {' '}address from, +
    + {' '}address to, +
    + {' '}uint256 tokenId +
    ) +
    - - transfer(address from, +
    +              transfer(
                   
    - address to, + {' '}address from,
    - bytes32 tokenId, + {' '}address to,
    - bool force, + {' '}bytes32 tokenId,
    - bytes memory data) -
    + {' '}bool force, +
    + {' '}bytes memory data +
    ) +
    + + 🔍 Function details +
    - - safeTransferFrom(address from, address to, uint256 tokenId) - +
    +              safeTransferFrom(
    +              
    + {' '}address from, +
    + {' '}address to, +
    + {' '}uint256 tokenId +
    ) +
    - - transfer(address from, +
    +              transfer(
    +              
    + {' '}address from,
    - address to, + {' '}address to,
    - bytes32 tokenId, + {' '}bytes32 tokenId,
    - bool force, + {' '}bool force,
    - bytes memory data) -
    + {' '}bytes memory data +
    ) +
    +

    + Set force = false for safe transfer behavior +

    + + 🔍 Function details +
    No equivalent - - revokeOperator(address operator, +
    +              revokeOperator(
    +              
    + {' '}address operator,
    - bytes32 tokenId, + {' '}bytes32 tokenId,
    - bool notify, + {' '}bool notify,
    - bytes memory data) -
    + {' '}bytes memory data +
    ) +
    + + 🔍 Function details +
    No equivalent - batchCalls(bytes[] memory data) +
    batchCalls(bytes[] memory data)
    +

    + Allows to pass multiple calls into a single transaction. For + instance: +

      +
    1. Transfer an NFT to an address.
    2. +
    3. Authorize an operator for a specific token.
    4. +
    5. Update the token contract metadata.
    6. +
    7. etc...
    8. +
    +

    + + 🔍 Function details + + {/*
  • + 🔀 Example Transaction +
  • */}
    name()
    symbol()
                   allowance(address owner, address spender)
    @@ -75,7 +75,7 @@ export default function Erc20LSP7Table() {
                 
    No equivalent
                   approve(address spender, uint256 amount)
    @@ -103,7 +103,7 @@ export default function Erc20LSP7Table() {
                 
    🔍 Function details - {' '} +
    No equivalent
    transfer(address to, uint256 amount)
                   transferFrom(
    @@ -237,7 +237,7 @@ export default function Erc20LSP7Table() {
                 
               
    No equivalent
    No equivalent
    name()
    symbol()
    ownerOf(uint256 tokenId)
    approve(address to, uint256 tokenId)
    getApproved(uint256 tokenId)
                   setApprovalForAll(address operator, bool approved)
    @@ -93,7 +93,7 @@ export default function Erc721LSP8Table() {
                 
               
                   isApprovedForAll(address owner, address operator)
    @@ -113,7 +113,7 @@ export default function Erc721LSP8Table() {
                 
               
                   transferFrom(
    @@ -146,7 +146,7 @@ export default function Erc721LSP8Table() {
                 
               
                   safeTransferFrom(
    @@ -182,7 +182,7 @@ export default function Erc721LSP8Table() {
                 
               
    No equivalent
    No equivalent