Skip to content

lukso-network/tools-lsp-factory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

612 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@lukso/lsp-factory.js

Deploy Universal Profiles, LSP7 tokens, and LSP8 NFTs on LUKSO and other EVM chains — all in a single function call.

NPM version Tests

📖 Full Documentation


Instead of manually deploying and wiring up multiple contracts, lsp-factory.js handles everything atomically:

Deployments use viem and LSP23LinkedContractsFactory — so linked contracts (e.g., a Universal Profile + its Key Manager) are always deployed together in a single transaction.

Requirements: Node.js >= 22 · TypeScript >= 5.9


Supported Networks

Network Chain ID
LUKSO Mainnet 42
LUKSO Testnet 4201
Ethereum Mainnet 1
BASE 8453

All factory contracts are deployed at the same deterministic address on every supported chain (0x2300000A84D25dF63081feAa37ba6b62C4c89a30).


Install

npm install @lukso/lsp-factory.js

Setup

import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { luksoTestnet } from 'viem/chains'; // swap for any supported chain
import { LSPFactory } from '@lukso/lsp-factory.js';

const account = privateKeyToAccount('0x...');

const factory = new LSPFactory(
  createPublicClient({ chain: luksoTestnet, transport: http() }),
  createWalletClient({ account, chain: luksoTestnet, transport: http() }),
);

Deploy a Universal Profile

Deploys a Universal Profile + Key Manager atomically, sets up controller permissions and a Universal Receiver Delegate.

const { LSP0ERC725Account, LSP6KeyManager } = await factory.UniversalProfile.deploy({
  controllerAddresses: ['0x...'], // wallet(s) that will control this profile
});

console.log('Profile:', LSP0ERC725Account.address);
console.log('Key Manager:', LSP6KeyManager.address);

With profile metadata (name, avatar, description via LSP3):

import { ERC725 } from '@erc725/erc725.js';
import LSP3ProfileSchema from '@erc725/erc725.js/schemas/LSP3ProfileMetadata.json';

const { values } = new ERC725(LSP3ProfileSchema).encodeData([
  { keyName: 'LSP3Profile', value: { json: metadata, url: 'ipfs://...' } },
]);

await factory.UniversalProfile.deploy(
  { controllerAddresses: ['0x...'], lsp3DataValue: values[0] },
  { salt: '0x...' }, // optional: makes the address deterministic
);

With custom controller permissions:

import { ERC725 } from '@erc725/erc725.js';

await factory.UniversalProfile.deploy({
  controllerAddresses: [
    '0xAdmin...',      // gets ALL_PERMISSIONS by default
    {
      address: '0xAgent...',
      permissions: ERC725.encodePermissions({ SUPER_SETDATA: true }),
    },
  ],
});

Pre-compute addresses before deploying:

const { upAddress, keyManagerAddress } = await factory.UniversalProfile.computeAddress(
  { controllerAddresses: ['0x...'] },
  { salt: '0x...' },
);

Deploy an LSP7 Token (Fungible)

const { LSP7DigitalAsset } = await factory.LSP7DigitalAsset.deploy({
  name: 'My Token',
  symbol: 'MTK',
  controllerAddress: '0x...', // token owner
  tokenType: 0,    // 0 = Token · 1 = NFT · 2 = Collection
  isNFT: false,    // true = non-divisible (0 decimals)
});

console.log('Token:', LSP7DigitalAsset.address);

With on-chain metadata:

await factory.LSP7DigitalAsset.deploy({
  name: 'My Token',
  symbol: 'MTK',
  controllerAddress: '0x...',
  tokenType: 0,
  isNFT: false,
  digitalAssetMetadata: {
    verification: { method: 'keccak256(bytes)', data: '0x...' },
    url: 'ipfs://Qm...',
  },
});

Deploy an LSP8 NFT (Non-Fungible)

const { LSP8IdentifiableDigitalAsset } = await factory.LSP8IdentifiableDigitalAsset.deploy({
  name: 'My Collection',
  symbol: 'MNFT',
  controllerAddress: '0x...',
  tokenType: 1,        // 0 = Token · 1 = NFT · 2 = Collection
  tokenIdFormat: 1,    // 0 = bytes32 · 1 = number · 2 = string · 3 = address · 4 = hash
});

console.log('NFT:', LSP8IdentifiableDigitalAsset.address);

Track Deployment Progress

All deploy methods accept an optional onDeployEvents callback:

await factory.UniversalProfile.deploy(
  { controllerAddresses: ['0x...'] },
  {
    onDeployEvents: {
      next: (event) => console.log(event.status, event.contractName),
      error: (err) => console.error(err),
      complete: (contracts) => console.log('Done!', contracts),
    },
  },
);

Development

npm install      # install dependencies
npm run lint     # check code style
npm run build    # compile TypeScript
npm test         # run tests

Contributing

See CONTRIBUTING.md.

License

Apache 2.0

About

Easy deployments of LSP standard Universal Profile and Digital Asset smart contracts

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors