Lux Docs
Build

Smart Contracts

Deploy and develop Solidity smart contracts on Lux C-Chain

Smart Contracts

Lux C-Chain is fully EVM-compatible, meaning you can write, test, and deploy Solidity smart contracts using the same tools you already know from Ethereum development.

Network Configuration

Add Lux to your development environment:

Network Name: Lux Mainnet C-Chain
RPC URL:      https://api.lux.network/ext/bc/C/rpc
Chain ID:     96369
Symbol:       LUX
Explorer:     https://explorer.lux.network

Development with Hardhat

Initialize a Hardhat Project

mkdir my-lux-contract && cd my-lux-contract
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
npx hardhat init

Configure Lux Networks

Update hardhat.config.js:

require("@nomicfoundation/hardhat-toolbox");

module.exports = {
  solidity: "0.8.24",
  networks: {
    lux: {
      url: "https://api.lux.network/ext/bc/C/rpc",
      chainId: 96369,
      accounts: [process.env.PRIVATE_KEY],
    },
    luxTestnet: {
      url: "https://api.testnet.lux.network/ext/bc/C/rpc",
      chainId: 96368,
      accounts: [process.env.PRIVATE_KEY],
    },
  },
};

Write a Contract

Create contracts/MyToken.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
    constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
        _mint(msg.sender, initialSupply);
    }
}

Deploy

npx hardhat run scripts/deploy.js --network luxTestnet

Development with Foundry

Foundry provides faster compilation and testing with Forge.

Install Foundry

curl -L https://foundry.paradigm.xyz | bash
foundryup

Create a Project

forge init my-lux-contract
cd my-lux-contract

Write and Test

Create src/Counter.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract Counter {
    uint256 public number;

    function setNumber(uint256 newNumber) public {
        number = newNumber;
    }

    function increment() public {
        number++;
    }
}

Create test/Counter.t.sol:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "forge-std/Test.sol";
import "../src/Counter.sol";

contract CounterTest is Test {
    Counter public counter;

    function setUp() public {
        counter = new Counter();
        counter.setNumber(0);
    }

    function test_Increment() public {
        counter.increment();
        assertEq(counter.number(), 1);
    }

    function testFuzz_SetNumber(uint256 x) public {
        counter.setNumber(x);
        assertEq(counter.number(), x);
    }
}

Run tests:

forge test -vvv

Deploy with Forge

forge create --rpc-url https://api.testnet.lux.network/ext/bc/C/rpc \
  --private-key $PRIVATE_KEY \
  src/Counter.sol:Counter

Contract Verification

Verify your contracts on the Lux Explorer for transparency and user trust:

# Hardhat
npx hardhat verify --network luxTestnet <CONTRACT_ADDRESS> <CONSTRUCTOR_ARGS>

# Foundry
forge verify-contract <CONTRACT_ADDRESS> src/Counter.sol:Counter \
  --chain-id 96368 \
  --verifier-url https://explorer.testnet.lux.network/api

Available Precompiles

Lux C-Chain includes precompiled contracts for common operations:

AddressPrecompileDescription
0x0100...0001NativeMinterMint native LUX tokens (admin only)
0x0100...0002ContractDeployerRestrict who can deploy contracts
0x0100...0003TxAllowListRestrict who can submit transactions
0x0100...0004FeeManagerConfigure dynamic fee parameters
0x0100...0005RewardManagerConfigure block reward recipients

Precompile access is governed by admin roles configured at the subnet level. On the Primary Network C-Chain, most precompiles are restricted to governance operations.

Gas Optimization Tips

Lux C-Chain uses a dynamic fee model similar to EIP-1559. Optimize gas costs with these practices:

  • Use calldata instead of memory for read-only function parameters
  • Pack storage variables to minimize storage slots (e.g., multiple uint128 in one slot)
  • Use immutable and constant for values that do not change after deployment
  • Batch operations to amortize base transaction costs
  • Avoid redundant storage reads by caching in local variables
// Gas-inefficient
function bad(uint256[] memory data) public {
    for (uint i = 0; i < data.length; i++) {
        total += data[i]; // reads storage `total` each iteration
    }
}

// Gas-efficient
function good(uint256[] calldata data) public {
    uint256 _total = total; // cache storage read
    for (uint i = 0; i < data.length; i++) {
        _total += data[i];
    }
    total = _total; // single storage write
}

Further Reading

  • Tutorials - Step-by-step contract deployment guides
  • JSON-RPC API - Interact with deployed contracts via RPC
  • SDKs - Call contracts from JavaScript, Go, or Rust

On this page