Skip to main content
Elysium is an Arbitrum Orbit chain from Kinetiq that settles to HyperEVM. It runs the standard EVM, so the Ethereum libraries and frameworks work against an Elysium node without modification. The differences are in the chain configuration: chain ID 99901 on Mainnet and 99801 on Testnet, HYPE as the gas token, and a Blockscout API for contract verification.

Chain configuration

Chainstack serves Elysium Mainnet and Elysium Testnet. Elysium’s HYPE comes from HyperEVM through a 1:1 bridge. Fund an Elysium Mainnet account by bridging HYPE from HyperEVM, and an Elysium Testnet account from the faucet or by bridging testnet HYPE from HyperEVM Testnet. Code examples that depend on the network cover both Elysium Mainnet and Elysium Testnet. See Elysium methods for per-method availability.

MetaMask

Add Elysium as a custom network. On Chainstack, get your Elysium endpoint, then in MetaMask select Add a custom network and fill in: MetaMask builds explorer links as <explorer URL>/tx/<hash> and <explorer URL>/address/<address>, and the Kinetiq explorers serve both paths.

ethers.js

Install ethers.js:
To receive new blocks as Elysium produces them, connect to the WSS endpoint and subscribe:

viem

Elysium is not in viem’s bundled chain list, so define it with defineChain:
The elysiumTestnet export in viem/chains is a different chain: Vulcan Forged’s Elysium Testnet, chain ID 1338, with LAVA as its currency. Importing it for Kinetiq’s Elysium gives you the wrong currency symbol and explorer links, and http() without a URL falls back to the Vulcan Forged RPC. Define chains 99901 and 99801 yourself.
The multicall3 entry lets client.multicall batch contract reads into a single eth_call. For Elysium Testnet, pass elysiumTestnet as the client’s chain and use your Elysium Testnet endpoint.

web3.py

Install web3.py:
web3.py rejects lowercase addresses with InvalidAddress. Wrap any address you did not get from the library itself in Web3.to_checksum_address(), as in the main.py example.

Foundry

Install Foundry and pass your Chainstack endpoint with --rpc-url. Read chain data with cast:
Deploy a contract with forge create. Without --broadcast, forge create only simulates the deployment.
Verify the deployed contract on the Blockscout of the network you deployed to. The API does not need a key.

Hardhat

In a Hardhat 3 project that uses @nomicfoundation/hardhat-toolbox-viem, add Elysium Mainnet and Elysium Testnet to hardhat.config.ts. The chainDescriptors entries give hardhat verify the address of each network’s Blockscout API.
configVariable reads ELYSIUM_MAINNET_RPC_URL, ELYSIUM_TESTNET_RPC_URL, and ELYSIUM_PRIVATE_KEY from environment variables or the Hardhat keystore, which keeps the endpoints and the key out of the config file. Hardhat reads a network’s variables only when a task uses that network, so set the variables for the network you deploy to. Deploy with an Ignition module, for example ignition/modules/Counter.ts:

Elysium behaviors that affect tooling

Don’t hard-code 21,000 gas for a HYPE transfer. Nitro adds the cost of posting the transaction to the parent chain to its gas, reported as gasUsedForL1 in the receipt. When that cost is above zero, a plain transfer uses more than 21,000 gas, and a transaction with a hard-coded gas limit of 21000 returns -32000 intrinsic gas too low. ethers.js, viem, web3.py, Foundry, and Hardhat all estimate gas when you don’t set a limit. HyperCore precompiles are not available. Elysium does not have HyperEVM’s HyperCore read precompiles (0x0000000000000000000000000000000000000800 and up) or the CoreWriter contract (0x3333333333333333333333333333333333333333). A call to one of these addresses succeeds and returns empty data, as a call to any address without code does, so a contract ported from HyperEVM reverts when it decodes the result, not at the call. Kinetiq plans a HyperCore market-data precompile and an ElysiumCoreWriter predeploy for an ArbOS upgrade after the Mainnet launch. See Building on Elysium. Pending transactions are never delivered. Elysium has a single sequencer and no public mempool. eth_subscribe("newPendingTransactions") and eth_newPendingTransactionFilter return an ID but deliver nothing, so an ethers.js provider.on("pending") listener never fires. Watch new blocks or transaction receipts instead. See Pending transactions are accepted but never delivered. Block-count limits cover little time. Elysium produces several blocks per second, and the block time varies with load, so limits defined in blocks span much less time than on Ethereum. A 10,000-block eth_getLogs request covers minutes of chain time, not hours, and eth_getProof serves state from less than 127 blocks behind the tip, which is seconds of chain time. To find how much time a block range covers, compare the timestamp fields of its first and last blocks instead of multiplying by a fixed block time. Paginate log backfills by block range. See EVM range limits and EVM eth_getProof history limits.
Last modified on November 10, 2026