Deploy Your First Smart Contract on Nexis This comprehensive tutorial walks you through deploying a smart contract on Nexis Appchain from start to finish. You’ll learn how to set up your development environment, write a contract, deploy it to the testnet, and verify it on the block explorer. 
Prerequisites Before starting this tutorial, ensure you have: 
Testnet NZT Get tokens from the faucet  
Code Editor VS Code, Sublime, or your preferred editor 
Important:  Never share your private keys or commit them to version control. Always use environment variables for sensitive data.
Part 1: Network Setup First, configure your wallet to connect to Nexis Appchain Testnet. 
 Manual Configuration
 Programmatic Addition
Open MetaMask and navigate to Settings → Networks → Add Network . Enter these parameters: Field Value Network Name Nexis Appchain Testnet RPC URL https://rpc.testnet.nexis.networkChain ID 84532Currency Symbol NZT Block Explorer https://explorer.testnet.nexis.network
Click “Save” to add the network. Step 2: Verify Network Connection Test your RPC connection: 
# Check if RPC is responding curl  https://rpc.testnet.nexis.network  \   -X  POST  \   -H  "Content-Type: application/json"  \   -d  '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' # Expected output: # {"jsonrpc":"2.0","id":1,"result":"0x1a2b3c"} Success!  If you see a hex result, your RPC connection is working correctly.
Part 2: Project Setup with Hardhat Step 1: Initialize a New Project Create a new directory and initialize your project: 
# Create project directory mkdir  nexis-contract-demo cd  nexis-contract-demo # Initialize npm project npm  init  -y # Install Hardhat and dependencies npm  install  --save-dev  hardhat  @nomicfoundation/hardhat-toolbox npm  install  @openzeppelin/contracts  dotenv Step 2: Initialize Hardhat Run the Hardhat initialization wizard: 
Select these options: 
What do you want to do?  → Create a JavaScript projectHardhat project root  → Press Enter (use current directory)Add a .gitignore?  → YesInstall dependencies?  → Yes 
Hardhat will create a basic project structure with sample contracts, tests, and scripts. 
Edit hardhat.config.js to add Nexis network configuration: 
require ( "@nomicfoundation/hardhat-toolbox" ); require ( "dotenv" ). config (); /**  @type  import('hardhat/config').HardhatUserConfig */ module . exports  =  {   solidity:  {     version:  "0.8.20" ,     settings:  {       optimizer:  {         enabled:  true ,         runs:  200       }     }   },   networks:  {     // Nexis Testnet     nexis:  {       url:  process . env . NEXIS_RPC_URL  ||  "https://rpc.testnet.nexis.network" ,       chainId:  84532 ,       accounts:  process . env . PRIVATE_KEY  ?  [ process . env . PRIVATE_KEY ]  :  [],       gasPrice:  1000000000 ,  // 1 gwei     },     // For local testing     localhost:  {       url:  "http://127.0.0.1:8545"     }   },   etherscan:  {     apiKey:  {       nexis:  "no-api-key-needed"  // Nexis doesn't require API key for verification     },     customChains:  [       {         network:  "nexis" ,         chainId:  84532 ,         urls:  {           apiURL:  "https://explorer.testnet.nexis.network/api" ,           browserURL:  "https://explorer.testnet.nexis.network"         }       }     ]   },   paths:  {     sources:  "./contracts" ,     tests:  "./test" ,     cache:  "./cache" ,     artifacts:  "./artifacts"   } }; Step 4: Create Environment Variables Create a .env file in your project root: 
# Your MetaMask private key (keep this secret!) PRIVATE_KEY = your_private_key_here # RPC URL (optional, uses default if not set) NEXIS_RPC_URL = https://rpc.testnet.nexis.network Security Best Practice:  Add .env to your .gitignore file to prevent committing secrets:echo  ".env"  >>  .gitignore Step 5: Get Your Private Key To export your private key from MetaMask: 
Open MetaMask 
Click the three dots menu 
Select Account details  
Click Show private key  
Enter your MetaMask password 
Copy the private key and paste it in your .env file 
 
Part 3: Write Your Smart Contract Step 1: Create the Contract File Create a new file contracts/AITaskRequester.sol: 
contracts/AITaskRequester.sol
// SPDX-License-Identifier: MIT pragma  solidity  ^0.8.20 ; import  "@openzeppelin/contracts/access/Ownable.sol" ; import  "@openzeppelin/contracts/security/ReentrancyGuard.sol" ; /**  *  @title  AITaskRequester  *  @dev  A contract that creates AI inference tasks on Nexis Appchain  */ contract  AITaskRequester  is  Ownable ,  ReentrancyGuard  {     // Interface for Nexis Tasks contract     interface  ITasks  {         function  createTask (             string  calldata  description ,             uint256  reward ,             uint256  deadline ,             bytes  calldata  requirements         )  external  payable  returns  ( uint256  taskId );         function  getTaskStatus ( uint256  taskId )             external             view             returns  ( uint8  status ,  address  agent ,  bytes32  resultHash );     }     // Events     event  TaskCreated (         uint256  indexed  taskId ,         address  indexed  requester ,         string  description ,         uint256  reward ,         uint256  deadline     );     event  TaskCompleted (         uint256  indexed  taskId ,         address  indexed  agent ,         bytes32  resultHash     );     // State variables     ITasks  public  immutable  tasksContract;     mapping ( uint256  =>  address )  public  taskRequesters;     mapping ( address  =>  uint256 [])  public  userTasks;     uint256  public  totalTasksCreated;     /**      *  @dev  Constructor sets the Tasks contract address      *  @param  _tasksContract  Address of the Nexis Tasks.sol contract      */     constructor ( address  _tasksContract ) {         require (_tasksContract  !=  address ( 0 ),  "Invalid tasks contract" );         tasksContract  =  ITasks (_tasksContract);     }     /**      *  @dev  Request an AI inference by creating a task      *  @param  prompt  The input prompt for the AI      *  @param  reward  Amount to reward the agent (in wei)      *  @param  duration  How long until task deadline (in seconds)      *  @param  modelRequirements  Encoded requirements (model, parameters, etc.)      *  @return  taskId  The ID of the created task      */     function  requestInference (         string  calldata  prompt ,         uint256  reward ,         uint256  duration ,         bytes  calldata  modelRequirements     )  external  payable  nonReentrant  returns  ( uint256 ) {         require ( bytes (prompt).length  >  0 ,  "Empty prompt" );         require ( bytes (prompt).length  <=  5000 ,  "Prompt too long" );         require (reward  >  0 ,  "Zero reward" );         require ( msg .value  >=  reward,  "Insufficient payment" );         require (duration  >=  300  &&  duration  <=  86400 ,  "Invalid duration" );         // Calculate deadline         uint256  deadline  =  block .timestamp  +  duration;         // Create task on Nexis         uint256  taskId  =  tasksContract.createTask{value :  reward}(             prompt,             reward,             deadline,             modelRequirements         );         // Track the task         taskRequesters[taskId]  =  msg.sender ;         userTasks[ msg.sender ]. push (taskId);         totalTasksCreated ++ ;         emit  TaskCreated (taskId,  msg.sender , prompt, reward, deadline);         // Refund excess payment         if  ( msg .value  >  reward) {             payable ( msg.sender ). transfer ( msg .value  -  reward);         }         return  taskId;     }     /**      *  @dev  Get tasks created by a user      *  @param  user  Address of the user      *  @return  Array  of task IDs      */     function  getUserTasks ( address  user )  external  view  returns  ( uint256 []  memory ) {         return  userTasks[user];     }     /**      *  @dev  Check if a task is complete      *  @param  taskId  The task ID to check      *  @return  completed  True if task is completed      *  @return  agent  Address of agent who completed it      *  @return  resultHash  Hash of the result      */     function  checkTaskStatus ( uint256  taskId )         external         view         returns  ( bool  completed ,  address  agent ,  bytes32  resultHash )     {         ( uint8  status,  address  taskAgent,  bytes32  hash )  =  tasksContract. getTaskStatus (taskId);         // Status: 0=Open, 1=Claimed, 2=Completed, 3=Disputed, 4=Resolved         completed  =  (status  ==  2  ||  status  ==  4 );         agent  =  taskAgent;         resultHash  =  hash ;     }     /**      *  @dev  Emergency withdraw function (only owner)      */     function  emergencyWithdraw ()  external  onlyOwner  {         payable ( owner ()). transfer ( address ( this ).balance);     }     /**      *  @dev  Allow contract to receive ETH      */     receive ()  external  payable  {} } This contract demonstrates best practices: 
Uses OpenZeppelin’s secure contracts 
Implements proper access control 
Includes reentrancy protection 
Has comprehensive error handling 
Emits events for tracking 
Includes detailed NatSpec documentation 
 Step 2: Compile the Contract Compile your contract to check for errors: 
Expected output: Compiled 1 Solidity file successfully If you see compilation errors, check: 
Solidity version matches your config 
All imports are correctly installed 
No syntax errors in the code 
 
Part 4: Deploy to Nexis Testnet Step 1: Create Deployment Script Create scripts/deploy.js: 
const  hre  =  require ( "hardhat" ); async  function  main () {   console . log ( "Deploying AITaskRequester to Nexis Appchain..." );   // Address of Tasks.sol on Nexis Testnet   const  TASKS_CONTRACT  =  "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" ;   // Get the deployer account   const  [ deployer ]  =  await  hre . ethers . getSigners ();   const  balance  =  await  hre . ethers . provider . getBalance ( deployer . address );   console . log ( "Deploying with account:" ,  deployer . address );   console . log ( "Account balance:" ,  hre . ethers . formatEther ( balance ),  "NZT" );   // Check if we have enough balance   if  ( balance  <  hre . ethers . parseEther ( "0.01" )) {     throw  new  Error ( "Insufficient balance. Get testnet NZT from the faucet." );   }   // Deploy the contract   const  AITaskRequester  =  await  hre . ethers . getContractFactory ( "AITaskRequester" );   const  contract  =  await  AITaskRequester . deploy ( TASKS_CONTRACT );   await  contract . waitForDeployment ();   const  contractAddress  =  await  contract . getAddress ();   console . log ( "✅ AITaskRequester deployed to:" ,  contractAddress );   // Wait for a few blocks before verification   console . log ( "Waiting for 5 block confirmations..." );   await  contract . deploymentTransaction (). wait ( 5 );   console . log ( " \n Deployment Summary:" );   console . log ( "===================" );   console . log ( "Contract Address:" ,  contractAddress );   console . log ( "Deployer:" ,  deployer . address );   console . log ( "Tasks Contract:" ,  TASKS_CONTRACT );   console . log ( "Network:" ,  hre . network . name );   console . log ( "Chain ID:" , ( await  hre . ethers . provider . getNetwork ()). chainId . toString ());   console . log ( " \n 📝 To verify on explorer, run:" );   console . log ( `npx hardhat verify --network nexis  ${ contractAddress }  ${ TASKS_CONTRACT } ` );   console . log ( " \n 🔗 View on explorer:" );   console . log ( `https://explorer.testnet.nexis.network/address/ ${ contractAddress } ` ); } main ()   . then (()  =>  process . exit ( 0 ))   . catch (( error )  =>  {     console . error ( "❌ Deployment failed:" ,  error );     process . exit ( 1 );   }); Step 2: Deploy the Contract Run the deployment script: 
npx  hardhat  run  scripts/deploy.js  --network  nexis Deployment typically takes 5-15 seconds  on Nexis due to 2-second block times.
Expected output: Deploying AITaskRequester to Nexis Appchain... Deploying with account: 0x1234...5678 Account balance: 10.5 NZT ✅ AITaskRequester deployed to: 0xAbC1...23dE Waiting for 5 block confirmations... Deployment Summary: =================== Contract Address: 0xAbC1...23dE Deployer: 0x1234...5678 Tasks Contract: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb Network: nexis Chain ID: 84532 Congratulations!  Your contract is now deployed on Nexis Appchain.
Step 3: Verify the Contract Verify your contract on the block explorer: 
npx  hardhat  verify  --network  nexis  DEPLOYED_ADDRESS  "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" Replace DEPLOYED_ADDRESS with your actual contract address. 
Expected output: Successfully verified contract AITaskRequester on Nexis Explorer. https://explorer.testnet.nexis.network/address/0xAbC1...23dE#code Part 5: Deploy with Foundry (Alternative) If you prefer Foundry over Hardhat, follow these steps: 
Step 1: Install Foundry # Install Foundry curl  -L  https://foundry.paradigm.xyz  |  bash # Update to latest version foundryup Step 2: Create Foundry Project # Initialize project forge  init  nexis-foundry-demo cd  nexis-foundry-demo # Install dependencies forge  install  OpenZeppelin/openzeppelin-contracts Edit foundry.toml: 
[ profile . default ] src  =  "src" out  =  "out" libs  = [ "lib" ] solc_version  =  "0.8.20" optimizer  =  true optimizer_runs  =  200 [ rpc_endpoints ] nexis  =  "https://rpc.testnet.nexis.network" [ etherscan ] nexis  = {  key  =  "no-api-key-needed" ,  url  =  "https://explorer.testnet.nexis.network/api"  } Step 4: Create Contract Move your contract to src/AITaskRequester.sol (use the same code as above). 
Step 5: Deploy with Forge # Set your private key export  PRIVATE_KEY = your_private_key_here # Deploy forge  create  src/AITaskRequester.sol:AITaskRequester  \   --rpc-url  nexis  \   --private-key  $PRIVATE_KEY  \   --constructor-args  0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb  \   --verify # Or use a script for more control forge  script  script/Deploy.s.sol:DeployScript  \   --rpc-url  nexis  \   --private-key  $PRIVATE_KEY  \   --broadcast  \   --verify Part 6: Testing Your Deployment Step 1: Interact via Hardhat Console Test your deployed contract: 
npx  hardhat  console  --network  nexis In the console: 
// Get contract instance const  AITaskRequester  =  await  ethers . getContractFactory ( "AITaskRequester" ); const  contract  =  await  AITaskRequester . attach ( "YOUR_CONTRACT_ADDRESS" ); // Check tasks contract address const  tasksAddress  =  await  contract . tasksContract (); console . log ( "Tasks contract:" ,  tasksAddress ); // Create a test task const  tx  =  await  contract . requestInference (   "Explain quantum computing in simple terms" ,   ethers . parseEther ( "0.1" ),  // 0.1 NZT reward   3600 ,  // 1 hour deadline   ethers . AbiCoder . defaultAbiCoder (). encode (     [ 'string' ,  'uint256' ],     [ 'gpt-4' ,  1000 ]  // model and max tokens   ),   {  value:  ethers . parseEther ( "0.1" ) } ); await  tx . wait (); console . log ( "Task created! Tx:" ,  tx . hash ); Step 2: View on Block Explorer Visit the explorer to see your contract: 
https://explorer.testnet.nexis.network/address/YOUR_CONTRACT_ADDRESS You should see: 
Contract code (if verified) 
Recent transactions 
Events emitted 
Current balance 
 
Troubleshooting Common Issues 
Error: Insufficient funds
Problem:  Your account doesn’t have enough NZT for gas fees.Solution: 
Visit the faucet  
Request testnet NZT 
Wait for transaction to confirm 
Check balance: await ethers.provider.getBalance(YOUR_ADDRESS) 
 
Problem:  Your local nonce is out of sync with the network.Solution: # Reset Hardhat cache rm  -rf  cache  artifacts # Or specify nonce manually await  contract.deploy ({   nonce:  await  ethers.provider.getTransactionCount ( deployer.address ) }) 
Error: Contract verification failed
Problem:  Verification on explorer is failing.Solution: 
Wait 1-2 minutes after deployment 
Make sure constructor arguments are correct 
Check Solidity version matches (0.8.20) 
Try manual verification on explorer UI 
 
Error: Invalid JSON RPC response
Problem:  Cannot connect to Nexis RPC.Solution: # Test RPC connectivity curl  https://rpc.testnet.nexis.network  \   -X  POST  \   -H  "Content-Type: application/json"  \   -d  '{"jsonrpc":"2.0","method":"net_version","params":[],"id":1}' # Try alternative RPC if main is down url:  "https://rpc-backup.testnet.nexis.network" 
Problem:  Transaction gas estimation is failing.Solution: // Specify gas limit manually await  contract . deploy ({   gasLimit:  5000000 }); // Or increase gas price await  contract . deploy ({   gasPrice:  ethers . parseUnits ( "2" ,  "gwei" ) }); Best Practices Checklist 
Security
Never commit private keys to git 
Use environment variables for secrets 
Add .env to .gitignore 
Test on testnet before mainnet 
Get contracts audited for production 
 
Gas Optimization
Enable Solidity optimizer 
Use immutable for constants set in constructor 
Batch operations when possible 
Emit events instead of storing strings 
Use calldata instead of memory for external function parameters 
 
Testing
Write comprehensive unit tests 
Test edge cases and error conditions 
Use Hardhat’s local network for rapid testing 
Test with actual testnet before production 
Monitor gas usage in tests 
 
Documentation
Add NatSpec comments to all functions 
Document constructor parameters 
Explain complex logic 
Keep README up to date 
Document deployment process 
 Next Steps Additional Resources Pro Tip:  Save your deployment addresses in a deployments.json file to track contracts across networks. This makes it easier to interact with them later.