Skip to main content

viem & wagmi

viem natively supports LUKSO Mainnet and Testnet as built-in chains — no custom chain configuration needed. This page covers client setup, reading Universal Profile data, calling LSP contracts, and React hooks with wagmi.

LUKSO is a first-class viem chain

viem includes lukso (chainId: 42) and luksoTestnet (chainId: 4201) as built-in chains.

import { lukso, luksoTestnet } from 'viem/chains';

No custom chain config required.

Installation

# viem only
npm install viem

# with wagmi (React)
npm install viem wagmi @tanstack/react-query

Chain Setup

Public Client (read-only)

Use a public client for reading on-chain data from scripts or server-side code:

import { createPublicClient, http } from 'viem';
import { lukso } from 'viem/chains';

const publicClient = createPublicClient({
chain: lukso,
transport: http(),
});

Wallet Client (browser + UP Extension)

Use a wallet client to send transactions via the UP Browser Extension:

import { createWalletClient, custom } from 'viem';
import { lukso } from 'viem/chains';

const [account] = await window.lukso.request({ method: 'eth_requestAccounts' });

const walletClient = createWalletClient({
account,
chain: lukso,
transport: custom(window.lukso),
});
UP Browser Extension

The UP Browser Extension injects a provider at window.lukso. Use custom(window.lukso) as the transport for browser dApps.

Reading Universal Profile Data

Read a Single Data Key

import { createPublicClient, http } from 'viem';
import { lukso } from 'viem/chains';
import { lsp0Erc725AccountAbi } from '@lukso/lsp0-contracts/abi';

const publicClient = createPublicClient({ chain: lukso, transport: http() });

// LSP3Profile metadata data key
const LSP3_PROFILE_KEY =
'0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5';

const profileData = await publicClient.readContract({
address: '0xYourUPAddress',
abi: lsp0Erc725AccountAbi,
functionName: 'getData',
args: [LSP3_PROFILE_KEY],
});

Read Multiple Data Keys

const [profileData, issuedAssets] = (await publicClient.readContract({
address: '0xYourUPAddress',
abi: lsp0Erc725AccountAbi,
functionName: 'getDataBatch',
args: [
[
'0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5', // LSP3Profile
'0x412e1c0000000000000000000000000000000000000000000000000000000000', // LSP12IssuedAssets[]
],
],
})) as [`0x${string}`, `0x${string}`];

Interacting with LSP Contracts

Check LSP7 Token Balance

import { lsp7DigitalAssetAbi } from '@lukso/lsp7-contracts/abi';

const balance = await publicClient.readContract({
address: '0xTokenContractAddress',
abi: lsp7DigitalAssetAbi,
functionName: 'balanceOf',
args: ['0xHolderAddress'],
});

Transfer LSP7 Tokens

import { lsp7DigitalAssetAbi } from '@lukso/lsp7-contracts/abi';

const txHash = await walletClient.writeContract({
address: '0xTokenContractAddress',
abi: lsp7DigitalAssetAbi,
functionName: 'transfer',
args: [
account, // from
'0xRecipient', // to
BigInt(100), // amount
false, // force: false = recipient must have a Universal Receiver
'0x', // data
],
});
LSP7 transfer vs ERC20 transfer

LSP7's transfer function has a different signature than ERC20: it requires from, to, amount, force, and data. Setting force to false will revert if the recipient does not have a Universal Receiver.

Using with wagmi (React)

Config Setup

import { createConfig, http } from 'wagmi';
import { lukso } from 'viem/chains';
import { injected } from 'wagmi/connectors';

export const config = createConfig({
chains: [lukso],
transports: {
[lukso.id]: http(),
},
connectors: [injected()],
});

Wrap your app with the required providers:

import { WagmiProvider } from 'wagmi';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { config } from './wagmi.config';

const queryClient = new QueryClient();

export function App() {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{/* your app */}
</QueryClientProvider>
</WagmiProvider>
);
}

Reading Data with Hooks

import { useReadContract } from 'wagmi';
import { lsp0Erc725AccountAbi } from '@lukso/lsp0-contracts/abi';

const LSP3_PROFILE_KEY =
'0x5ef83ad9559033e6e941db7d7c495acdce616347d28e90c7ce47cbfcfcad3bc5';

function ProfileData({ upAddress }: { upAddress: `0x${string}` }) {
const { data, isLoading } = useReadContract({
address: upAddress,
abi: lsp0Erc725AccountAbi,
functionName: 'getData',
args: [LSP3_PROFILE_KEY],
});

if (isLoading) return <span>Loading...</span>;
return <pre>{String(data ?? '')}</pre>;
}
info

wagmi works well for read operations and standard wallet interactions. For advanced LSP-specific features like relay transactions or batch calls, use viem directly.

Using with UP Provider (Grid mini-apps)

For LUKSO Grid mini-apps, combine viem with @lukso/up-provider for seamless one-click connect. The UP Provider handles the connection lifecycle while viem handles all contract interactions.

See the UP Provider documentation for setup details.

Migration from ethers.js

Coming from ethers.js?
ethers.jsviem
ProviderPublicClient
SignerWalletClient
ContractgetContract / readContract
BigNumberbigint (native JS)
ethers.utils.parseEtherparseEther (from viem)