In this guide, you’ll learn how to deploy your first smart contract on the Nexus Layer 1. We’ll walk you through creating a Timelock Wallet - a simple but powerful contract that demonstrates fundamental blockchain concepts.
What you’ll accomplish:
Set up a complete development environment using Hardhat
Configure your wallet and obtain test NEX tokens
Write, compile, and deploy a timelock smart contract
Verify your contract on the Nexus blockchain
Interact with your deployed contract through scripts
What is a Timelock Wallet?
A timelock wallet is a smart contract that holds funds and only allows withdrawal after a specified time period. Think of it as a digital safe with a timer - once you lock your funds, they can only be accessed by the owner after the unlock time expires. This is useful for:
Creating savings accounts with built-in discipline
Setting up vesting schedules for tokens
Building escrow mechanisms for time-sensitive agreements
By the end of this tutorial, you’ll have a working timelock wallet deployed on Nexus and understand the fundamentals of smart contract development.
A smart contract is a program stored on a blockchain that automatically executes predefined actions when certain conditions are fulfilled. Unlike traditional contracts, which rely on people or institutions to enforce them, a smart contract is self-enforcing — once it’s deployed, it runs exactly as programmed without human intervention.
Think of it as:
“If this happens, then do that” — enforced by code and trustless infrastructure.
Smart contracts are important because they eliminate the need for intermediaries, reduce the risk of fraud, and ensure agreements are executed exactly as written — with transparency and automation. This makes them a foundational building block for decentralized applications (dApps), enabling trustless interactions in finance, governance, identity, and beyond.
Let’s break down a simple smart contract to understand its parts:
Copy
Ask AI
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract SimpleStorage { // State Variables uint256 private storedData; // Events event DataStored(uint256 newValue); // Constructor constructor() { storedData = 0; } // Functions function set(uint256 x) public { storedData = x; emit DataStored(x); } function get() public view returns (uint256) { return storedData; }}
Examining each component:
License and Version
// SPDX-License-Identifier: MIT: Specifies the license
pragma solidity ^0.8.0: Specifies the Solidity version
State Variables
Variables that are permanently stored in contract storage
Example: uint256 private storedData
Can be marked as public, private, or internal
Events
Used to log important actions on the blockchain
Example: event DataStored(uint256 newValue)
Help frontend applications track contract state changes
Constructor
Runs once when the contract is deployed
Used for initial setup
Example: constructor() { storedData = 0; }
Functions
public: Can be called by anyone
Copy
Ask AI
contract PublicFunctionExample { // Public function - can be called by anyone function publicFunction() public { // This function can be called by: // 1. Other contracts // 2. External accounts // 3. The contract itself } // Public state variable - automatically creates a getter function uint256 public number; // Internal function - can only be called within the contract function internalFunction() internal { // This can only be called by other functions in this contract }}
Public functions:
Can be called by anyone (external accounts, other contracts)
Can be called by the contract itself
Are part of the contract’s external interface
Generate more bytecode than internal functions
Are more gas-expensive than internal functions
Common use cases:
External contract interactions
User-facing functions
Functions that need to be called by other contracts
Functions that implement external interfaces
private: Can only be called within the contract
Copy
Ask AI
contract PrivateFunctionExample { // Private function - can only be called within this contract function privateFunction() private { // This function can only be called by other functions // in this specific contract } // Internal function - can be called by this contract and derived contracts function internalFunction() internal { // This can be called by this contract and any contracts // that inherit from this contract } function publicFunction() public { // Can call private functions privateFunction(); }}
Private functions:
Can only be called within the same contract
Cannot be called by derived contracts
Are more restrictive than internal functions
Are gas-efficient for internal operations
Help with code organization and security
Common use cases:
Internal helper functions
Security-sensitive operations
Functions that should never be exposed externally
Code that should not be inherited
view: Doesn't modify state
Copy
Ask AI
contract ViewFunctionExample { uint256 public number; // View function - reads state but doesn't modify it function getNumber() public view returns (uint256) { return number; // Reads state but doesn't modify it } // Not view - modifies state function setNumber(uint256 newNumber) public { number = newNumber; // Modifies state } // View function can call other view functions function getNumberPlusOne() public view returns (uint256) { return getNumber() + 1; }}
View functions:
Can read contract state
Cannot modify contract state
Are gas-efficient for read operations
Can be called without a transaction
Can call other view functions
Can call pure functions
Common use cases:
Reading contract state
Computing values based on state
Data validation that requires state
Getter functions
Status checks
pure: Doesn't read or modify state
Copy
Ask AI
contract PureFunctionExample { // Pure function - only performs computation function add(uint256 a, uint256 b) public pure returns (uint256) { return a + b; } // Not pure - reads state variable uint256 public number; function addToNumber(uint256 a) public view returns (uint256) { return a + number; // Reads state, so it's view, not pure } // Not pure - modifies state function setNumber(uint256 newNumber) public { number = newNumber; // Modifies state, so it's not pure or view }}
Pure functions:
Only perform computations
Don’t read from blockchain state
Don’t modify blockchain state
Are gas-efficient for read operations
Can be called without a transaction
Are deterministic (same input always produces same output)
# Install Node.js and npm if not already installed# Then install Hardhatnpm install --save-dev hardhat
Hardhat is a development environment and task runner for Ethereum that helps developers compile, deploy, test, and debug smart contracts. The —save-dev flag ensures Hardhat is installed as a development-only dependency, keeping it separate from production dependencies.
# Create a new directorymkdir my-first-contractcd my-first-contract# Initialize a Node.js project with package.jsonnpm init -y# Initialize a new Hardhat projectnpx hardhat
Within your project directory, create/update your config file hardhat.config.js which will define the network configuration, RPC endpoint for Hardhat to connect to, and chainID for signature verification:
5. Receive test NEX from a faucet for contract deployment
To deploy your contract on Nexus Layer 1, you’ll need NEX tokens to pay for gas fees. Gas fees are the cost of executing transactions on the blockchain, similar to how you need fuel to drive a car.
There are two ways to receive NEX for testing:
Earn NEX through Proving
Submit proofs to earn points and NEX in real-time
This is the recommended way as it helps secure the network
For detailed instructions on proving, visit our Proving Guide
Use the Nexus Faucet
A faucet is a service that provides small amounts of cryptocurrency for testing.
It’s like a water faucet, but instead of water, it dispenses test tokens
Note: The amount of NEX you receive from the faucet is sufficient for deploying and testing basic contracts. For more extensive testing, consider earning NEX through proving.
This contract is the default Solidity example included when you scaffold a new Hardhat project. It demonstrates core Ethereum concepts like sending and holding ETH, working with block.timestamp, using events, and enforcing access control with msg.sender.
The contract implements a simple timelock wallet. When deployed, it requires:
A future unlockTime (timestamp),
And an ETH payment (payable constructor).
The contract locks the ETH until the specified unlock time. After that time has passed, only the deploying address (the owner) can withdraw the funds. The withdraw() function will revert if called too early or by anyone other than the owner.
This type of contract is useful for:
Time-based escrow
Delayed disbursements or vesting
Testing ETH flow logic with time-based constraints
Copy
Ask AI
contract Lock { uint public unlockTime; address payable public owner; event Withdrawal(uint amount, uint when); constructor(uint _unlockTime) payable { require( block.timestamp < _unlockTime, "Unlock time should be in the future" ); unlockTime = _unlockTime; owner = payable(msg.sender); } function withdraw() public { // Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal // console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp); require(block.timestamp >= unlockTime, "You can't withdraw yet"); require(msg.sender == owner, "You aren't the owner"); emit Withdrawal(address(this).balance, block.timestamp); owner.transfer(address(this).balance); }}
A deployment script is a programmatic way to deploy your smart contracts to a blockchain using Hardhat. Instead of manually interacting with the network through a UI or console, deployment scripts allow you to:
Automate contract deployment
Set constructor arguments dynamically
Log or save deployed addresses
Chain deployments in a predictable order
Integrate easily into testing, development, or CI/CD pipelines
Here we create a new folder entitled scripts and create a file entitled deploy.js, which will deploy our code to the Layer 1:
Copy
Ask AI
const hre = require("hardhat");async function main() { console.log("Deploying Lock contract..."); // Get the contract factory const Lock = await hre.ethers.getContractFactory("Lock"); // Deploy the contract // The constructor requires a timestamp for the unlock time const unlockTime = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 365; // 1 year from now const lock = await Lock.deploy(unlockTime); // Wait for deployment to finish await lock.waitForDeployment(); const lockAddress = await lock.getAddress(); console.log(`Lock contract deployed to: ${lockAddress}`); // Wait for a few block confirmations before verifying console.log("Waiting for block confirmations..."); await new Promise(resolve => setTimeout(resolve, 30000)); // Wait 30 seconds // Verify the contract console.log("Verifying contract..."); try { await hre.run("verify:verify", { address: lockAddress, constructorArguments: [unlockTime], }); console.log("Contract verified successfully"); } catch (error) { if (error.message.includes("Already Verified")) { console.log("Contract is already verified!"); } else { console.error("Error verifying contract:", error); } }}// We recommend this pattern to be able to use async/await everywhere// and properly handle errors.main().catch((error) => { console.error(error); process.exitCode = 1;});
This script demonstrates a complete, real-world deployment pattern:
It handles constructor parameters (unlockTime)
Manages asynchronous deployment logic with await
Provides helpful logs to track progress
Prepares for contract verification (though it may be disabled or optional in some cases)
Run the following command to deploy your contract to the Nexus network:
Copy
Ask AI
npx hardhat run scripts/deploy.js --network nexus
You should see the following output in your terminal:
Copy
Ask AI
Deploying Lock contract...Lock contract deployed to: 0x... # Your contract's address will appear here
This means your contract has been successfully deployed to the Nexus network. Save the contract address - you’ll need it to interact with your contract later.
Try deploying more complex contracts (see additional guides)
Build a full-stack dApp
Remember: Smart contract development is a journey. Start simple, test thoroughly, and gradually build up to more complex applications. The Nexus community is here to support you every step of the way.
Assistant
Responses are generated using AI and may contain mistakes.