Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion docs/learn/digital-assets/choose-lsp7-vs-lsp8.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
---
title: 'Choose LSP7 or LSP8 for Tokens and NFTs'
sidebar_label: '❓ Choose between LSP7 or LSP8'
sidebar_position: 2
description: Discover which standard is best suited for your token or NFT project between LSP7 or LSP8.
description: Discover whether LSP7 or LSP8 is best for your token, NFT, collection, or ERC1155-style multi-asset project on LUKSO.
---

# Choose between LSP7 or LSP8
Expand Down Expand Up @@ -144,3 +145,24 @@ flowchart TD

- Each tokenId is a of `LSP8TokenIdFormat` of `Address`.
- Each sub-collection is a smart contract that can be either an LSP7 or LSP8

### Example Use Cases

- a creator collection grouping several NFT drops.
- a game collection grouping character, item, and badge contracts.
- a brand collection grouping several editions or product lines.

---

## ERC1155-style multi-asset projects

If you come from ERC1155, first decide whether your assets are mostly interchangeable quantities or unique identifiable items. LUKSO projects usually model these cases with LSP7 and LSP8 instead of one mixed contract interface.

| ERC1155-style need | LUKSO pattern |
| ------------------------------------------------------------ | --------------------------------------------- |
| Many identical editions of one item | LSP7 with `LSP4TokenType` set to `NFT` |
| A collection of unique items | LSP8 with `LSP4TokenType` set to `NFT` |
| A parent collection that points to several child collections | LSP8 with `LSP4TokenType` set to `Collection` |
| Fungible game points, rewards, or credits | LSP7 with `LSP4TokenType` set to `Token` |

This split makes indexing and metadata clearer: fungible balances, semi-fungible editions, unique NFTs, and umbrella collections each expose their own LSP4/ERC725Y metadata and LSP1-aware transfer behavior.
52 changes: 47 additions & 5 deletions docs/learn/migrate/migrate-erc20-to-lsp7.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
---
title: 'ERC20 vs LSP7: Migrate ERC20 Tokens to LUKSO'
sidebar_label: '🪙 ERC20 to LSP7'
sidebar_position: 2
description: Learn how to migrate your ERC20 token to the LSP7 Digital Asset standard on LUKSO.
description: Learn how to migrate ERC20 tokens to LSP7 on LUKSO, including token metadata, transfer hooks, operator permissions, and ERC20 approval differences.
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

import Erc20LSP7Table from '@site/src/components/Erc20LSP7Table';
import StructuredData from '@site/src/components/StructuredData';

<StructuredData
data={{
'@context': 'https://schema.org',
'@type': 'TechArticle',
headline: 'ERC20 vs LSP7: Migrate ERC20 Tokens to LUKSO',
description:
'Migration guide for ERC20 developers moving token logic to LSP7 Digital Assets on LUKSO, covering metadata, transfer hooks, operators, and approvals.',
author: { '@type': 'Organization', name: 'LUKSO' },
publisher: { '@type': 'Organization', name: 'LUKSO' },
mainEntityOfPage:
'https://docs.lukso.tech/learn/migrate/migrate-erc20-to-lsp7/',
isAccessibleForFree: true,
}}
/>

# 🪙 Migrate ERC20 to LSP7

Expand All @@ -21,10 +38,22 @@ import Erc20LSP7Table from '@site/src/components/Erc20LSP7Table';

:::info Resources

