Essential Patterns and Practices in Smart Contract Development
1.1 Overwiew
1.2 Setting Up Development Environment
Prerequisites
Node.js and npm to manage dependencies.
Truffle or Hardhat framework for compiling, testing, and deploying contracts.
Solidity (usually installed with Truffle or Hardhat) as the primary programming language for Ethereum-based smart contracts.
Ganache for local blockchain testing.
Installation of Tools
# Install Truffle or Hardhat
npm install -g truffle
# or
npm install --save-dev hardhat
Directory Structure
project-directory/
β
βββ contracts/ # Contains Solidity contract files
β βββ Token.sol # ERC-20 contract
β βββ NFT.sol # ERC-721 contract
β
βββ migrations/ # Migration scripts for deployment
β
βββ test/ # Test files for contracts
β βββ Token.test.js
β βββ NFT.test.js
β
βββ truffle-config.js # Configuration file for Truffle
βββ hardhat.config.js # Configuration file for Hardhat
1.3 ERC-20 Smart Contract for Tokens
The ERC-20 standard defines a fungible token, which means each token is identical to another token. Below is an example of a basic ERC-20 contract with Solidity.
1.3.1 ERC-20 Contract Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply * (10 ** decimals()));
}
// Optional functions for additional functionality
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
function burn(address from, uint256 amount) external {
_burn(from, amount);
}
}
1.3.2 Explanation
This contract inherits the ERC20 implementation from OpenZeppelin for secure and standard-compliant functions.
1.3.3 Deployment of ERC-20 Contract
Use Truffle or Hardhat migration scripts to deploy this contract.
Truffle Migration Script
const MyToken = artifacts.require("MyToken");
module.exports = function (deployer) {
const initialSupply = web3.utils.toWei("1000", "ether");
deployer.deploy(MyToken, initialSupply);
};
Hardhat Deployment Script
const { ethers } = require("hardhat");
async function main() {
const initialSupply = ethers.utils.parseEther("1000");
const MyToken = await ethers.getContractFactory("MyToken");
const myToken = await MyToken.deploy(initialSupply);
await myToken.deployed();
console.log("MyToken deployed to:", myToken.address);
}
main();
1.4 ERC-721 Smart Contract for NFTs
The ERC-721 standard defines a non-fungible token (NFT), meaning each token is unique and cannot be exchanged on a 1-to-1 basis with another token.
1.4.1 ERC-721 Contract Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyNFT is ERC721URIStorage, Ownable {
uint256 public nextTokenId;
address public admin;
constructor() ERC721("MyNFT", "MNFT") {
admin = msg.sender;
}
function mint(address to, string memory uri) external onlyOwner {
uint256 tokenId = nextTokenId;
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
nextTokenId++;
}
function burn(uint256 tokenId) external onlyOwner {
_burn(tokenId);
}
}
1.4.2 Explanation
This contract extension from OpenZeppelin allows for storing metadata (such as the token's URI) on the blockchain.
1.4.3 Deployment of ERC-721 Contract
Truffle Migration Script
const MyNFT = artifacts.require("MyNFT");
module.exports = function (deployer) {
deployer.deploy(MyNFT);
};
Hardhat Deployment Script
const { ethers } = require("hardhat");
async function main() {
const MyNFT = await ethers.getContractFactory("MyNFT");
const myNFT = await MyNFT.deploy();
await myNFT.deployed();
console.log("MyNFT deployed to:", myNFT.address);
}
main();
1.5 Best Practices for Secure and Efficient Smart Contracts
1.5.1 Security Practices
Use nonReentrant
from OpenZeppelin's ReentrancyGuard
contract to prevent reentrancy attacks.
1.5.2 Gas Optimization
Use constant
for variables that wonβt change to reduce gas costs.
1.6 Testing and Deployment on Mainnet
Testing is essential before deploying to the mainnet. Use Truffle or Hardhatβs testing frameworks to test contract functions locally and on test networks.
Test in Truffle
const MyToken = artifacts.require("MyToken");
contract("MyToken", accounts => {
it("should mint initial supply to the deployer", async () => {
const myToken = await MyToken.deployed();
const balance = await myToken.balanceOf(accounts[0]);
assert(balance.toString() === web3.utils.toWei("1000", "ether"));
});
});
1.6.1 Deployment to Mainnet
Ensure the contract is fully tested.
Set up a deployment wallet with sufficient ETH for gas.
Use your
.env
to securely manage your private key and Infura/Alchemy endpoint.
npx hardhat run --network mainnet scripts/deploy.js
Last updated