Quickstart your first contract on Lumia
Who this is for: developers who already know Solidity and Hardhat, and want the shortest correct path from an empty folder to a verified contract on Lumia. If you've never used Hardhat before, this still works: every command is given in full.
What you'll have at the end: a deployed, verified Hardhat contract live on Lumia Beam testnet, plus a script that reads and updates it.
Time: under 10 minutes once your wallet has testnet funds.
Prerequisites
Node.js 18+ and npm (or pnpm/yarn) installed.
A wallet (MetaMask or similar) with a private key you control.
Basic familiarity with the command line.
Testnet only. Never use a mainnet key for this walkthrough.
What you'll do
Add Lumia Beam testnet to your wallet.
Get testnet funds.
Scaffold a Hardhat project.
Configure the network.
Write and deploy a contract.
Verify it on the explorer.
Interact with it.
Add Lumia Beam testnet to your wallet
Follow Add Lumia to MetaMask or Add Lumia to FoxWallet. Both pull the network fields from /reference/networks, so you're always adding the current values rather than ones copied out of an old tutorial.
Verify: confirm the chain ID your wallet shows is 2030232745: that's Beam, the live testnet.
Get testnet funds
Claim Beam testnet tokens from the faucet listed at /reference/faucet, which carries the current URL, claim amount, and cooldown. Use the same address you added Beam to in step 1.
Verify: your wallet's Beam testnet balance increases once the claim lands. See Block explorers if you want to confirm the incoming transaction on-chain first.
Scaffold a Hardhat project
mkdir lumia-quickstart && cd lumia-quickstart
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox dotenv
npx hardhat init
# choose: "Create a JavaScript project"This installs Hardhat 2.x with the standard toolbox (ethers v6, chai matchers, gas reporter).
Verify: the command finishes without error and hardhat.config.js exists in your project folder; you'll edit it directly in the next step.
Configure the network
Open /reference/networks and copy the Beam testnet RPC (HTTPS) value into a .env file (never commit this file):
LUMIA_BEAM_RPC_URL=<paste the Beam RPC URL from /reference/networks>
PRIVATE_KEY=<YOUR_TESTNET_ONLY_PRIVATE_KEY>Edit hardhat.config.js:
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.24",
networks: {
lumiaBeam: {
url: process.env.LUMIA_BEAM_RPC_URL, // from /reference/networks; do not hardcode this value
chainId: 2030232745,
accounts: [process.env.PRIVATE_KEY],
},
},
};Deliberately no hardcoded RPC fallback here: if LUMIA_BEAM_RPC_URL is unset, Hardhat should fail loudly rather than silently pointing at a stale or guessed URL.
Write and deploy a contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Greeter {
string private greeting;
address public owner;
event GreetingChanged(string newGreeting, address changedBy);
constructor(string memory _greeting) {
greeting = _greeting;
owner = msg.sender;
}
function greet() external view returns (string memory) {
return greeting;
}
function setGreeting(string calldata _greeting) external {
greeting = _greeting;
emit GreetingChanged(_greeting, msg.sender);
}
}npx hardhat compileconst hre = require("hardhat");
async function main() {
const Greeter = await hre.ethers.getContractFactory("Greeter");
const greeter = await Greeter.deploy("Hello, Lumia");
await greeter.waitForDeployment();
console.log("Greeter deployed to:", await greeter.getAddress());
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});npx hardhat run scripts/deploy.js --network lumiaBeamCopy the printed contract address. You'll need it for the next two steps.
Verify: the terminal prints Greeter deployed to: <address> from the script's final console.log call.
Verify it on the explorer
See Verify a contract with Hardhat for the current verifier plugin configuration for Beam.
npx hardhat verify --network lumiaBeam <DEPLOYED_CONTRACT_ADDRESS> "Hello, Lumia"Verify it worked: open the Beam explorer (linked from /reference/explorers) and search for <DEPLOYED_CONTRACT_ADDRESS>. You should see a confirmed contract-creation transaction and, once this step succeeds, a verified "Contract" tab showing your source code.
Interact with it
// scripts/interact.js
const hre = require("hardhat");
async function main() {
const address = "<DEPLOYED_CONTRACT_ADDRESS>";
const greeter = await hre.ethers.getContractAt("Greeter", address);
console.log("Current greeting:", await greeter.greet());
const tx = await greeter.setGreeting("Hello from the quickstart");
await tx.wait();
console.log("Updated greeting:", await greeter.greet());
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});npx hardhat run scripts/interact.js --network lumiaBeamVerify: the terminal prints Current greeting: Hello, Lumia, then, after the update transaction confirms, Updated greeting: Hello from the quickstart.
Troubleshooting
You're done
You've added Beam testnet to a wallet, funded it, and deployed, verified, and called a contract on Lumia. From here:
Building something that represents a real-world asset? Read
/tokenize/overviewfirst: the lifecycle model changes how you should structure contracts.Gating access with credentials? See
/build/identity/on-chain-kyc-integration.Running your own infrastructure instead of relying on public RPC? See
/run-a-node/rpc-node/overview.
Last updated
Was this helpful?