See the [contract overview](../../contracts/overview/Token/index.md#comparisons-with-erc20--erc721) page for the interface differences between ERC20 and LSP7.
See the [contract overview](../../contracts/overview/Token/index.md#comparisons-with-erc20) page for the interface differences between ERC20 and LSP7.

:::

## ERC20 vs LSP7 at a glance

LSP7 keeps the familiar EVM token model of balances and transfers, but it adds the LUKSO-specific surfaces that ERC20 does not standardize: extensible metadata through ERC725Y data keys, transfer data, optional receiver checks, and operator authorization.

| ERC20 concern | LSP7 migration point |
| ----------------------------------------------- | ------------------------------------------------------------------------------------ |
| `name()`, `symbol()`, and optional `decimals()` | Token information is stored as LSP4/ERC725Y data keys. |
| `transfer` and `transferFrom` | LSP7 `transfer(...)` includes `force` and `data` parameters. |
| Allowances and approvals | LSP7 uses operators for amount-based token authorization. |
| Receiver behavior | Transfers can require LSP1 support when `force` is `false`. |
| Indexing | Index LSP7 `Transfer`, `OperatorAuthorizationChanged`, and `OperatorRevoked` events. |

## Comparisons

### Solidity code
Expand Down Expand Up @@ -118,22 +147,35 @@ function transfer(

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.
- **Additional `force` parameter**: for the [`mint(...)`](../../contracts/contracts/LSP7DigitalAsset/presets/LSP7Mintable.md#mint) and [`transfer(...)`](../../contracts/contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#transfer) 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.
> See the [**LSP7 Standard > LSP1 Token Hooks**](../../standards/tokens/LSP7-Digital-Asset.md#lsp1-token-hooks) 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..._).

> 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/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).
- **LSP7 metadata is generic**: via a [flexible data key / value store](../../standards/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.

### ERC20 approvals vs LSP7 operators

ERC20 approvals store an allowance from an owner to a spender. This is simple, but it often leads to unlimited approvals, stale allowances, approval phishing, and approve-then-action user flows. LSP7 models token-level authorization with operators instead. An operator can be authorized for a specific amount and can receive LSP1-compatible notification data.

Operators are still amount-based token authorizations, so they should not be treated as full account permissions. If a dApp needs a controller to call selected contracts, edit selected metadata, or submit relay transactions from a Universal Profile, use [LSP6 Key Manager permissions](../../learn/universal-profile/key-manager/grant-permissions.md) together with allowed calls or allowed ERC725Y data keys.

| Use case | Recommended LUKSO primitive |
| ---------------------------------------------------------------- | ------------------------------------------------ |
| Let a marketplace move a bounded amount of one token | LSP7 operator authorization |
| Let an app call only selected contracts from a Universal Profile | LSP6 `CALL` with Allowed Calls |
| Let a session edit selected profile data | LSP6 `SETDATA` with Allowed ERC725Y Data Keys |
| Let a Transaction Relay Service submit signed actions | LSP25 relay execution with LSP6 relay permission |

### Interact with the Token Contract

:::info
Expand Down
51 changes: 47 additions & 4 deletions docs/learn/migrate/migrate-erc721-to-lsp8.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
---
title: 'ERC721 vs LSP8: Migrate NFT Collections to LUKSO'
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.
description: Learn how to migrate ERC721 NFT collections to LSP8 on LUKSO, including bytes32 token IDs, dynamic metadata, transfer hooks, and safe transfer behavior.
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

import Erc721LSP8Table from '@site/src/components/Erc721LSP8Table';
import StructuredData from '@site/src/components/StructuredData';

<StructuredData
data={{
'@context': 'https://schema.org',
'@type': 'TechArticle',
headline: 'ERC721 vs LSP8: Migrate NFT Collections to LUKSO',
description:
'Migration guide for ERC721 developers moving NFT collections to LSP8 Identifiable Digital Assets on LUKSO, covering token IDs, metadata, transfer hooks, and operators.',
author: { '@type': 'Organization', name: 'LUKSO' },
publisher: { '@type': 'Organization', name: 'LUKSO' },
mainEntityOfPage:
'https://docs.lukso.tech/learn/migrate/migrate-erc721-to-lsp8/',
isAccessibleForFree: true,
}}
/>

# 🖼️ Migrate ERC721 to LSP8

Expand All @@ -21,10 +38,22 @@ import Erc721LSP8Table from '@site/src/components/Erc721LSP8Table';

:::info Resources

See the [contract overview](../../contracts/overview/NFT/index.md#comparisons-with-erc20--erc721) page for the interface differences between ERC721 and LSP8.
See the [contract overview](../../contracts/overview/NFT/index.md#comparisons-with-erc721) page for the interface differences between ERC721 and LSP8.

:::

## ERC721 vs LSP8 at a glance

LSP8 covers NFT-style assets, but it does not copy ERC721 one-to-one. The main migration points are token ID format, metadata storage, transfer behavior, and operator authorization.

| ERC721 concern | LSP8 migration point |
| ------------------------------------- | ------------------------------------------------------------------------- |
| `uint256 tokenId` | LSP8 token IDs are `bytes32`, allowing numeric IDs and richer ID schemes. |
| `tokenURI(tokenId)` | Collection and token metadata can be stored with LSP4/ERC725Y data keys. |
| `transferFrom` and `safeTransferFrom` | LSP8 `transfer(...)` includes `force` and `data` parameters. |
| `approve` and `setApprovalForAll` | LSP8 uses token-specific operators. |
| Receiver safety | Transfers can require LSP1 support when `force` is `false`. |

## Comparisons

### Solidity code
Expand Down Expand Up @@ -124,15 +153,29 @@ There are 4 main differences for LSP8 to note:

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.
> See the [**LSP8 Standard > LSP1 Token Hooks**](../../standards/tokens/LSP8-Identifiable-Digital-Asset.md#lsp1-token-hooks) section for more details.

- **Additional `data` field**: for the `mint(...)`, `transfer(...)`, and [`burn(...)`](../../contracts/contracts/LSP8IdentifiableDigitalAsset/extensions/LSP8Burnable.md#burn) functions.

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..._).

> 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**: via a [flexible data key / value store](<(../../standards/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).
- **LSP8 metadata is generic**: via a [flexible data key / value store](../../standards/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).

### Dynamic NFT metadata and safe transfers

In ERC721 projects, dynamic NFT metadata usually depends on changing `tokenURI` responses or refreshing marketplace caches. LSP8 gives the collection a standardized ERC725Y storage surface, so collection metadata and token-specific metadata can be represented through LSP4 data keys instead of relying only on URI conventions.

The `force` parameter is the main transfer-safety decision when migrating ERC721 safe transfer behavior:

| Transfer goal | LSP8 setting |
| ---------------------------------------------------------------- | ------------------------------------------------ |
| Match broad ERC721 transfer compatibility | Use `force` set to `true`. |
| Require the recipient contract to support LSP1 receiver behavior | Use `force` set to `false`. |
| Let a recipient react to incoming tokens | Pass contextual `data` and require LSP1 support. |

Use `force` set to `false` when the recipient must be able to react to the NFT transfer, register the asset, or reject unsupported assets. Use `force` set to `true` only when the application intentionally allows transfers to addresses that do not implement LSP1.

### Interact with the Token Contract

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: 'EIP-4337 and Universal Profiles'
sidebar_label: ' 🛠️ Integrate EIP-4337'
description: 'Learn how to integrate the EIP-4337 extension into your Universal Profile.'
description: 'Learn how EIP-4337 account abstraction relates to Universal Profiles and how to integrate the EIP-4337 extension.'
sidebar_position: 2
---

Expand All @@ -10,6 +11,12 @@ sidebar_position: 2
This guide assumes that you are already familiar with the [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) standard and [Universal Profiles](/standards/introduction.md).
:::

## EIP-4337 and Universal Profiles

EIP-4337 defines a UserOperation flow with bundlers, an EntryPoint contract, and optional paymasters. Universal Profiles define the account layer on LUKSO: metadata, controllers, permissions, receiver behavior, relay execution, and extensions.

The EIP-4337 extension lets Universal Profiles participate in 4337-style transaction routing while keeping the Universal Profile account model. Use it when your application specifically needs UserOperation infrastructure. Use the native LSP6 and LSP25 flow when your main requirement is permissioned relay execution for Universal Profiles.

## Prerequisites for Integration

### Key Manager
Expand Down
25 changes: 24 additions & 1 deletion docs/learn/universal-profile/connect-profile/siwe.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
---
title: 'SIWE Login With Universal Profiles and EIP-1271'
sidebar_label: 'UP Log-in & SIWE'
sidebar_position: 2
description: Learn how to log-in a Universal Profile using SIWE (Sign-In With Ethereum).
description: Learn how to log in with a Universal Profile using SIWE and EIP-1271 smart contract signature verification.
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import StructuredData from '@site/src/components/StructuredData';

<StructuredData
data={{
'@context': 'https://schema.org',
'@type': 'TechArticle',
headline: 'SIWE Login With Universal Profiles and EIP-1271',
description:
'Guide for implementing Sign-In with Ethereum with LUKSO Universal Profiles, controller signatures, and EIP-1271 verification.',
author: { '@type': 'Organization', name: 'LUKSO' },
publisher: { '@type': 'Organization', name: 'LUKSO' },
mainEntityOfPage:
'https://docs.lukso.tech/learn/universal-profile/connect-profile/siwe/',
isAccessibleForFree: true,
}}
/>

# Log-in a Universal Profile (SIWE)

Expand Down Expand Up @@ -166,6 +183,12 @@ Your dApp has now received a message signed by the controller address of the Uni

To check the signature, you can use the [`isValidSignature(...)`](/contracts/contracts/UniversalProfile/UniversalProfile.md#isvalidsignature) method of the [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) standardization. If the signature is valid, the method will return the magic value `0x1626ba7e`, indicating a successful verification.

### SIWE with smart contract accounts

With an Externally Owned Account, a server can usually recover the signer from the SIWE message and compare it to the connected address. A Universal Profile is a smart contract account, so the Universal Profile address is the user identity while a controller signs the message.

For Universal Profiles, verify SIWE logins through `isValidSignature(...)` on the Universal Profile. This lets the account decide whether the controller that produced the signature currently has the `SIGN` permission. If the controller is revoked later, future SIWE checks can fail without changing the Universal Profile address used as the application identity.

<Tabs groupId="provider-lib">
<TabItem value="ethers" label="ethers" attributes={{className: "tab_ethers"}}>

Expand Down
Loading