From 314ddb12219d383bcb8d8bbc7ba879de03701c04 Mon Sep 17 00:00:00 2001 From: emmet-bot Date: Thu, 5 Mar 2026 07:41:42 +0100 Subject: [PATCH 1/6] docs: replace lsp-factory.js deprecation notice with v4 documentation Replace the deprecation notice with full v4 documentation covering: - Supported networks (LUKSO Mainnet/Testnet, Ethereum, BASE) - viem-based setup with PublicClient and WalletClient - Universal Profile deployment (with LSP3 metadata, custom permissions, address pre-computation) - LSP7 and LSP8 digital asset deployment - Deployment event tracking Co-Authored-By: Claude Opus 4.6 --- .../dapps/lsp-factoryjs/getting-started.md | 180 +++++++++++++++++- 1 file changed, 175 insertions(+), 5 deletions(-) diff --git a/docs/tools/dapps/lsp-factoryjs/getting-started.md b/docs/tools/dapps/lsp-factoryjs/getting-started.md index 21dacd5e9..6f9eb74a3 100644 --- a/docs/tools/dapps/lsp-factoryjs/getting-started.md +++ b/docs/tools/dapps/lsp-factoryjs/getting-started.md @@ -4,12 +4,182 @@ sidebar_position: 1.1 # Getting Started -:::warning Deprecation notice +`@lukso/lsp-factory.js` is a helper library for deploying [Universal Profiles](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-0-ERC725Account.md), [LSP7 Digital Assets](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-7-DigitalAsset.md), and [LSP8 Identifiable Digital Assets](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-8-IdentifiableDigitalAsset.md). -This package is deprecated. Please check the following guides and library: +v4 uses [viem](https://viem.sh/) for all blockchain interactions and deploys contracts atomically via [LSP23LinkedContractsFactory](../../../standards/factories/lsp23-linked-contracts-factory.md). -- [Deploying Universal Profiles with LSP23 Factory](/learn/universal-profile/advanced-guides/deploy-up-with-lsp23/) -- [Deploying tokens and NFTs](/learn/digital-assets/getting-started) -- [`lsp-utils`](../lsp-utils/getting-started.md) library to easily set profile and asset metadata +## Supported Networks +All contracts (LSP23 factory, base implementations) are deployed at the same deterministic addresses across chains via the [Nick Factory (EIP-2470)](https://eips.ethereum.org/EIPS/eip-2470). + +**LSP23 Factory Address:** `0x2300000A84D25dF63081feAa37ba6b62C4c89a30` + +| Network | Chain ID | +| ------------------ | -------- | +| LUKSO Mainnet | 42 | +| LUKSO Testnet | 4201 | +| Ethereum Mainnet | 1 | +| BASE | 8453 | + +## Installation + +```bash +npm install @lukso/lsp-factory.js +``` + +## Setup + +Create a [viem](https://viem.sh/) `PublicClient` (for reading) and `WalletClient` (for signing transactions), then pass them to `LSPFactory`: + +```typescript +import { createPublicClient, createWalletClient, http } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { luksoTestnet } from 'viem/chains'; +import { LSPFactory } from '@lukso/lsp-factory.js'; + +const account = privateKeyToAccount('0x...'); + +const publicClient = createPublicClient({ + chain: luksoTestnet, + transport: http(), +}); + +const walletClient = createWalletClient({ + account, + chain: luksoTestnet, + transport: http(), +}); + +const factory = new LSPFactory(publicClient, walletClient); +``` + +:::tip +You can use any viem-supported chain. Just swap `luksoTestnet` for `lukso`, `mainnet`, `base`, etc. ::: + +## Deploying a Universal Profile + +Deploys an [LSP0 Universal Profile](../../../standards/accounts/lsp0-erc725account.md) and [LSP6 KeyManager](../../../standards/access-control/lsp6-key-manager.md) atomically via LSP23, then configures controller permissions and a Universal Receiver Delegate. + +```typescript +const contracts = await factory.UniversalProfile.deploy({ + controllerAddresses: ['0x...'], // Addresses that will control the UP +}); + +console.log('UP Address:', contracts.LSP0ERC725Account.address); +console.log('KeyManager Address:', contracts.LSP6KeyManager.address); +``` + +### With LSP3 metadata and a deterministic salt + +```typescript +const contracts = await factory.UniversalProfile.deploy( + { + controllerAddresses: ['0x...'], + lsp3DataValue: '0x...', // Pre-encoded LSP3Profile data (VerifiableURI) + }, + { + salt: '0x...', // bytes32 salt for deterministic address generation + }, +); +``` + +### With custom controller permissions + +```typescript +const contracts = await factory.UniversalProfile.deploy({ + controllerAddresses: [ + '0xFullPermissionsAddress', // Gets ALL_PERMISSIONS by default + { + address: '0xLimitedAddress', + permissions: '0x0000000000000000000000000000000000000000000000000000000000000010', + }, + ], +}); +``` + +### Pre-computing addresses + +Compute the UP and KeyManager addresses before deploying: + +```typescript +const { upAddress, keyManagerAddress } = + await factory.UniversalProfile.computeAddress( + { controllerAddresses: ['0x...'] }, + { salt: '0x...' }, // Use the same salt you will deploy with + ); +``` + +## Deploying an LSP7 Digital Asset + +Deploys an [LSP7 Digital Asset](../../../standards/tokens/LSP7-Digital-Asset.md) (fungible token) as a minimal proxy: + +```typescript +const contracts = await factory.LSP7DigitalAsset.deploy({ + name: 'My Token', + symbol: 'MTK', + controllerAddress: '0x...', // Owner of the token contract + tokenType: 0, // 0 = Token, 1 = NFT, 2 = Collection + isNFT: false, // Whether the token is non-divisible +}); + +console.log('LSP7 Address:', contracts.LSP7DigitalAsset.address); +``` + +### With metadata + +```typescript +const contracts = await factory.LSP7DigitalAsset.deploy({ + name: 'My Token', + symbol: 'MTK', + controllerAddress: '0x...', + tokenType: 0, + isNFT: false, + digitalAssetMetadata: { + verification: { + method: 'keccak256(utf8)', + data: '0x...', + }, + url: 'ipfs://Qm...', + }, +}); +``` + +## Deploying an LSP8 Identifiable Digital Asset + +Deploys an [LSP8 Identifiable Digital Asset](../../../standards/tokens/LSP8-Identifiable-Digital-Asset.md) (NFT) as a minimal proxy: + +```typescript +const contracts = await factory.LSP8IdentifiableDigitalAsset.deploy({ + name: 'My NFT Collection', + symbol: 'MNFT', + controllerAddress: '0x...', + tokenType: 1, // 0 = Token, 1 = NFT, 2 = Collection + tokenIdFormat: 1, // Token ID format (e.g., 1 = Number) +}); + +console.log('LSP8 Address:', contracts.LSP8IdentifiableDigitalAsset.address); +``` + +## Deployment Events + +All `deploy` methods accept an `onDeployEvents` callback for tracking deployment progress: + +```typescript +const contracts = await factory.UniversalProfile.deploy( + { controllerAddresses: ['0x...'] }, + { + onDeployEvents: { + next: (event) => { + console.log(event.status, event.contractName, event.functionName); + }, + error: (error) => { + console.error('Deployment error:', error); + }, + complete: (deployedContracts) => { + console.log('Deployment complete:', deployedContracts); + }, + }, + }, +); +``` From 074cbc43f978cdcf911578b80f32c49e8a12cf67 Mon Sep 17 00:00:00 2001 From: emmet-bot Date: Thu, 5 Mar 2026 07:45:06 +0100 Subject: [PATCH 2/6] style: format getting-started.md with prettier --- docs/tools/dapps/lsp-factoryjs/getting-started.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/tools/dapps/lsp-factoryjs/getting-started.md b/docs/tools/dapps/lsp-factoryjs/getting-started.md index 6f9eb74a3..9cb5582d5 100644 --- a/docs/tools/dapps/lsp-factoryjs/getting-started.md +++ b/docs/tools/dapps/lsp-factoryjs/getting-started.md @@ -14,12 +14,12 @@ All contracts (LSP23 factory, base implementations) are deployed at the same det **LSP23 Factory Address:** `0x2300000A84D25dF63081feAa37ba6b62C4c89a30` -| Network | Chain ID | -| ------------------ | -------- | -| LUKSO Mainnet | 42 | -| LUKSO Testnet | 4201 | -| Ethereum Mainnet | 1 | -| BASE | 8453 | +| Network | Chain ID | +| ---------------- | -------- | +| LUKSO Mainnet | 42 | +| LUKSO Testnet | 4201 | +| Ethereum Mainnet | 1 | +| BASE | 8453 | ## Installation @@ -92,7 +92,8 @@ const contracts = await factory.UniversalProfile.deploy({ '0xFullPermissionsAddress', // Gets ALL_PERMISSIONS by default { address: '0xLimitedAddress', - permissions: '0x0000000000000000000000000000000000000000000000000000000000000010', + permissions: + '0x0000000000000000000000000000000000000000000000000000000000000010', }, ], }); From 9c702f1ca4eb8ab1a7eb80cd395c06d8fd699695 Mon Sep 17 00:00:00 2001 From: emmet-bot Date: Mon, 16 Mar 2026 14:46:44 +0100 Subject: [PATCH 3/6] fix: Address Leo's review comments on lsp-factory getting-started MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix verification method: keccak256(utf8) → keccak256(bytes) - Add erc725.js encoding example for lsp3DataValue generation - Add tokenIdFormat constants reference (0-4 with descriptions) - Add chain import examples in the tip callout (lukso, mainnet, base) - Add 'Next steps' section linking to edit profile, digital assets, and type IDs pages --- .../dapps/lsp-factoryjs/getting-started.md | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/docs/tools/dapps/lsp-factoryjs/getting-started.md b/docs/tools/dapps/lsp-factoryjs/getting-started.md index 9cb5582d5..6f31e90ac 100644 --- a/docs/tools/dapps/lsp-factoryjs/getting-started.md +++ b/docs/tools/dapps/lsp-factoryjs/getting-started.md @@ -54,7 +54,15 @@ const factory = new LSPFactory(publicClient, walletClient); ``` :::tip -You can use any viem-supported chain. Just swap `luksoTestnet` for `lukso`, `mainnet`, `base`, etc. +You can use any viem-supported chain. Just swap `luksoTestnet` for the chain you want to deploy to: + +```typescript +import { lukso } from 'viem/chains'; // LUKSO Mainnet (42) +import { luksoTestnet } from 'viem/chains'; // LUKSO Testnet (4201) +import { mainnet } from 'viem/chains'; // Ethereum (1) +import { base } from 'viem/chains'; // BASE (8453) +``` + ::: ## Deploying a Universal Profile @@ -76,7 +84,11 @@ console.log('KeyManager Address:', contracts.LSP6KeyManager.address); const contracts = await factory.UniversalProfile.deploy( { controllerAddresses: ['0x...'], - lsp3DataValue: '0x...', // Pre-encoded LSP3Profile data (VerifiableURI) + // Use erc725.js to encode LSP3Profile metadata: + // import ERC725 from '@erc725/erc725.js'; + // const encoded = erc725.encodeData([{ keyName: 'LSP3Profile', value: { json: metadata, url: 'ipfs://...' } }]); + // lsp3DataValue = encoded.values[0]; + lsp3DataValue: '0x...', // Pre-encoded LSP3Profile VerifiableURI (see above) }, { salt: '0x...', // bytes32 salt for deterministic address generation @@ -138,8 +150,8 @@ const contracts = await factory.LSP7DigitalAsset.deploy({ isNFT: false, digitalAssetMetadata: { verification: { - method: 'keccak256(utf8)', - data: '0x...', + method: 'keccak256(bytes)', + data: '0x...', // keccak256 hash of the JSON metadata file bytes }, url: 'ipfs://Qm...', }, @@ -156,7 +168,13 @@ const contracts = await factory.LSP8IdentifiableDigitalAsset.deploy({ symbol: 'MNFT', controllerAddress: '0x...', tokenType: 1, // 0 = Token, 1 = NFT, 2 = Collection - tokenIdFormat: 1, // Token ID format (e.g., 1 = Number) + // Token ID format constants (from @lukso/lsp8-contracts): + // 0 = UNIQUE_ID (unique bytes32) + // 1 = NUMBER (sequential uint256) + // 2 = STRING (human-readable string) + // 3 = ADDRESS (address packed in bytes32) + // 4 = HASH (keccak256 hash) + tokenIdFormat: 1, }); console.log('LSP8 Address:', contracts.LSP8IdentifiableDigitalAsset.address); @@ -184,3 +202,9 @@ const contracts = await factory.UniversalProfile.deploy( }, ); ``` + +## Next steps + +- [Edit Universal Profile metadata](../../../learn/universal-profile/metadata/edit-profile.md) +- [Deploying tokens and NFTs](../../../learn/digital-assets/getting-started.md) +- [LSP1 Notification Type IDs](../../../contracts/type-ids.md) — understanding notifications when deploying assets From a169ad6bc33aa64f71f09c49f33c1060e10772e4 Mon Sep 17 00:00:00 2001 From: emmet-bot Date: Mon, 16 Mar 2026 16:09:11 +0100 Subject: [PATCH 4/6] fix: Move erc725.js encoding to standalone code block per Leo's suggestion Extract LSP3Profile encoding from inline comments to its own code block before the deploy call, making it easier to copy-paste and test. --- .../dapps/lsp-factoryjs/getting-started.md | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/docs/tools/dapps/lsp-factoryjs/getting-started.md b/docs/tools/dapps/lsp-factoryjs/getting-started.md index 6f31e90ac..0cd451bd9 100644 --- a/docs/tools/dapps/lsp-factoryjs/getting-started.md +++ b/docs/tools/dapps/lsp-factoryjs/getting-started.md @@ -80,15 +80,38 @@ console.log('KeyManager Address:', contracts.LSP6KeyManager.address); ### With LSP3 metadata and a deterministic salt +First, encode your LSP3Profile metadata using [erc725.js](https://docs.lukso.tech/tools/dapps/erc725js/getting-started): + +```typescript +import ERC725 from '@erc725/erc725.js'; + +const erc725 = new ERC725([ + { + name: 'LSP3Profile', + key: '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', + keyType: 'Singleton', + valueType: 'bytes', + valueContent: 'VerifiableURI', + }, +]); + +const encoded = erc725.encodeData([ + { + keyName: 'LSP3Profile', + value: { json: metadata, url: 'ipfs://...' }, + }, +]); + +const lsp3DataValue = encoded.values[0]; +``` + +Then pass it into the deploy call: + ```typescript const contracts = await factory.UniversalProfile.deploy( { controllerAddresses: ['0x...'], - // Use erc725.js to encode LSP3Profile metadata: - // import ERC725 from '@erc725/erc725.js'; - // const encoded = erc725.encodeData([{ keyName: 'LSP3Profile', value: { json: metadata, url: 'ipfs://...' } }]); - // lsp3DataValue = encoded.values[0]; - lsp3DataValue: '0x...', // Pre-encoded LSP3Profile VerifiableURI (see above) + lsp3DataValue, // Pre-encoded LSP3Profile VerifiableURI }, { salt: '0x...', // bytes32 salt for deterministic address generation From a3dcd674f08e07a55847e8623e3b49172ed36ca9 Mon Sep 17 00:00:00 2001 From: emmet-bot Date: Mon, 16 Mar 2026 16:22:18 +0100 Subject: [PATCH 5/6] fix: Address Jean's final review comments - Import LSP3 schema from erc725.js library instead of hardcoding - Add erc725.js to install command - Link LSP23 Factory in deploy description - Use ERC725.encodePermissions() for custom controller permissions with named variables for clarity --- .../dapps/lsp-factoryjs/getting-started.md | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/tools/dapps/lsp-factoryjs/getting-started.md b/docs/tools/dapps/lsp-factoryjs/getting-started.md index 0cd451bd9..c8e17ea67 100644 --- a/docs/tools/dapps/lsp-factoryjs/getting-started.md +++ b/docs/tools/dapps/lsp-factoryjs/getting-started.md @@ -24,7 +24,7 @@ All contracts (LSP23 factory, base implementations) are deployed at the same det ## Installation ```bash -npm install @lukso/lsp-factory.js +npm install @lukso/lsp-factory.js @erc725/erc725.js ``` ## Setup @@ -67,7 +67,7 @@ import { base } from 'viem/chains'; // BASE (8453) ## Deploying a Universal Profile -Deploys an [LSP0 Universal Profile](../../../standards/accounts/lsp0-erc725account.md) and [LSP6 KeyManager](../../../standards/access-control/lsp6-key-manager.md) atomically via LSP23, then configures controller permissions and a Universal Receiver Delegate. +Deploys an [LSP0 Universal Profile](../../../standards/accounts/lsp0-erc725account.md) and [LSP6 KeyManager](../../../standards/access-control/lsp6-key-manager.md) atomically via [LSP23 Factory](../../../standards/factories/lsp23-linked-contracts-factory.md), then configures controller permissions and a Universal Receiver Delegate. ```typescript const contracts = await factory.UniversalProfile.deploy({ @@ -83,17 +83,10 @@ console.log('KeyManager Address:', contracts.LSP6KeyManager.address); First, encode your LSP3Profile metadata using [erc725.js](https://docs.lukso.tech/tools/dapps/erc725js/getting-started): ```typescript -import ERC725 from '@erc725/erc725.js'; +import { ERC725 } from '@erc725/erc725.js'; +import LSP3ProfileSchema from '@erc725/erc725.js/schemas/LSP3ProfileMetadata.json'; -const erc725 = new ERC725([ - { - name: 'LSP3Profile', - key: '0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', - keyType: 'Singleton', - valueType: 'bytes', - valueContent: 'VerifiableURI', - }, -]); +const erc725 = new ERC725(LSP3ProfileSchema); const encoded = erc725.encodeData([ { @@ -122,13 +115,19 @@ const contracts = await factory.UniversalProfile.deploy( ### With custom controller permissions ```typescript +import { ERC725 } from '@erc725/erc725.js'; + +// Replace with the correct addresses for your controllers +const adminController = '0x...'; +const restrictedController = '0x...'; + const contracts = await factory.UniversalProfile.deploy({ controllerAddresses: [ - '0xFullPermissionsAddress', // Gets ALL_PERMISSIONS by default + // Gets ALL_PERMISSIONS by default + adminController, { - address: '0xLimitedAddress', - permissions: - '0x0000000000000000000000000000000000000000000000000000000000000010', + address: restrictedController, + permissions: ERC725.encodePermissions({ SUPER_SETDATA: true }), }, ], }); From 12bf4be79e5c6a1f54240ce70efd4c77f0ab0412 Mon Sep 17 00:00:00 2001 From: emmet-bot Date: Mon, 16 Mar 2026 22:53:21 +0100 Subject: [PATCH 6/6] fix: Use absolute paths for all internal links Replace relative ../../../ paths with absolute /path/to/page format for all internal doc links. --- docs/tools/dapps/lsp-factoryjs/getting-started.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/tools/dapps/lsp-factoryjs/getting-started.md b/docs/tools/dapps/lsp-factoryjs/getting-started.md index c8e17ea67..0af2660d9 100644 --- a/docs/tools/dapps/lsp-factoryjs/getting-started.md +++ b/docs/tools/dapps/lsp-factoryjs/getting-started.md @@ -6,7 +6,7 @@ sidebar_position: 1.1 `@lukso/lsp-factory.js` is a helper library for deploying [Universal Profiles](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-0-ERC725Account.md), [LSP7 Digital Assets](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-7-DigitalAsset.md), and [LSP8 Identifiable Digital Assets](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-8-IdentifiableDigitalAsset.md). -v4 uses [viem](https://viem.sh/) for all blockchain interactions and deploys contracts atomically via [LSP23LinkedContractsFactory](../../../standards/factories/lsp23-linked-contracts-factory.md). +v4 uses [viem](https://viem.sh/) for all blockchain interactions and deploys contracts atomically via [LSP23LinkedContractsFactory](/standards/factories/lsp23-linked-contracts-factory). ## Supported Networks @@ -67,7 +67,7 @@ import { base } from 'viem/chains'; // BASE (8453) ## Deploying a Universal Profile -Deploys an [LSP0 Universal Profile](../../../standards/accounts/lsp0-erc725account.md) and [LSP6 KeyManager](../../../standards/access-control/lsp6-key-manager.md) atomically via [LSP23 Factory](../../../standards/factories/lsp23-linked-contracts-factory.md), then configures controller permissions and a Universal Receiver Delegate. +Deploys an [LSP0 Universal Profile](/standards/accounts/lsp0-erc725account) and [LSP6 KeyManager](/standards/access-control/lsp6-key-manager) atomically via [LSP23 Factory](/standards/factories/lsp23-linked-contracts-factory), then configures controller permissions and a Universal Receiver Delegate. ```typescript const contracts = await factory.UniversalProfile.deploy({ @@ -147,7 +147,7 @@ const { upAddress, keyManagerAddress } = ## Deploying an LSP7 Digital Asset -Deploys an [LSP7 Digital Asset](../../../standards/tokens/LSP7-Digital-Asset.md) (fungible token) as a minimal proxy: +Deploys an [LSP7 Digital Asset](/standards/tokens/LSP7-Digital-Asset) (fungible token) as a minimal proxy: ```typescript const contracts = await factory.LSP7DigitalAsset.deploy({ @@ -182,7 +182,7 @@ const contracts = await factory.LSP7DigitalAsset.deploy({ ## Deploying an LSP8 Identifiable Digital Asset -Deploys an [LSP8 Identifiable Digital Asset](../../../standards/tokens/LSP8-Identifiable-Digital-Asset.md) (NFT) as a minimal proxy: +Deploys an [LSP8 Identifiable Digital Asset](/standards/tokens/LSP8-Identifiable-Digital-Asset) (NFT) as a minimal proxy: ```typescript const contracts = await factory.LSP8IdentifiableDigitalAsset.deploy({ @@ -227,6 +227,6 @@ const contracts = await factory.UniversalProfile.deploy( ## Next steps -- [Edit Universal Profile metadata](../../../learn/universal-profile/metadata/edit-profile.md) -- [Deploying tokens and NFTs](../../../learn/digital-assets/getting-started.md) -- [LSP1 Notification Type IDs](../../../contracts/type-ids.md) — understanding notifications when deploying assets +- [Edit Universal Profile metadata](/learn/universal-profile/metadata/edit-profile) +- [Deploying tokens and NFTs](/learn/digital-assets/getting-started) +- [LSP1 Notification Type IDs](/contracts/type-ids) — understanding notifications when deploying assets