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)