Network setup
LitVMSwap lives on LitVM. Here's everything you need to point your wallet, script or app at the right chain.
The basics
| Setting | Value |
|---|---|
| Network name | LitVM LiteForge |
| Chain id | 4441 (hex 0x1159) |
| Gas token | zkLTC, 18 decimals |
| RPC | https://liteforge.rpc.caldera.xyz/http |
| Explorer | liteforge.explorer.caldera.xyz |
| Multicall3 | 0xcA11bde05977b3631167028862bE2a173976CA11 |
| Block time | Fast. Roughly 4 blocks per second |
Testing in a browser? This button asks your wallet to add the network (nothing gets signed):
viem
import { defineChain } from 'viem'
export const litvm = defineChain({
id: 4441,
name: 'LitVM LiteForge',
nativeCurrency: { name: 'zkLTC', symbol: 'zkLTC', decimals: 18 },
rpcUrls: { default: { http: ['https://liteforge.rpc.caldera.xyz/http'] } },
blockExplorers: {
default: { name: 'LiteForge Explorer', url: 'https://liteforge.explorer.caldera.xyz' },
},
contracts: {
multicall3: { address: '0xcA11bde05977b3631167028862bE2a173976CA11' },
},
})wagmi
import { createConfig, http } from 'wagmi'
import { litvm } from './litvm'
export const config = createConfig({
chains: [litvm],
transports: { [litvm.id]: http() },
})ethers v6
import { JsonRpcProvider } from 'ethers'
export const provider = new JsonRpcProvider('https://liteforge.rpc.caldera.xyz/http', {
chainId: 4441,
name: 'litvm',
})Adding the network by hand
Some wallets want the details typed in. Use the values from the table above, or call
wallet_addEthereumChain yourself:
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: '0x1159',
chainName: 'LitVM LiteForge',
nativeCurrency: { name: 'zkLTC', symbol: 'zkLTC', decimals: 18 },
rpcUrls: ['https://liteforge.rpc.caldera.xyz/http'],
blockExplorerUrls: ['https://liteforge.explorer.caldera.xyz'],
},
],
})Gotchas worth knowing
Native zkLTC vs wzkLTC
zkLTC pays for gas, like ETH on Ethereum. Pools can't hold native coins, so they hold wzkLTC at
0x315374AA9b5536037Cc1Efeea2439CCC0913A77e, a standard wrapper with deposit() and withdraw(uint256).
When you talk to the APIs, use 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE to mean native zkLTC. When you talk to
the pools directly, use the wzkLTC address.
block.number inside contracts
LitVM is an Arbitrum-style chain. Inside a contract, block.number gives you the parent chain's block number,
not LitVM's. The number your RPC, explorer and eth_getLogs use comes from the ArbSys precompile:
interface ArbSys {
function arbBlockNumber() external view returns (uint256);
}
function litvmBlock() view returns (uint256) {
// ArbSys lives at address 0x64 on Arbitrum-style chains
return ArbSys(address(0x64)).arbBlockNumber();
}If you store a block number on chain so you can look up logs later, store this one. block.timestamp is fine as
is. Heads up: a local fork (anvil and friends) usually won't show the difference, so test on the real chain too.
Blocks are quick
About 4 blocks a second means around 345,000 blocks a day. That matters when you call eth_getLogs: ask for
ranges of a few thousand blocks at a time instead of "everything since launch". There's a ready helper on
Events and indexing.
Decimals
Read decimals() from every token you touch. On LitVM, ZKUSDC uses 18 decimals, not 6.