8.1 Unit Testing with Hardhat or Truffle
Unit Testing is the process of testing individual parts (units) of your smart contract code to make sure they work as expected. It's very important to catch bugs early, especially when dealing with blockchain where mistakes can cost real money.
Why Unit Testing Matters
- Ensures your smart contract works as expected.
- Catches bugs before deploying to mainnet.
- Makes future code changes safer and easier.
- Helps build trust in your decentralized application (DApp).
Tools Used
- Hardhat – A powerful Ethereum development environment.
- Truffle – Another popular Ethereum development framework.
- Chai/Mocha – JavaScript libraries used for writing and running tests.
Sample Unit Test with Hardhat
Let’s say we have a simple smart contract with a function to set and get a number:
// contracts/SimpleStorage.sol
pragma solidity ^0.8.0;
contract SimpleStorage {
uint public number;
function setNumber(uint _num) public {
number = _num;
}
}
Now we write a test in JavaScript:
// test/SimpleStorage.js
const { expect } = require("chai");
describe("SimpleStorage", function () {
it("Should set and get the correct number", async function () {
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
const storage = await SimpleStorage.deploy();
await storage.setNumber(42);
expect(await storage.number()).to.equal(42);
});
});
Running the Test
npx hardhat test
Sample Unit Test with Truffle
If you're using Truffle, your test might look like this:
// test/SimpleStorage.test.js
const SimpleStorage = artifacts.require("SimpleStorage");
contract("SimpleStorage", accounts => {
it("Should store the value 42", async () => {
const instance = await SimpleStorage.deployed();
await instance.setNumber(42);
const result = await instance.number();
assert.equal(result.toNumber(), 42);
});
});
Best Practices
- Test all functions and edge cases.
- Use descriptive names for your tests.
- Reset contract state before each test.
- Test for failure conditions (e.g., reverts).
Conclusion
Unit testing is crucial in smart contract development. Tools like Hardhat and Truffle make it easy to test your code in a local environment before deploying it live, helping you avoid costly mistakes.
8.2 Debugging Smart Contracts
Debugging smart contracts means finding and fixing errors or unexpected behavior in your Solidity code. Because smart contracts are immutable and run on the blockchain, debugging is crucial before deploying to the mainnet.
Common Issues in Smart Contracts
- Logical bugs (wrong conditions, calculations)
- Incorrect gas estimation
- Revert or require failures
- State changes not persisting
- Unexpected access control issues
Debugging Tools
- Hardhat Console.log – Debug like JavaScript using `console.log` in Solidity.
- Hardhat Network Tracing – See what happened in a transaction.
- Remix IDE Debugger – Step-by-step execution and state inspection.
- Truffle Debugger – CLI tool for tracing transactions on Truffle.
Using console.log in Hardhat
You can use `console.log` in Solidity during local testing with Hardhat:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "hardhat/console.sol";
contract DebugExample {
uint public value;
function setValue(uint _v) public {
console.log("Setting value to:", _v);
value = _v;
}
}
Using Remix Debugger
- Deploy the contract on the JavaScript VM in Remix.
- Run a function that causes a bug.
- Click the Debug button on the failed transaction.
- Inspect stack trace, storage, and variables at each step.
Using Truffle Debugger
After running a failed test, use:
truffle debug <transactionHash>
Use keyboard shortcuts to step through transactions and examine values.
Hardhat Network Tracing
- After a failed test or transaction, Hardhat shows a full error trace.
- This includes the exact line where revert occurred.
Best Practices
- Write unit tests for all functions before debugging manually.
- Use assertions and require statements with meaningful messages.
- Log variables using `console.log()` to trace values.
- Use test-driven development to catch bugs early.
Conclusion
Debugging is a key step in smart contract development. Use tools like Hardhat, Remix, and Truffle to inspect your code deeply and fix bugs before deploying to a live network.
8.3 Security Tools for Smart Contracts
Smart contracts are immutable and handle valuable assets, so it's essential to scan them for vulnerabilities. Two widely used tools are MythX and Slither.
MythX
MythX is a cloud-based smart contract security analysis platform. It performs deep static and symbolic analysis to detect bugs and vulnerabilities.
Features:
- Detects reentrancy, integer overflows, gas griefing, etc.
- Integrates with Truffle, Hardhat, and Remix.
- Provides a report with severity levels.
How to Use:
You can use mythx-cli
or plugins for Remix and Hardhat.
npm install -g mythx-cli
mythx analyze contracts/MyContract.sol
Or use via Remix by enabling the MythX plugin from the plugin manager.
Slither
Slither is an open-source static analysis tool developed by Trail of Bits. It inspects Solidity code and detects vulnerabilities without running the contract.
Features:
- Detects common bugs: uninitialized variables, reentrancy, etc.
- Provides recommendations and severity levels.
- Very fast – ideal for local development.
How to Use:
Install and run via CLI:
pip install slither-analyzer
slither contracts/MyContract.sol
Sample Output:
Slither will output potential issues like:
Reentrancy in function withdraw()
Uninitialized storage pointer
Low-level calls detected
When to Use
- Run Slither locally after each update to your smart contract.
- Use MythX for deeper scanning before deployment.
Best Practices
- Combine multiple tools to cover all vulnerability types.
- Don’t rely solely on automated tools – perform manual audits as well.
- Keep contracts simple and test thoroughly.
Conclusion
Security is non-negotiable in smart contracts. Use Slither for fast static analysis and MythX for deeper vulnerability detection. These tools help catch bugs early and make your contracts safer.
8.4 Common Exploits in Smart Contracts
Smart contracts are vulnerable to several well-known attacks. Understanding these helps developers write secure code and prevent losses.
1. Reentrancy Attack
Occurs when a contract calls an external contract (usually via .call
) before updating its state. The external contract can re-enter the original function and exploit logic errors.
Example:
function withdraw() public {
require(balances[msg.sender] > 0);
(bool sent, ) = msg.sender.call{value: balances[msg.sender]}("");
require(sent);
balances[msg.sender] = 0;
}
Fix: Update state before making external calls.
2. Integer Overflow/Underflow
In older Solidity versions, numbers would wrap around if they exceed their limit (e.g., 0 - 1 becomes max uint256).
Example:
uint8 a = 0;
a = a - 1; // becomes 255
Fix: Use Solidity ≥0.8.0 which has built-in checks, or use OpenZeppelin’s SafeMath.
3. Front Running
When a malicious actor sees a pending transaction in the mempool and submits a similar one with higher gas fees to execute it first.
Fix: Use commit-reveal schemes or design contracts to avoid relying on transaction order.
4. Access Control Issues
Functions meant for admins might be exposed due to missing or incorrect modifiers.
Example:
function kill() public {
selfdestruct(msg.sender); // No owner check!
}
Fix: Always validate the caller with modifiers like onlyOwner
.
5. Denial of Service (DoS)
When a malicious contract or user intentionally blocks certain functions from working (e.g., blocking refund loop, running out of gas).
Example:
for (uint i = 0; i < users.length; i++) {
users[i].send(refund);
}
Fix: Use pull-over-push pattern where users withdraw their funds themselves.
6. Unchecked External Calls
Using low-level .call()
without checking for success can lead to lost funds.
Fix: Always check return value of .call
, or use higher-level functions like transfer
with care.
7. Delegatecall Vulnerabilities
delegatecall
executes code in the context of the caller. If misused, it can overwrite storage.
Fix: Use strict validation and trusted libraries only.
8. Tx.origin Phishing
tx.origin
is sometimes misused for authorization, making contracts vulnerable to phishing via malicious contracts.
Fix: Use msg.sender
for auth checks instead of tx.origin
.
Best Practices
- Use the latest Solidity version (≥0.8.0).
- Follow the Checks-Effects-Interactions pattern.
- Run static analysis tools like Slither and MythX.
- Write extensive unit and integration tests.
- Conduct third-party security audits before deployment.
Conclusion
Smart contract exploits have cost users billions. Learning about common attack vectors and how to prevent them is essential for all blockchain developers.
8.5 Bug Bounty Programs and Auditing Careers
What is a Bug Bounty Program?
A Bug Bounty Program is a program where companies and blockchain projects invite ethical hackers or security researchers to find and report vulnerabilities (bugs) in their smart contracts, websites, or apps.
In return, the researchers are rewarded with money, tokens, or recognition. This helps companies fix security problems before hackers can misuse them.
Example:
- A DeFi project offers $10,000 if someone finds a bug in its smart contract.
- A researcher finds a loophole that allows double withdrawals.
- The project pays the researcher and fixes the code.
Popular Bug Bounty Platforms
- HackerOne: Works with big companies like PayPal, Google, etc.
- Immunefi: Focuses on blockchain projects like Synthetix, Polygon.
- Bugcrowd: Another platform where you can report bugs and earn rewards.
What is Smart Contract Auditing?
Smart contract auditing is the process of carefully checking code written for Ethereum or other blockchains to find bugs or security issues.
Auditors look for problems like:
- Reentrancy attacks
- Integer overflows
- Gas inefficiencies
- Unauthorized access
Why Auditing is Important:
If a smart contract has a bug, hackers can steal millions. That’s why auditing is a high-paying and respected career in the Web3 world.
How to Start a Career in Auditing?
- Learn Solidity (language for smart contracts)
- Understand Ethereum and common vulnerabilities
- Use tools like Remix, Hardhat, and Slither
- Study past hacks on rekt.news
- Practice on test projects or bug bounty programs
Average Salary
- Freelance Bounty Hunters: $500 to $50,000 per bug
- Smart Contract Auditors: $80,000 to $200,000+ per year
Conclusion
Bug bounty and auditing are exciting paths in blockchain security. You get to protect real-world projects, earn great money, and build a solid tech career.
No comments:
Post a Comment