diff --git a/docs/learn/digital-assets/choose-lsp7-vs-lsp8.md b/docs/learn/digital-assets/choose-lsp7-vs-lsp8.md
index 032f5af0f6..f47f754c4b 100644
--- a/docs/learn/digital-assets/choose-lsp7-vs-lsp8.md
+++ b/docs/learn/digital-assets/choose-lsp7-vs-lsp8.md
@@ -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
@@ -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.
diff --git a/docs/learn/migrate/migrate-erc20-to-lsp7.md b/docs/learn/migrate/migrate-erc20-to-lsp7.md
index bd67aecaab..5552cc6137 100644
--- a/docs/learn/migrate/migrate-erc20-to-lsp7.md
+++ b/docs/learn/migrate/migrate-erc20-to-lsp7.md
@@ -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';
+
+
# 🪙 Migrate ERC20 to LSP7
@@ -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
@@ -118,11 +147,11 @@ 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.
@@ -130,10 +159,23 @@ For full compatibility with ERC20 behavior, set this to empty bytes `""`. This d
> 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
diff --git a/docs/learn/migrate/migrate-erc721-to-lsp8.md b/docs/learn/migrate/migrate-erc721-to-lsp8.md
index 2cec85aa0a..fa2b3e9693 100644
--- a/docs/learn/migrate/migrate-erc721-to-lsp8.md
+++ b/docs/learn/migrate/migrate-erc721-to-lsp8.md
@@ -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';
+
+
# 🖼️ Migrate ERC721 to LSP8
@@ -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
@@ -124,7 +153,7 @@ 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.
@@ -132,7 +161,21 @@ For full compatibility with ERC721 behavior, set this to empty bytes `""`. This
> 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
diff --git a/docs/learn/universal-profile/advanced-guides/4337-extension.md b/docs/learn/universal-profile/advanced-guides/4337-extension.md
index d670d2d659..2fa0009481 100644
--- a/docs/learn/universal-profile/advanced-guides/4337-extension.md
+++ b/docs/learn/universal-profile/advanced-guides/4337-extension.md
@@ -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
---
@@ -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
diff --git a/docs/learn/universal-profile/connect-profile/siwe.md b/docs/learn/universal-profile/connect-profile/siwe.md
index 2b2ab2af64..8d0e044812 100644
--- a/docs/learn/universal-profile/connect-profile/siwe.md
+++ b/docs/learn/universal-profile/connect-profile/siwe.md
@@ -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';
+
+
# Log-in a Universal Profile (SIWE)
@@ -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.
+
diff --git a/docs/learn/universal-profile/key-manager/execute-relay-transactions.md b/docs/learn/universal-profile/key-manager/execute-relay-transactions.md
index 7b6d72b5ff..5a3f357fa4 100644
--- a/docs/learn/universal-profile/key-manager/execute-relay-transactions.md
+++ b/docs/learn/universal-profile/key-manager/execute-relay-transactions.md
@@ -1,6 +1,8 @@
---
+title: 'Gasless Transactions With LSP25 Relay Calls'
sidebar_label: 'Execute Relay Transactions'
sidebar_position: 3
+description: Learn how gasless transactions work with Universal Profiles, LSP25 Execute Relay Call, LSP6 permissions, and Transaction Relay Services.
---
import Tabs from '@theme/Tabs';
@@ -36,6 +38,14 @@ To execute relay calls, the address [signing the relay transaction](/standards/a
:::
+## Gasless onboarding with LSP25
+
+Gasless onboarding means the user can authorize a Universal Profile action before holding native tokens for gas. The controller signs the LSP25 relay payload off-chain, then a Transaction Relay Service submits the transaction and pays the gas.
+
+This does not give the Transaction Relay Service control over the Universal Profile. The Key Manager verifies the signature, nonce, validity timestamps, and `EXECUTE_RELAY_CALL` permission before the payload is executed.
+
+Common gasless flows include creating or registering a Universal Profile, editing LSP3 Profile Metadata, transferring LYX during onboarding, or completing an app action sponsored by a dApp.
+
## Setup
You will need the following dependencies to follow this guide:
diff --git a/docs/learn/universal-profile/key-manager/grant-permissions.md b/docs/learn/universal-profile/key-manager/grant-permissions.md
index ae36fff875..6931681754 100644
--- a/docs/learn/universal-profile/key-manager/grant-permissions.md
+++ b/docs/learn/universal-profile/key-manager/grant-permissions.md
@@ -1,11 +1,28 @@
---
+title: 'Universal Profile Permissions and Session Keys'
sidebar_label: 'Grant Permissions'
sidebar_position: 2
-description: Learn how to give some permissions to an address to perform specific actions on a Universal Profile on LUKSO.
+description: Learn how to grant Universal Profile permissions, session keys, app controllers, allowed calls, and allowed ERC725Y data keys on LUKSO.
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
+import StructuredData from '@site/src/components/StructuredData';
+
+
# Grant Permissions
@@ -36,6 +53,20 @@ These permissions are stored in the Universal Profile. **We need to update thre
| [`AddressPermissions[index]`](/standards/access-control/lsp6-key-manager.md#retrieving-addresses-with-permissions) | holds a controller address at a specific index. | We need to **add the beneficiary address at the new index**. |
| [`AddressPermissions:Permissions:`](/standards/access-control/lsp6-key-manager.md#address-permissions) | this data key holds the permissions of a controller address. | We need to **add the permissions of the beneficiary address** under this data key. |
+### App permissions and session keys
+
+LSP6 permissions can be used for more than permanent owner devices. A controller can represent a dApp, backend service, temporary session, recovery setup, or automation contract. The important part is to grant only the permission bits and restrictions needed for that role.
+
+| Controller use case | Permission pattern |
+| --------------------------------- | --------------------------------------------------------------------- |
+| Login-only controller | `SIGN` |
+| Metadata editor | `SETDATA` with Allowed ERC725Y Data Keys |
+| App session for one protocol | `CALL` with Allowed Calls |
+| Transaction Relay Service flow | `EXECUTE_RELAY_CALL` |
+| Full recovery or admin controller | Use broad permissions only when the controller is trusted accordingly |
+
+Allowed Calls and Allowed ERC725Y Data Keys are the scoping layer that turns a broad capability into an app-specific permission. Use them when a controller should only interact with selected contracts or selected data keys.
+
## Setup
To follow this guide, we will need the following libraries and packages:
diff --git a/docs/learn/universal-profile/metadata/read-profile-data.md b/docs/learn/universal-profile/metadata/read-profile-data.md
index 3c43148c55..b3c3086148 100644
--- a/docs/learn/universal-profile/metadata/read-profile-data.md
+++ b/docs/learn/universal-profile/metadata/read-profile-data.md
@@ -1,7 +1,7 @@
---
sidebar_label: 'Read Profile Data'
sidebar_position: 1
-description: Learn how to read profile data from your Universal Profile.
+description: Learn how to read Universal Profile metadata, ERC725Y data keys, received assets, issued assets, and smart account identity data.
---
import Tabs from '@theme/Tabs';
@@ -24,6 +24,12 @@ A Universal Profile is a smart contract that uses a generic key-value store (ERC
ERC725Y data keys are defined by their **ERC725Y JSON schema**. The schema is an object describing the information (= value) stored under this data key. Therefore, a list of schemas let us know which ERC725Y data keys we can set and **which information we can retrieve and edit from the Universal Profile**.
+## Profile metadata and identity
+
+Externally Owned Accounts do not have a standard place to store profile metadata. Universal Profiles use ERC725Y data keys and LSP3 Profile Metadata so dApps can read the same profile name, images, links, received assets, issued assets, and app-specific data from the account itself.
+
+This makes the Universal Profile address the stable identity for login, display, ownership, and social features, while controllers and private keys can be added, restricted, or revoked separately through the Key Manager.
+

:::info
diff --git a/docs/learn/universal-profile/metadata/retrieve-owned-assets.md b/docs/learn/universal-profile/metadata/retrieve-owned-assets.md
index c81a63b47f..f49258ef7a 100644
--- a/docs/learn/universal-profile/metadata/retrieve-owned-assets.md
+++ b/docs/learn/universal-profile/metadata/retrieve-owned-assets.md
@@ -1,7 +1,7 @@
---
sidebar_label: 'Get Profile Owned Assets'
sidebar_position: 3
-description: Learn how to retrieve the list of assets owned by a Universal Profile.
+description: Learn how to discover tokens and NFTs owned by a Universal Profile using LSP5 Received Assets and ERC725Y data keys.
---
import CodeSandbox from "@site/src/components/CodeSandbox";
@@ -24,6 +24,8 @@ Every Universal Profile deployed with the [**🧩 Universal Profile Browser Exte
This guide shows you how to easily retrieve the list of owned asset, by fetching the values stored under the [`LSP5ReceivedAssets[]`](../../../standards/metadata/lsp5-received-assets.md#lsp5receivedassets) data key.
+Unlike event-only token discovery, LSP5 lets dApps read the asset list from the Universal Profile storage itself. Indexers can still use token transfer events for history and balances, but `LSP5ReceivedAssets[]` provides a standard account-level inventory of received LSP7 and LSP8 assets.
+
## Using erc725.js
The [erc725.js](../../../tools/dapps/erc725js/getting-started.md) enable us to do that easily.
diff --git a/docs/learn/universal-profile/universal-receiver/accept-reject-assets.md b/docs/learn/universal-profile/universal-receiver/accept-reject-assets.md
index 38bf202c7d..55bed32d7e 100644
--- a/docs/learn/universal-profile/universal-receiver/accept-reject-assets.md
+++ b/docs/learn/universal-profile/universal-receiver/accept-reject-assets.md
@@ -1,6 +1,7 @@
---
sidebar_label: 'Accept & Reject Assets'
sidebar_position: 7
+description: Learn how Universal Profiles can accept, reject, register, or react to incoming LSP7 tokens and LSP8 NFTs with a Universal Receiver Delegate.
---
import Tabs from '@theme/Tabs';
@@ -12,6 +13,8 @@ Each user can create a **Universal Receiver Delegate** contract with some **cus

+Universal Receiver Delegates are the LUKSO pattern for receiver hooks. They let a Universal Profile decide how to react when it receives assets, including rejecting unsupported tokens, registering received assets, or forwarding a portion of received tokens to another address.
+
## Reject any Assets
To **reject any assets** received by the Universal Profile, we need to create a Universal Receiver Delegate contract that reverts when there is an asset transfer (LSP7 & LSP8). The [`typeId`](/contracts/contracts/LSP0ERC725Account/LSP0ERC725Account.md#universalreceiver) parameter will give us more context on the call being made.
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 fc0d715fb0..58cc2a3f8d 100644
--- a/docs/learn/universal-profile/universal-receiver/create-receiver-forwarder.md
+++ b/docs/learn/universal-profile/universal-receiver/create-receiver-forwarder.md
@@ -1,7 +1,7 @@
---
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.
+description: Create an LSP1 Universal Receiver Delegate that auto-forwards a portion of received LSP7 tokens from a Universal Profile.
---
import Tabs from '@theme/Tabs';
@@ -17,6 +17,8 @@ We will this contract an **LSP1 Forwarder**. Every time our 🆙 will receive a
An example scenario could be: _"each time I receive USDT, I want to automatically transfer 20% to my wife's UP"_.
+This is an example of a receiver hook: the token transfer notifies the Universal Profile, the Universal Receiver Delegate receives the context, and the delegate runs custom logic for the incoming asset.
+
## Setup & Requirements
:::success Tips
diff --git a/docs/standards/access-control/lsp14-ownable-2-step.md b/docs/standards/access-control/lsp14-ownable-2-step.md
index 68265ee753..ab9c5bf107 100644
--- a/docs/standards/access-control/lsp14-ownable-2-step.md
+++ b/docs/standards/access-control/lsp14-ownable-2-step.md
@@ -1,7 +1,7 @@
---
sidebar_label: 'LSP14 - Ownable 2-Step'
sidebar_position: 2
-description: "LUKSO's LSP14 - Ownable2Step: an extended version of EIP173 - Contract Ownership Standard for transferring and renouncing ownership."
+description: "LUKSO's LSP14 - Ownable2Step: a safer smart contract ownership transfer and renounce pattern extending EIP173."
---
# LSP14 - Ownable 2-Step
@@ -30,6 +30,12 @@ Renouncing ownership of the contract in [EIP173 - Contract Ownership Standard](h
What is needed is a safer mechanism for managing contract ownership.
+## Safe contract ownership transfer
+
+LSP14 reduces one-step ownership mistakes by separating ownership transfer into an initiation step and an acceptance step. The new owner must explicitly call `acceptOwnership()` before control changes, which helps prevent losing ownership to a mistyped address, an inaccessible account, or a contract that cannot manage the asset.
+
+The same safety principle applies to renouncing ownership. Instead of a single irreversible transaction, LSP14 requires an initiation period and a confirmation window before ownership is fully renounced.
+
## What does this standard represent ?
**LSP14 - Ownable2Step** is an extended version of [EIP173 - Contract Ownership Standard](https://eips.ethereum.org/EIPS/eip-173) that uses a 2-step process for transferring and renouncing ownership.
@@ -52,7 +58,7 @@ The control of the contract is fully transferred _once the new owner has accepte

-2. The new owner claims ownership of the contract by calling the [`acceptOwnership()`](../../contracts/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md #acceptownership)` function.
+2. The new owner claims ownership of the contract by calling the [`acceptOwnership()`](../../contracts/contracts/LSP14Ownable2Step/LSP14Ownable2Step.md#acceptownership) function.

diff --git a/docs/standards/accounts/introduction.md b/docs/standards/accounts/introduction.md
index b480da90b9..af59188a06 100644
--- a/docs/standards/accounts/introduction.md
+++ b/docs/standards/accounts/introduction.md
@@ -1,7 +1,7 @@
---
sidebar_label: 'Introduction'
sidebar_position: 1
-description: Introduction to LUKSO's Universal Profiles.
+description: Introduction to LUKSO Universal Profiles, smart contract accounts with metadata, permissions, asset receiving, relay execution, and recovery patterns.
---
# Universal Profiles
@@ -19,6 +19,20 @@ Building an identity on top of keys is almost impossible because keys are likely
Blockchain-based accounts can change the way of interacting on-chain, allowing the usage of multiple components together. Used in combination with a Controller (see **[LSP6 - Key Manager](../access-control/lsp6-key-manager.md)**), they could allow any entity to execute or set some data on your profile directly or via relay execution. Finally, developers could use contracts for social recovery if keys are lost. All these components together can enhance the blockchain experience.
+## Wallet vs Universal Profile
+
+A wallet is usually a signing interface around one or more private keys. A Universal Profile is the smart contract account that represents the user, creator, organization, or application on-chain. The Universal Profile address can stay the same while controllers, permissions, metadata, and recovery flows change over time.
+
+This distinction matters for dApps:
+
+| Builder question | Universal Profile pattern |
+| ---------------------------------------------------- | -------------------------------------------------------------- |
+| Where does profile identity live? | LSP3 Profile Metadata stored through ERC725Y data keys. |
+| How can multiple devices or apps have scoped access? | LSP6 Key Manager permissions and restrictions. |
+| How does a smart account receive assets safely? | LSP1 Universal Receiver and Universal Receiver Delegate logic. |
+| How can users act without holding gas first? | LSP25 relay execution through a Transaction Relay Service. |
+| How can the account evolve without changing address? | LSP17 extensions and LSP20 call verification patterns. |
+
diff --git a/docs/standards/accounts/lsp17-contract-extension.md b/docs/standards/accounts/lsp17-contract-extension.md
index 85c4dd1496..be40da5140 100644
--- a/docs/standards/accounts/lsp17-contract-extension.md
+++ b/docs/standards/accounts/lsp17-contract-extension.md
@@ -1,7 +1,7 @@
---
sidebar_label: 'LSP17 - Contract Extension'
sidebar_position: 7
-description: LUKSO's LSP17 - Contract Extension for enabling smart contracts to support new functions through extensions.
+description: LUKSO's LSP17 - Contract Extension for adding smart contract functions after deployment through reusable extension contracts.
---
# LSP17 - Contract Extension
@@ -28,6 +28,12 @@ What is required is a method to extend the functionalities of a smart contract e
A possible solution to this problem is to establish a system of extensions that can be added to a smart contract, enabling it to **acquire new functionalities** without the need for redeployment.
+## Add functions after deployment
+
+LSP17 is the LUKSO pattern for smart contracts that need to support new function selectors after deployment without changing the contract address. Instead of redeploying the original contract, the extendable contract maps a function selector to an extension contract and forwards calls for that selector through its fallback logic.
+
+This is useful when a protocol, Universal Profile, marketplace, or asset contract needs to add support for new interfaces over time while keeping the original contract address and existing integrations.
+
## What does this standard represent ?
This standard defines a mechanism for extending a contract to support new functions through the use of **extensions**.
diff --git a/docs/standards/accounts/lsp20-call-verification.md b/docs/standards/accounts/lsp20-call-verification.md
index 16a9b77825..599ec92d60 100644
--- a/docs/standards/accounts/lsp20-call-verification.md
+++ b/docs/standards/accounts/lsp20-call-verification.md
@@ -1,7 +1,7 @@
---
sidebar_label: 'LSP20 - Call Verification'
sidebar_position: 8
-description: LUKSO's LSP20 - Call Verification for delegating the the verification of a function call to another smart contract.
+description: LUKSO's LSP20 - Call Verification for direct Universal Profile calls, smart account permission checks, and delegated call verification.
---
# LSP20 - Call Verification
@@ -68,4 +68,6 @@ This creates development complexity, as interactions must be crafted, encoded an
LSP20 being embedded in LSP0 (the smart contract based account under a Universal Profile) simplify this complexity, allowing anyone to interact directly with the Universal Profile without having to go through the Key Manager first. The LSP20 module embedded in the Universal Profile will see that the request does not come from the Key Manager directly, and will instead forward the request and the calldata back to the Key Manager to verify the permissions of the caller first.
+This is why LSP20 matters for smart account integrations: dApps can call the Universal Profile as the account they want to interact with, while the Key Manager remains responsible for checking LSP6 permissions, Allowed Calls, value, and calldata before execution.
+

diff --git a/docs/standards/accounts/lsp26-follower-system.md b/docs/standards/accounts/lsp26-follower-system.md
index f3b51eda41..5ea2571803 100644
--- a/docs/standards/accounts/lsp26-follower-system.md
+++ b/docs/standards/accounts/lsp26-follower-system.md
@@ -2,7 +2,7 @@
sidebar_label: 'LSP26 - Follower System'
sidebar_position: 10
title: 'LSP26 - Follower System'
-description: LUKSO's LSP26 Follower System for managing on-chain following relationships between addresses.
+description: LUKSO's LSP26 Follower System for managing on-chain social graph relationships, followers, follows, and profile notifications.
---
# LSP26 - Follower System
@@ -74,6 +74,12 @@ LSP26 integrates with [LSP1-UniversalReceiver](../accounts/lsp1-universal-receiv
This integration allows for real-time reactions to follower changes, enhancing the interactive capabilities of LSP26-compatible addresses.
+## On-chain social graph
+
+For social dApps, LSP26 provides a shared on-chain social graph instead of a follow list that only one application can read. Any app can query followers and following relationships through the same contract, index `Follow` and `Unfollow` events, and combine those relationships with Universal Profile metadata.
+
+Universal Profiles add the identity layer, while LSP1 notifications let profiles or other smart contracts react when they are followed or unfollowed. Use the batch functions when a product flow needs to follow or unfollow several addresses in one transaction.
+
## Deployment
The official LSP26 Follower System contract is deployed at `0xf01103E5a9909Fc0DBe8166dA7085e0285daDDcA` on the LUKSO mainnet. This address is consistent across different EVM-compatible networks when deployed using the [Nick Factory contract](https://github.com/Arachnid/deterministic-deployment-proxy/tree/master).
diff --git a/src/components/StructuredData/index.tsx b/src/components/StructuredData/index.tsx
new file mode 100644
index 0000000000..7c5bd862b2
--- /dev/null
+++ b/src/components/StructuredData/index.tsx
@@ -0,0 +1,19 @@
+import Head from '@docusaurus/Head';
+
+type StructuredDataProps = {
+ data: Record | Record[];
+};
+
+export default function StructuredData({ data }: StructuredDataProps) {
+ const items = Array.isArray(data) ? data : [data];
+
+ return (
+
+ {items.map((item, index) => (
+
+ ))}
+
+ );
+}