diff --git a/docs/contracts/type-ids.md b/docs/contracts/type-ids.md
index e952fac3f4..17bf08f76c 100644
--- a/docs/contracts/type-ids.md
+++ b/docs/contracts/type-ids.md
@@ -1,26 +1,62 @@
---
-title: Universal Receiver Type IDs
+title: LSP1 Notification Type IDs
+sidebar_label: LSP1 Notification Type IDs
---
-# Universal Receiver Type IDs
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# LSP1 Notification Type IDs
The **LSP1 Type IDs** listed below are unique identifiers used across the LSP standards for the [Universal Receiver](../standards/accounts/lsp1-universal-receiver.md) notification mechanism.
These Type IDs are sent as the `typeId` parameter when calling the `universalReceiver(bytes32 typeId, bytes data)` function on contracts implementing [LSP1](../standards/accounts/lsp1-universal-receiver.md). They allow contracts to identify what type of notification they are receiving and react accordingly.
-For instance:
+When a Universal Profile receives a notification, its Universal Receiver function ([LSP1](../standards/accounts/lsp1-universal-receiver.md)) is called with a `typeId` and `data`. A connected [LSP1 Delegate](../standards/accounts/lsp1-universal-receiver-delegate.md) inspects the `typeId` to decide how to react. For example:
-- Notify a sender that LSP7 tokens are being transferred from their balance
-- Notify a recipient about receiving LSP7 tokens
-- Notify a profile that they have a new follower
+- Auto-register a received token / NFT in your list of received assets
+- Swap automatically a token received
+- Send a tip or an NFT to a new follower
+- Auto-split received LYX / LSP7 tokens between collaborators
+- Save a new follower to a subscriber list for future airdrops (NFT music tracks, vouchers, newsletter, etc...)
+- Any customisation you might want
-## Using Type IDs in JavaScript
+## Notification Type IDs list
-The Type IDs are available as constants from the [`@lukso/lsp-smart-contracts`](https://www.npmjs.com/package/@lukso/lsp-smart-contracts) npm package:
+| Notification Type | TypeId value | Details |
+| --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
+| When receiving native LYX (ERC725Account) | [`LSP0ValueReceived`](#lsp0valuereceived)
`0x9c4705229491d365fb5434052e12a386d6771d976bea61070a8c694e8affea3d` | [↓](#lsp0valuereceived) |
+| When ownership transfer starts (ERC725Account) | [`LSP0OwnershipTransferStarted`](#lsp0ownershiptransferstarted)
`0xe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac6926` | [↓](#lsp0ownershiptransferstarted) |
+| When previous owner is notified of ownership transfer (ERC725Account) | [`LSP0OwnershipTransferred_SenderNotification`](#lsp0ownershiptransferred_sendernotification)
`0xa4e59c931d14f7c8a7a35027f92ee40b5f2886b9fdcdb78f30bc5ecce5a2f814` | [↓](#lsp0ownershiptransferred_sendernotification) |
+| When new owner is notified of ownership transfer (ERC725Account) | [`LSP0OwnershipTransferred_RecipientNotification`](#lsp0ownershiptransferred_recipientnotification)
`0xceca317f109c43507871523e82dc2a3cc64dfa18f12da0b6db14f6e23f995538` | [↓](#lsp0ownershiptransferred_recipientnotification) |
+| When sending LSP7 tokens | [`LSP7Tokens_SenderNotification`](#lsp7tokens_sendernotification)
`0x429ac7a06903dbc9c13dfcb3c9d11df8194581fa047c96d7a4171fc7402958ea` | [↓](#lsp7tokens_sendernotification) |
+| When receiving LSP7 tokens | [`LSP7Tokens_RecipientNotification`](#lsp7tokens_recipientnotification)
`0x20804611b3e2ea21c480dc465142210acf4a2485947541770ec1fb87dee4a55c` | [↓](#lsp7tokens_recipientnotification) |
+| When an LSP7 operator is authorized or revoked | [`LSP7Tokens_OperatorNotification`](#lsp7tokens_operatornotification)
`0x386072cc5a58e61263b434c722725f21031cd06e7c552cfaa06db5de8a320dbc` | [↓](#lsp7tokens_operatornotification) |
+| When sending an LSP8 NFT | [`LSP8Tokens_SenderNotification`](#lsp8tokens_sendernotification)
`0xb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab00` | [↓](#lsp8tokens_sendernotification) |
+| When receiving an LSP8 NFT | [`LSP8Tokens_RecipientNotification`](#lsp8tokens_recipientnotification)
`0x0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d` | [↓](#lsp8tokens_recipientnotification) |
+| When an LSP8 operator is authorized or revoked | [`LSP8Tokens_OperatorNotification`](#lsp8tokens_operatornotification)
`0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970` | [↓](#lsp8tokens_operatornotification) |
+| When receiving native LYX (Vault) | [`LSP9ValueReceived`](#lsp9valuereceived)
`0x468cd1581d7bc001c3b685513d2b929b55437be34700410383d58f3aa1ea0abc` | [↓](#lsp9valuereceived) |
+| When ownership transfer starts (Vault) | [`LSP9OwnershipTransferStarted`](#lsp9ownershiptransferstarted)
`0xaefd43f45fed1bcd8992f23c803b6f4ec45cf6b62b0d404d565f290a471e763f` | [↓](#lsp9ownershiptransferstarted) |
+| When previous owner is notified of Vault ownership transfer | [`LSP9OwnershipTransferred_SenderNotification`](#lsp9ownershiptransferred_sendernotification)
`0x0c622e58e6b7089ae35f1af1c86d997be92fcdd8c9509652022d41aa65169471` | [↓](#lsp9ownershiptransferred_sendernotification) |
+| When new owner is notified of Vault ownership transfer | [`LSP9OwnershipTransferred_RecipientNotification`](#lsp9ownershiptransferred_recipientnotification)
`0x79855c97dbc259ce395421d933d7bc0699b0f1561f988f09a9e8633fd542fe5c` | [↓](#lsp9ownershiptransferred_recipientnotification) |
+| When ownership transfer starts (Ownable2Step) | [`LSP14OwnershipTransferStarted`](#lsp14ownershiptransferstarted)
`0xee9a7c0924f740a2ca33d59b7f0c2929821ea9837ce043ce91c1823e9c4e52c0` | [↓](#lsp14ownershiptransferstarted) |
+| When previous owner is notified of Ownable2Step transfer | [`LSP14OwnershipTransferred_SenderNotification`](#lsp14ownershiptransferred_sendernotification)
`0xa124442e1cc7b52d8e2ede2787d43527dc1f3ae0de87f50dd03e27a71834f74c` | [↓](#lsp14ownershiptransferred_sendernotification) |
+| When new owner is notified of Ownable2Step transfer | [`LSP14OwnershipTransferred_RecipientNotification`](#lsp14ownershiptransferred_recipientnotification)
`0xe32c7debcb817925ba4883fdbfc52797187f28f73f860641dab1a68d9b32902c` | [↓](#lsp14ownershiptransferred_recipientnotification) |
+| When someone follows you | [`LSP26FollowerSystem_FollowNotification`](#lsp26followersystem_follownotification)
`0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a` | [↓](#lsp26followersystem_follownotification) |
+| When someone unfollows you | [`LSP26FollowerSystem_UnfollowNotification`](#lsp26followersystem_unfollownotification)
`0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f` | [↓](#lsp26followersystem_unfollownotification) |
-```bash
-npm install @lukso/lsp-smart-contracts
-```
+## Using Type ID
+
+:::success Recommendation
+
+It is recommended to import each notification type ID from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package to ensure the logic of your dApp or smart contract checks against the correct Type ID values.
+
+:::
+
+
+
+
+The JavaScript constants are exported from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package.
```js
import { LSP1_TYPE_IDS } from '@lukso/lsp-smart-contracts';
@@ -35,9 +71,79 @@ LSP1_TYPE_IDS.LSP7Tokens_RecipientNotification;
LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
```
-> **Note:** The JavaScript constants are exported from the `@lukso/lsp-smart-contracts` package. The corresponding Solidity constants are defined in each LSP's contract constants file (e.g., `LSP7Constants.sol`, `LSP26Constants.sol`).
->
-> See the [lsp-smart-contracts repository](https://github.com/lukso-network/lsp-smart-contracts) for the full source code.
+
+
+
+The JavaScript constants are exported from the [`@lukso/lsp-smart-contracts`](https://github.com/lukso-network/lsp-smart-contracts) package.
+
+```js
+import { LSP1_TYPE_IDS } from '@lukso/lsp-smart-contracts';
+
+// The constants are plain bytes32 hex strings
+LSP1_TYPE_IDS.LSP7Tokens_RecipientNotification;
+```
+
+
+
+
+The Solidity constants are defined in each LSP's contract constants file (e.g., `LSP7Constants.sol`, `LSP26Constants.sol`).
+
+```solidity
+import { _TYPEID_LSP7_TOKENSSENDER } from "@lukso/lsp7-contracts/contracts/LSP7Constants.sol";
+
+function universalReceiverDelegate(
+ address sender,
+ uint256 value,
+ bytes32 typeId,
+ bytes memory data
+) external returns (bytes memory) {
+ if (typeId == _TYPEID_LSP7_TOKENSSENDER) {
+ // handle LSP7 token sent notification
+ }
+}
+```
+
+
+
+
+
+ How Type IDs are generated
+
+Each Type ID is a `bytes32` value computed as the **keccak256 hash of the Type ID name string**. For example:
+
+```
+keccak256("LSP7Tokens_SenderNotification") = 0x429ac7a06903dbc9c13dfcb3c9d11df8194581fa047c96d7a4171fc7402958ea
+```
+
+You can verify any Type ID by hashing its name:
+
+
+
+
+```js
+import { keccak256, toUtf8Bytes } from 'ethers'; // ethers v6
+const typeId = keccak256(toUtf8Bytes('LSP7Tokens_SenderNotification'));
+```
+
+
+
+
+```js
+import { keccak256, toHex } from 'viem';
+const typeId = keccak256(toHex('LSP7Tokens_SenderNotification'));
+```
+
+
+
+
+```solidity
+bytes32 typeId = keccak256("LSP7Tokens_SenderNotification");
+```
+
+
+
+
+
---
@@ -49,40 +155,163 @@ LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP0ValueReceived"` |
| **TypeID** | `0x9c4705229491d365fb5434052e12a386d6771d976bea61070a8c694e8affea3d` |
+| **TypeID generation** | `keccak256("LSP0ValueReceived")` |
| **Used in:** | [`constructor(address)`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#constructor), [`receive()`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#receive), [`fallback(bytes)`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#fallback), [`execute(uint256,address,uint256,bytes)`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#execute), [`executeBatch(uint256[],address[],uint256[],bytes[])`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#executebatch), [`setData(bytes32,bytes)`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#setdata), [`setDataBatch(bytes32[],bytes[])`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#setdatabatch) |
| **Solidity constant:** | `_TYPEID_LSP0_VALUE_RECEIVED` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP0ValueReceived` |
+No additional data is sent with this notification (empty bytes `""`).
+
### `LSP0OwnershipTransferStarted`
| | |
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP0OwnershipTransferStarted"` |
| **TypeID** | `0xe17117c9d2665d1dbeb479ed8058bbebde3c50ac50e2e65619f60006caac6926` |
+| **TypeID generation** | `keccak256("LSP0OwnershipTransferStarted")` |
| **Used in:** | [`transferOwnership(address)`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#transferownership) |
| **Solidity constant:** | `_TYPEID_LSP0_OwnershipTransferStarted` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP0OwnershipTransferStarted` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [currentOwner, pendingNewOwner] = abiCoder.decode(
+ ['address', 'address'],
+ data,
+);
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [currentOwner, pendingNewOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+```
+
+
+
+
+```solidity
+(address currentOwner, address pendingNewOwner) = abi.decode(data, (address, address));
+```
+
+
+
+
+
+
### `LSP0OwnershipTransferred_SenderNotification`
| | |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP0OwnershipTransferred_SenderNotification"` |
| **TypeID** | `0xa4e59c931d14f7c8a7a35027f92ee40b5f2886b9fdcdb78f30bc5ecce5a2f814` |
+| **TypeID generation** | `keccak256("LSP0OwnershipTransferred_SenderNotification")` |
| **Used in:** | [`acceptOwnership()`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#acceptownership)
[`renounceOwnership()`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#renounceownership) |
| **Solidity constant:** | `_TYPEID_LSP0_OwnershipTransferred_SenderNotification` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP0OwnershipTransferred_SenderNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [previousOwner, newOwner] = abiCoder.decode(['address', 'address'], data);
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [previousOwner, newOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+```solidity
+(address previousOwner, address newOwner) = abi.decode(data, (address, address));
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+
+
### `LSP0OwnershipTransferred_RecipientNotification`
| | |
| ------------------------ | ----------------------------------------------------------------------------------------- |
| **Name** | `"LSP0OwnershipTransferred_RecipientNotification"` |
| **TypeID** | `0xceca317f109c43507871523e82dc2a3cc64dfa18f12da0b6db14f6e23f995538` |
+| **TypeID generation** | `keccak256("LSP0OwnershipTransferred_RecipientNotification")` |
| **Used in:** | [`acceptOwnership()`](./contracts/LSP0ERC725Account/LSP0ERC725Account.md#acceptownership) |
| **Solidity constant:** | `_TYPEID_LSP0_OwnershipTransferred_RecipientNotification` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP0OwnershipTransferred_RecipientNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [previousOwner, newOwner] = abiCoder.decode(['address', 'address'], data);
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [previousOwner, newOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+```
+
+
+
+
+```solidity
+(address previousOwner, address newOwner) = abi.decode(data, (address, address));
+```
+
+
+
+
+
+
---
## LSP7 - Digital Asset
@@ -93,30 +322,190 @@ LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP7Tokens_SenderNotification"` |
| **TypeID** | `0x429ac7a06903dbc9c13dfcb3c9d11df8194581fa047c96d7a4171fc7402958ea` |
+| **TypeID generation** | `keccak256("LSP7Tokens_SenderNotification")` |
| **Used in:** | [`_burn(address,uint256,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_burn),
[`_transfer(address,address,uint256,bool,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_transfer) |
| **Solidity constant:** | `_TYPEID_LSP7_TOKENSSENDER` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP7Tokens_SenderNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [operator, from, to, amount, transferData] = abiCoder.decode(
+ ['address', 'address', 'address', 'uint256', 'bytes'],
+ data,
+);
+// `to` is address(0) when burning
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [operator, from, to, amount, transferData] = decodeAbiParameters(
+ [
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'uint256' },
+ { type: 'bytes' },
+ ],
+ data,
+);
+// `to` is address(0) when burning
+```
+
+
+
+
+```solidity
+(
+ address operator,
+ address from,
+ address to,
+ uint256 amount,
+ bytes memory transferData
+) = abi.decode(data, (address, address, address, uint256, bytes));
+// `to` is address(0) when burning
+```
+
+
+
+
+
+
### `LSP7Tokens_RecipientNotification`
| | |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Name** | `"LSP7Tokens_RecipientNotification"` |
| **TypeID** | `0x20804611b3e2ea21c480dc465142210acf4a2485947541770ec1fb87dee4a55c` |
+| **TypeID generation** | `keccak256("LSP7Tokens_RecipientNotification")` |
| **Used in:** | [`_mint(address,uint256,bool,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_mint),
[`_transfer(address,address,uint256,bool,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#_transfer) |
| **Solidity constant:** | `_TYPEID_LSP7_TOKENSRECIPIENT` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP7Tokens_RecipientNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [operator, from, to, amount, transferData] = abiCoder.decode(
+ ['address', 'address', 'address', 'uint256', 'bytes'],
+ data,
+);
+// `from` is address(0) when minting
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [operator, from, to, amount, transferData] = decodeAbiParameters(
+ [
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'uint256' },
+ { type: 'bytes' },
+ ],
+ data,
+);
+// `from` is address(0) when minting
+```
+
+
+
+
+```solidity
+(
+ address operator,
+ address from,
+ address to,
+ uint256 amount,
+ bytes memory transferData
+) = abi.decode(data, (address, address, address, uint256, bytes));
+// `from` is address(0) when minting
+```
+
+
+
+
+
+
### `LSP7Tokens_OperatorNotification`
| | |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP7Tokens_OperatorNotification"` |
| **TypeID** | `0x386072cc5a58e61263b434c722725f21031cd06e7c552cfaa06db5de8a320dbc` |
+| **TypeID generation** | `keccak256("LSP7Tokens_OperatorNotification")` |
| **Used in:** | [`authorizeOperator(address,uint256,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#authorizeoperator), [`revokeOperator(address,bool,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#revokeoperator), [`increaseAllowance(address,uint256,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#increaseallowance), [`decreaseAllowance(address,uint256,bytes)`](./contracts/LSP7DigitalAsset/LSP7DigitalAsset.md#decreaseallowance) |
| **Solidity constant:** | `_TYPEID_LSP7_TOKENOPERATOR` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP7Tokens_OperatorNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [tokenOwner, allowance, operatorNotificationData] = abiCoder.decode(
+ ['address', 'uint256', 'bytes'],
+ data,
+);
+// allowance is 0 on revokeOperator
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [tokenOwner, allowance, operatorNotificationData] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'uint256' }, { type: 'bytes' }],
+ data,
+);
+// allowance is 0 on revokeOperator
+```
+
+
+
+
+```solidity
+(
+ address tokenOwner,
+ uint256 allowance,
+ bytes memory operatorNotificationData
+) = abi.decode(data, (address, uint256, bytes));
+// allowance is 0 on revokeOperator
+```
+
+
+
+
+
+
---
## LSP8 - Identifiable Digital Asset
@@ -127,30 +516,195 @@ LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP8Tokens_SenderNotification"` |
| **TypeID** | `0xb23eae7e6d1564b295b4c3e3be402d9a2f0776c57bdf365903496f6fa481ab00` |
+| **TypeID generation** | `keccak256("LSP8Tokens_SenderNotification")` |
| **Used in:** | [`_burn(bytes32,bytes)`](./contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#_burn),
[`_transfer(address,address,bytes32,bool,bytes)`](./contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#_transfer) |
| **Solidity constant:** | `_TYPEID_LSP8_TOKENSSENDER` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP8Tokens_SenderNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [operator, from, to, tokenId, transferData] = abiCoder.decode(
+ ['address', 'address', 'address', 'bytes32', 'bytes'],
+ data,
+);
+// `to` is address(0) when burning
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [operator, from, to, tokenId, transferData] = decodeAbiParameters(
+ [
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'bytes32' },
+ { type: 'bytes' },
+ ],
+ data,
+);
+// `to` is address(0) when burning
+```
+
+
+
+
+```solidity
+(
+ address operator,
+ address from,
+ address to,
+ bytes32 tokenId,
+ bytes memory transferData
+) = abi.decode(data, (address, address, address, bytes32, bytes));
+// `to` is address(0) when burning
+```
+
+
+
+
+
+
### `LSP8Tokens_RecipientNotification`
| | |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Name** | `"LSP8Tokens_RecipientNotification"` |
| **TypeID** | `0x0b084a55ebf70fd3c06fd755269dac2212c4d3f0f4d09079780bfa50c1b2984d` |
+| **TypeID generation** | `keccak256("LSP8Tokens_RecipientNotification")` |
| **Used in:** | [`_mint(address,bytes32,bool,bytes)`](./contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#_mint),
[`_transfer(address,address,bytes32,bool,bytes)`](./contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#_transfer) |
| **Solidity constant:** | `_TYPEID_LSP8_TOKENSRECIPIENT` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP8Tokens_RecipientNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [operator, from, to, tokenId, transferData] = abiCoder.decode(
+ ['address', 'address', 'address', 'bytes32', 'bytes'],
+ data,
+);
+// `from` is address(0) when minting
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [operator, from, to, tokenId, transferData] = decodeAbiParameters(
+ [
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'address' },
+ { type: 'bytes32' },
+ { type: 'bytes' },
+ ],
+ data,
+);
+// `from` is address(0) when minting
+```
+
+
+
+
+```solidity
+(
+ address operator,
+ address from,
+ address to,
+ bytes32 tokenId,
+ bytes memory transferData
+) = abi.decode(data, (address, address, address, bytes32, bytes));
+// `from` is address(0) when minting
+```
+
+
+
+
+
+
### `LSP8Tokens_OperatorNotification`
| | |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP8Tokens_OperatorNotification"` |
-| **TypeID** | `0x468cd1581d7bc001c3b685513d2b929b55437be34700410383d58f3aa1ea0abc` |
+| **TypeID** | `0x8a1c15a8799f71b547e08e2bcb2e85257e81b0a07eee2ce6712549eef1f00970` |
+| **TypeID generation** | `keccak256("LSP8Tokens_OperatorNotification")` |
| **Used in:** | [`authorizeOperator(address,bytes32,bytes)`](./contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#authorizeoperator), [`revokeOperator(address,bytes32,bool,bytes)`](./contracts/LSP8IdentifiableDigitalAsset/LSP8IdentifiableDigitalAsset.md#revokeoperator) |
| **Solidity constant:** | `_TYPEID_LSP8_TOKENOPERATOR` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP8Tokens_OperatorNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [tokenOwner, tokenId, authorized, operatorNotificationData] =
+ abiCoder.decode(['address', 'bytes32', 'bool', 'bytes'], data);
+// authorized = true on authorizeOperator, false on revokeOperator
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [tokenOwner, tokenId, authorized, operatorNotificationData] =
+ decodeAbiParameters(
+ [
+ { type: 'address' },
+ { type: 'bytes32' },
+ { type: 'bool' },
+ { type: 'bytes' },
+ ],
+ data,
+ );
+// authorized = true on authorizeOperator, false on revokeOperator
+```
+
+
+
+
+```solidity
+(
+ address tokenOwner,
+ bytes32 tokenId,
+ bool authorized,
+ bytes memory operatorNotificationData
+) = abi.decode(data, (address, bytes32, bool, bytes));
+// authorized = true on authorizeOperator, false on revokeOperator
+```
+
+
+
+
+
+
---
## LSP9 - Vault
@@ -161,40 +715,163 @@ LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP9ValueReceived"` |
| **TypeID** | `0x468cd1581d7bc001c3b685513d2b929b55437be34700410383d58f3aa1ea0abc` |
+| **TypeID generation** | `keccak256("LSP9ValueReceived")` |
| **Used in:** | [`constructor(address)`](./contracts/LSP9Vault/LSP9Vault.md#constructor), [`receive()`](./contracts/LSP9Vault/LSP9Vault.md#receive), [`fallback(bytes)`](./contracts/LSP9Vault/LSP9Vault.md#fallback), [`execute(uint256,address,uint256,bytes)`](./contracts/LSP9Vault/LSP9Vault.md#execute), [`executeBatch(uint256[],address[],uint256[],bytes[])`](./contracts/LSP9Vault/LSP9Vault.md#executebatch) |
| **Solidity constant:** | `_TYPEID_LSP9_VALUE_RECEIVED` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP9ValueReceived` |
+No additional data is sent with this notification (empty bytes `""`).
+
### `LSP9OwnershipTransferStarted`
| | |
| ------------------------ | ------------------------------------------------------------------------------------ |
| **Name** | `"LSP9OwnershipTransferStarted"` |
| **TypeID** | `0xaefd43f45fed1bcd8992f23c803b6f4ec45cf6b62b0d404d565f290a471e763f` |
+| **TypeID generation** | `keccak256("LSP9OwnershipTransferStarted")` |
| **Used in:** | [`transferOwnership(address)`](./contracts/LSP9Vault/LSP9Vault.md#transferownership) |
| **Solidity constant:** | `_TYPEID_LSP9_OwnershipTransferStarted` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP9OwnershipTransferStarted` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [currentOwner, pendingNewOwner] = abiCoder.decode(
+ ['address', 'address'],
+ data,
+);
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [currentOwner, pendingNewOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+```
+
+
+
+
+```solidity
+(address currentOwner, address pendingNewOwner) = abi.decode(data, (address, address));
+```
+
+
+
+
+
+
### `LSP9OwnershipTransferred_SenderNotification`
| | |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP9OwnershipTransferred_SenderNotification"` |
| **TypeID** | `0x0c622e58e6b7089ae35f1af1c86d997be92fcdd8c9509652022d41aa65169471` |
+| **TypeID generation** | `keccak256("LSP9OwnershipTransferred_SenderNotification")` |
| **Used in:** | [`acceptOwnership()`](./contracts/LSP9Vault/LSP9Vault.md#acceptownership)
[`renounceOwnership()`](./contracts/LSP9Vault/LSP9Vault.md#renounceownership) |
| **Solidity constant:** | `_TYPEID_LSP9_OwnershipTransferred_SenderNotification` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP9OwnershipTransferred_SenderNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [previousOwner, newOwner] = abiCoder.decode(['address', 'address'], data);
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [previousOwner, newOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+```solidity
+(address previousOwner, address newOwner) = abi.decode(data, (address, address));
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+
+
### `LSP9OwnershipTransferred_RecipientNotification`
| | |
| ------------------------ | ------------------------------------------------------------------------- |
| **Name** | `"LSP9OwnershipTransferred_RecipientNotification"` |
| **TypeID** | `0x79855c97dbc259ce395421d933d7bc0699b0f1561f988f09a9e8633fd542fe5c` |
+| **TypeID generation** | `keccak256("LSP9OwnershipTransferred_RecipientNotification")` |
| **Used in:** | [`acceptOwnership()`](./contracts/LSP9Vault/LSP9Vault.md#acceptownership) |
| **Solidity constant:** | `_TYPEID_LSP9_OwnershipTransferred_RecipientNotification` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP9OwnershipTransferred_RecipientNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [previousOwner, newOwner] = abiCoder.decode(['address', 'address'], data);
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [previousOwner, newOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+```
+
+
+
+
+```solidity
+(address previousOwner, address newOwner) = abi.decode(data, (address, address));
+```
+
+
+
+
+
+
---
## LSP14 - Ownable 2-Step
@@ -205,30 +882,150 @@ LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
| ------------------------ | ---------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP14OwnershipTransferStarted"` |
| **TypeID** | `0xee9a7c0924f740a2ca33d59b7f0c2929821ea9837ce043ce91c1823e9c4e52c0` |
+| **TypeID generation** | `keccak256("LSP14OwnershipTransferStarted")` |
| **Used in:** | [`transferOwnership(address)`](./contracts/LSP14Ownable2Step/LSP14Ownable2Step.md#transferownership) |
| **Solidity constant:** | `_TYPEID_LSP14_OwnershipTransferStarted` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP14OwnershipTransferStarted` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [currentOwner, pendingNewOwner] = abiCoder.decode(
+ ['address', 'address'],
+ data,
+);
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [currentOwner, pendingNewOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+```
+
+
+
+
+```solidity
+(address currentOwner, address pendingNewOwner) = abi.decode(data, (address, address));
+```
+
+
+
+
+
+
#### `LSP14OwnershipTransferred_SenderNotification`
| | |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP14OwnershipTransferred_SenderNotification"` |
| **TypeID** | `0xa124442e1cc7b52d8e2ede2787d43527dc1f3ae0de87f50dd03e27a71834f74c` |
+| **TypeID generation** | `keccak256("LSP14OwnershipTransferred_SenderNotification")` |
| **Used in:** | [`acceptOwnership()`](./contracts/LSP14Ownable2Step/LSP14Ownable2Step.md#acceptownership)
[`renounceOwnership()`](./contracts/LSP14Ownable2Step/LSP14Ownable2Step.md#renounceownership) |
| **Solidity constant:** | `_TYPEID_LSP14_OwnershipTransferred_SenderNotification` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP14OwnershipTransferred_SenderNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [previousOwner, newOwner] = abiCoder.decode(['address', 'address'], data);
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [previousOwner, newOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+```solidity
+(address previousOwner, address newOwner) = abi.decode(data, (address, address));
+// newOwner is address(0) on renounceOwnership
+```
+
+
+
+
+
+
#### `LSP14OwnershipTransferred_RecipientNotification`
| | |
| ------------------------ | ----------------------------------------------------------------------------------------- |
| **Name** | `"LSP14OwnershipTransferred_RecipientNotification"` |
| **TypeID** | `0xe32c7debcb817925ba4883fdbfc52797187f28f73f860641dab1a68d9b32902c` |
+| **TypeID generation** | `keccak256("LSP14OwnershipTransferred_RecipientNotification")` |
| **Used in:** | [`acceptOwnership()`](./contracts/LSP14Ownable2Step/LSP14Ownable2Step.md#acceptownership) |
| **Solidity constant:** | `_TYPEID_LSP14_OwnershipTransferred_RecipientNotification` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP14OwnershipTransferred_RecipientNotification` |
+
+How to decode notification data?
+
+
+
+
+```js
+import { AbiCoder } from 'ethers';
+
+const abiCoder = new AbiCoder();
+const [previousOwner, newOwner] = abiCoder.decode(['address', 'address'], data);
+```
+
+
+
+
+```js
+import { decodeAbiParameters } from 'viem';
+
+const [previousOwner, newOwner] = decodeAbiParameters(
+ [{ type: 'address' }, { type: 'address' }],
+ data,
+);
+```
+
+
+
+
+```solidity
+(address previousOwner, address newOwner) = abi.decode(data, (address, address));
+```
+
+
+
+
+
+
---
## LSP26 - Follower System
@@ -239,16 +1036,100 @@ LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification;
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP26FollowerSystem_FollowNotification"` |
| **TypeID** | `0x71e02f9f05bcd5816ec4f3134aa2e5a916669537ec6c77fe66ea595fabc2d51a` |
+| **TypeID generation** | `keccak256("LSP26FollowerSystem_FollowNotification")` |
| **Used in:** | [`follow(address)`](../standards/accounts/lsp26-follower-system.md) — notifies the followed address that they have a new follower |
| **Solidity constant:** | `_TYPEID_LSP26_FOLLOW` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP26FollowerSystem_FollowNotification` |
+
+How to decode notification data?
+
+> **Note:** LSP26 uses `abi.encodePacked` (not `abi.encode`), so the data is 20 bytes (the raw address) rather than 32 bytes (ABI-padded).
+
+
+
+
+```js
+import { dataSlice, getAddress } from 'ethers';
+
+// data is 20 bytes (not ABI-padded)
+const follower = getAddress(dataSlice(data, 0, 20));
+```
+
+
+
+
+```js
+import { getAddress, slice } from 'viem';
+
+// data is 20 bytes (not ABI-padded)
+const follower = getAddress(slice(data, 0, 20));
+```
+
+
+
+
+```solidity
+address follower = address(bytes20(data));
+```
+
+
+
+
+
+
### `LSP26FollowerSystem_UnfollowNotification`
| | |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| **Name** | `"LSP26FollowerSystem_UnfollowNotification"` |
| **TypeID** | `0x9d3c0b4012b69658977b099bdaa51eff0f0460f421fba96d15669506c00d1c4f` |
+| **TypeID generation** | `keccak256("LSP26FollowerSystem_UnfollowNotification")` |
| **Used in:** | [`unfollow(address)`](../standards/accounts/lsp26-follower-system.md) — notifies the unfollowed address that they lost a follower |
| **Solidity constant:** | `_TYPEID_LSP26_UNFOLLOW` |
| **JavaScript constant:** | `LSP1_TYPE_IDS.LSP26FollowerSystem_UnfollowNotification` |
+
+
+How to decode notification data?
+
+> **Note:** LSP26 uses `abi.encodePacked` (not `abi.encode`), so the data is 20 bytes (the raw address) rather than 32 bytes (ABI-padded).
+
+
+
+
+```js
+import { dataSlice, getAddress } from 'ethers';
+
+// data is 20 bytes (not ABI-padded)
+const unfollower = getAddress(dataSlice(data, 0, 20));
+```
+
+
+
+
+```js
+import { getAddress, slice } from 'viem';
+
+// data is 20 bytes (not ABI-padded)
+const unfollower = getAddress(slice(data, 0, 20));
+```
+
+
+
+
+```solidity
+address unfollower = address(bytes20(data));
+```
+
+
+
+
+
+
+---
+
+## See also
+
+- [Build a Universal Receiver Delegate](../standards/accounts/lsp1-universal-receiver-delegate.md)
+- [LSP1 Universal Receiver standard](../standards/accounts/lsp1-universal-receiver.md)
+- [lsp-smart-contracts constants reference](https://github.com/lukso-network/lsp-smart-contracts)