The post Writing and Deploying Smart Contracts for Developers appeared first on Coinpedia Fintech News
Introduction
Blockchain is a huge decentralized distributed database. It is designed in such a way that it is ideal for industries where transparency, immutability, tamper-proofing, and decentralization are priorities. Blockchain has expanded its domain in various fields such as Finance, cryptocurrencies, Supply chain, and Healthcare.
Smart Contracts
Smart contracts are programs that run by themselves. They are stored on the blockchain network. The smart contract code contains transactions, agreements, and terms of the contract. Smart Contracts are immutable and transparent making them a perfect choice for decentralized applications. At their core, they’re programs that enforce contract terms when set conditions are met.
Why should you Write and Deploy Smart Contracts for dApps?
Decentralization as the name refers means no centralized authority and intermediaries. Smart contracts are automated without needing any third-party interference. Smart contracts allow deals without trust cut down on cheating risk, and make many steps work better. Hence smart contracts are a good choice for dApps.Getting good at writing and deploying smart contracts is key for developers who want to build strong and safe dApps.
We hope you have comforted yourself with the basic idea of smart contracts. In this article, we will walk you through a step-by-step guide on writing and deploying smart contracts. Get ready!! We are now going to dive into the practical aspects of writing, deploying, and integrating smart contracts within decentralized applications (DApps), exploring the tools, best practices, and real-world use cases that make these technologies transformative.
Development Tools and Environment Setup
Before you write any code it’s crucial to have solid setup of the development tools and environment.
Integrated Development Environments (IDEs):
Developers generally opt for various IDEs for smart contract development and testing. But some of the most preferred ones are below:
Remix: Remix is an online IDE specially curated for Solidity smart contracts and has a very interactive interface and robust debugging tools. Remix gives you a hassle free experience and there is no need to configure. Just visit the site and start coding.
VS Code: Vs Code is the evergreen IDE that every developer uses that has its compatibility with various languages and provides extensions for Solidity as well. It has a versatile environment for development and can seamlessly integrate with other tools and plugins.
To setup VS Code :
Download it from the official site
Follow the on screen instructions
Install all the Solidity extensions needed to write a smart contracts
Frameworks and Libraries:
Frameworks and libraries ease the development process, making it more structured and streamlined. Let’s take a look at the ones supporting smart contracts.
Truffle: It is a development framework that provides a set of tools for the development, compilation, linking, and deployment of smart contracts.
Hardhat: Hardhat is a popular choice among developers due to its features like flexibility and extensibility. Also, it has an integrated task runner, and network management ability, and can extend its functionalities through plugins.
Brownie: Brownie is a Python-based framework for Ethereum smart contract development.
Setting up the frameworks is just writing these commands in your terminal and you are ready to go:
Install Node.js and setup npm
Install Truffle: npm
install -g truffleInstall Hardhat: install –save-dev hardhat
Install Ganache
pip install eth-brownie
Life Cycle of a Smart Contract:
Let’s have a look at the Lifecycle of the Smart contract
Writing Smart Contracts
Now, let’s get to the fun part—writing your first smart contract!
Contract Structure:
Before we jump to the technical part let us understand the core concepts and structure of a Smart Contract. A smart contract is a small program that runs on the blockchain—every element has a specific purpose in making this program both functional and secure.
A smart contract is comprised of the following components:
State Variables: They are used to store the contract data.
Functions: Functions are the operations we need to perform on the contract data
Events: These are the log activities that can be observed externally
Modifiers: These control the access to functions.
Here is the practically written structure of the Smart Contract:
pragma solidity ^0.8.0;
contract SimpleStorage { uint256 public storedData; //state variable
event DataStored(uint256 data); //event
function set(uint256 x) public { //function
storedData = x;
emit DataStored(x);
}
function get() public view returns (uint256) {
return storedData;
}
}
Common Design Patterns:
When developing decentralized applications, using design patterns is a smart way to write efficient, maintainable contracts. Patterns are used to enhance the scalability of the smart contract. Here are the two most widely used patterns:
Factory Pattern: The Factory pattern influences the creation of many instances of a contract. This comes in handy to create new contracts on the fly, like setting up new versions of a contract for different users. It is helpful in a multi-user scenario.
Example code snippet
pragma solidity ^0.8.0;
contract Token { string public name;
constructor(string memory _name) {
name = _name;
}
}
contract TokenFactory {
Token[] public deployedTokens;
function createToken(string memory _name) public {
Token newToken = new Token(_name); // Create a new Token contract
instance
deployedTokens.push(newToken); // Store the instance in an array
}
}
The function TokenFactory() is used to store the values of contract tokens dynamically.
Proxy Pattern: This pattern enables the contract upgradeability by delegating calls to an implementation contract. Fundamentally smart contracts are immutable but Proxy pattern provides a way for users to change the logic and upgrade the contract over time.
Example code snippet
pragma solidity ^0.8.0;
contract Proxy {
address public implementation; // Address of the current implementation
function upgrade(address _newImplementation) public {
implementation = _newImplementation; // Upgrade the logic
}
fallback() external payable {
address _impl = implementation;
require(_impl != address(0));
(bool success, ) = _impl.delegatecall(msg.data); // Delegate calls to the implementation require(success);
}
}
Advanced Features:
These features make smart contracts more modular, reusable and powerful.
Inheritance: As the name suggests allows contracts to inherit properties and methods from other contracts.This is a concept of Object oriented programming and works the exact same way here also.It establishes the parent-child relationship between inherited classes.
Libraries: Libraries are the universal reusable code snippets that enhance the readability and modularity of the code by reducing redundancy.
Interfaces and Abstract Contracts: Define contract structures without implementing functions, promoting modularity.
Smart Contract Security
Common Vulnerabilities:
Security is paramount of Blockchain hence implementing best security practices is a must. Smart contracts hold real value and a little ignorance can lead to big impacts. The DAO hack of 2016 is a prime example of how vulnerable contracts can be if security best practices aren’t followed.Some common vulnerabilities in this domain are Reentrancy and Integer Overflow/underflow.
Reentrancy: This is the phenomenon where attackers call a contract repeatedly before the previous execution is completed.
Integer Overflow/Underflow: These are errors occurring when the calculations exceed the maximum or minimum values.
Front Running: Attackers Premetibvely execute the transaction.
Best Security Practices:
Use the latest Complier version
Follow the checks-effects-interaction
Limit the amount of code in fallback functions
Use the SafeMath library to prevent over and underflows.
Audit and Testing:
Once you are done with the writing part having regular audits and testing your smart contracts is the heart of the development life cycle.
MythX
MythX is a security analysis tool that performs security scans in your smart contracts.
Steps to integrate MythX into the development workflow:
Sign up for MythX,
configure your project
run scans to identify
fix security issues.
Slither
Slither looks for bugs in Solidity contracts. It’s a tool that doesn’t run the code but checks it for problems. Slither checks your code to find common safety issues. It also gives ideas to make your code better.
Performing security audits on smart contracts:
Review the code for vulnerabilities
Use automated tools
Address the identifies issues before the final deployment.
Example:
const { expect } = require(“chai”);
describe(“SimpleStorage”, function () {
it(“Should store and retrieve the correct value”, async function () {
const SimpleStorage = await
ethers.getContractFactory(“SimpleStorage”);
const simpleStorage = await SimpleStorage.deploy();
await simpleStorage.set(42);
expect(await simpleStorage.get()).to.equal(42);
});
});
Smart Contract Deployment
The next step after you are sure and content with the test and audit results of your contracts is Deployment.For Ethereum-based projects, tools like Truffle or Hardhat simplify the process.
Deployment Strategies:
Getting Smart Contracts Ready for Launch:
Code Optimization: Clean up and improve code to use less gas, which affects how much it costs to launch. Use tools like solc and hardhat-gas-reporter to check how much gas your code uses.
Gas Management: Keep a close eye on gas limits and prices to avoid failed transactions and high costs. Make sure your contract functions work well and don’t try to do too many complex things in one go.
Deployment Process Using Truffle, Hardhat, or Brownie:
(bash)
truffle migrate –network <network_name>
(hardhat)
async function main() {
const SimpleStorage = await
ethers.getContractFactory(“SimpleStorage”);
const simpleStorage = await SimpleStorage.deploy();
await simpleStorage.deployed();
console.log(“SimpleStorage deployed to:”, simpleStorage.address);
}
(brownie)
def main():
SimpleStorage.deploy({‘from’: accounts[0]})
Deployment Scripts: Create scripts to automate the deployment process. These scripts handle contract deployment set up configurations, and start the system.
async function main() {
const [deployer] = await ethers.getSigners();
console.log(“Deploying contracts with the account:”, deployer.address);
const SimpleStorage = await
ethers.getContractFactory(“SimpleStorage”);
const simpleStorage = await SimpleStorage.deploy();
console.log(“SimpleStorage address:”, simpleStorage.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
//Hardhat configuration
module.exports = {
networks: {
ropsten: {
url: “https://ropsten.infura.io/v3/YOUR-PROJECT-ID”,
accounts: [`0x${YOUR_PRIVATE_KEY}`]
},
mainnet: {
url: “https://mainnet.infura.io/v3/YOUR-PROJECT-ID”,
accounts: [`0x${YOUR_PRIVATE_KEY}`]
}
}
};
Verification and Validation:
Use services like Etherscan to verify and publish your contract’s source code.
npx hardhat verify –network mainnet DEPLOYED_CONTRACT_ADDRESS “Constructor argument 1”
Interacting with Deployed Contracts
Once your contract is deployed, you’ll need to interact with it using a front-end interface. Libraries like Web3.js or ethers.js allow you to communicate with smart contracts from JavaScript.
Web3 Integration:
We use Web3.py, and ether.js for interaction with the deployed contacts and front-end integration.
Here are some example code snippets:
from web3 import Web3
# Connect to the Ethereum networkweb3 = Web3(Web3.HTTPProvider(‘https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID’))
# Define the contract ABI and address
abi =
‘[{“constant”:false,”inputs”:[{“name”:”x”,”type”:”uint256″}],”name”:”set”,
“outputs”:[],”payable”:false,”stateMutability”:”nonpayable”,”type”:”function”},{“constant”:true,”inputs”:[],”name”:”get”,”outputs”:[{“name”:””,”type”:”uint256″}],”payable”:false,”stateMutability”:”view”,”type”:”function”}]’
contract_address = ‘0xYourContractAddress’
# Create a contract instance
contract = web3.eth.contract(address=contract_address, abi=abi)
# Call the contract’s functions
stored_data = contract.functions.get().call()
print(f’Stored Data: {stored_data}’)
# Send a transaction to modify the contract’s state
tx_hash = contract.functions.set(42).transact({‘from’: web3.eth.accounts[0]})
web3.eth.waitForTransactionReceipt(tx_hash)
Following is the code snippet for the frontend integration using Web3,js
<!DOCTYPE html>
<html>
<head>
<title>Simple Storage</title>
<script src=”https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js”></script></head><body>
<h1>Simple Storage</h1>
<p id=”storedData”></p>
<button onclick=”setData()”>Set Data</button>
<script>
const web3 = new Web3(Web3.givenProvider || ‘http://127.0.0.1:8545’);
const contractAddress = ‘0xYourContractAddress’;
const abi = [ /* ABI from the contract */ ];
const contract = new web3.eth.Contract(abi, contractAddress);
async function setData() {
const accounts = await web3.eth.requestAccounts();
await contract.methods.set(42).send({ from: accounts[0] })
getData();
getData();
</script>
</body>
</html>
Transaction Management:
Sending transactions involves invoking functions on your smart contract, which typically modify the blockchain state. Here’s how you can do it using different libraries:
web3.js
const Web3 = require(‘web3’);
const web3 = new Web3(‘https://mainnet.infura.io/v3/YOUR-PROJECT-ID’);
const contract = new web3.eth.Contract(abi, contractAddress);
const sendTransaction = async () => {
const receipt = await contract.methods.set(42).send({ from: userAddress });
console.log(“Transaction receipt:”, receipt);
};
ether.js
const { ethers } = require(‘ethers’);
const provider = new ethers.providers.InfuraProvider(‘mainnet’,
‘YOUR-PROJECT-ID’);
const wallet = new ethers.Wallet(‘YOUR-PRIVATE-KEY’, provider);
const contract = new ethers.Contract(contractAddress, abi, wallet);
const sendTransaction = async () => {
const tx = await contract.set(42);
const receipt = await tx.wait();
console.log(“Transaction receipt:”, receipt);};
web3.py
from web3 import Web3web3 =
Web3(Web3.HTTPProvider(‘https://mainnet.infura.io/v3/YOUR-PROJECT-ID’))contract = web3.eth.contract(address=contract_address, abi=abi)
tx = contract.functions.set(42).buildTransaction({
‘from’: user_address,
‘nonce’: web3.eth.getTransactionCount(user_address),
‘gas’: 2000000, ‘
gasPrice’: web3.toWei(’50’, ‘gwei’)
})
signed_tx = web3.eth.account.sign_transaction(tx, private_key)tx_hash = web3.eth.sendRawTransaction(signed_tx.rawTransaction)receipt = web3.eth.waitForTransactionReceipt(tx_hash)print(“Transaction receipt:”, receipt)
Smart contracts can emit events that can be listened to by your application. Here’s how you can handle events:
ether.js
contract.events.DataStored()
.on(‘data’, (event) => {
console.log(event.returnValues);
})
.on(‘error’, console.error);
web3.py
event_filter = contract.events.DataStored.createFilter(fromBlock=’latest’)while True:
for event in event_filter.get_new_entries():
print(event[‘args’])
Error Handling and Retries in Transaction Processing
Blockchain transactions can fail for many reasons. These include running out of gas or network congestion. To build a reliable app, you need to handle errors well and try again when things go wrong.
const sendTransaction = async () => {
try {
const receipt = await contract.methods.set(42).send({ from:
userAddress });
console.log(“Transaction successful:”, receipt); } catch (error) {
console.error(“Transaction failed:”, error);
// Implement retry logic
if (shouldRetry(error)) {
setTimeout(sendTransaction, 1000); // Retry after 1 second
}
}
};
const shouldRetry = (error) => {
// Define retry logic based on the error type
return error.message.includes(‘network congestion’) ||
error.message.includes(‘out of gas’);
};
Upgrading and Maintaining Smart Contracts
Upgradeability Patterns:
Implementing proxy patterns for contract upgradeability:
Proxy patterns give you the ability to upgrade smart contracts by keeping the logic separate from the storage. The proxy sends calls to the logic contract while keeping the same storage layout.
Solidity:
contract Proxy {
address implementation;
function upgrade(address newImplementation) public {
implementation = newImplementation; }
fallback() external payable {
address _impl = implementation;
require(_impl != address(0), “Implementation contract not set”);
assembly {
let ptr := mload(0x40)
calldatacopy(ptr, 0, calldatasize())
let result := delegatecall(gas(), _impl, ptr, calldatasize(),
0, 0)
let size := returndatasize()
returndatacopy(ptr, 0, size)
switch result
case 0 { revert(ptr, size) }
default { return(ptr, size) }
}
}
}
Handling state migrations and contract storage: When you upgrade contracts, you need to make sure the state stays intact and moves over . Write code to shift data from the old contract to the new one.
contract NewContract {
uint256 public data;
function setData(uint256 _data) public {
data = _data;
}
}
contract Migration {
function migrate(address oldContract, address newContract) public {
uint256 data = OldContract(oldContract).data();
NewContract(newContract).setData(data);
}
}
Maintaining Contracts:
Best Practices to Maintain and Update Contracts Over Time:
Regular Audits: Conduct security audits at set intervals to spot and correct weak points.
Monitoring: Keep an eye on contract performance and security with specialized tools and services.
Documentation: Keep thorough records to make updates and maintenance easier.
Monitoring Deployed Contracts for Performance and Security:
Use tools like Etherscan, Tenderly, and custom scripts to track contract activity, performance, and possible security threats. Check logs and transaction histories often to spot anything unusual.
When you stick to these practices, you make sure your smart contracts stay secure work well, and can adapt to future changes and upgrades.
Real-World Applications and Case Studies
We can take the example of Uniswap: Decentralized exchange.
Overview of the project:
Uniswap is a decentralized exchange (DEX) built on the Ethereum blockchain. Unlike traditional exchanges that rely on order books, Uniswap uses an automated market maker (AMM) model to facilitate ERC-20 token trading through liquidity pools. Users can trade tokens directly from their wallets, providing liquidity to pools and earning fees in return.
Key Parts:
Liquidity Pools: In this phenomenon, users deposit equal values for two tokens in a pool to allow others to trade.
AMM System: This system determines the price of tokens based on the ratio of tokens in the pool, eliminating the need for an order book.
Main Contracts: The core contracts manage the creation of new trading pairs, execution of trades, and liquidity management.
Contract for creating new pairs: Allows users to create new trading pairs for any ERC-20 tokens.
Good Practices:
Have Regular Safety Checks
Gas Optimization
Community decision making
Project Development:
To develop an entire project from scratch you need to have a framework in mind that has all the necessary steps. This can be a checklist and help you develop the application efficiently. Take a quick look at the Flow chart:
Define the Project Scope: problem identification and research
Choose the right blockchain platform
Design the Smart contract: Check the architecture, security and Optimization
Develop and Test
Deploy and maintain
Key considerations for project planning and execution.
Clear Objectives
Stake Holder engagement
Resource allocation
User Experience(UX)
Timeline and Milestones
Risk Management
Community engagement
Regulatory Compliance
Quality Assurance
Sustainability
Technology and Tools
Monitoring and evaluation
Change Management
Conclusion
Smart contracts are the main elements of blockchain development that enable trustless, decentralized, and automated interactions. From writing secure contracts to deploying and interacting with them, you’ve now gained a solid foundation to build your own dApps. This is just the stepping stone of the entire journey ahead. Keep exploring the advanced features and update yourself to excel in every part of life.
Stay curious and keep up with changes in rules and industry guidelines. Change how you build things to use new tools and systems making sure your smart contracts stay useful and work well as the blockchain world grows and changes. Happy coding!!
Future Trends in Smart Contracts
Let’s talk about new tech and trends, like layer 2 solutions and cross-chain interoperability. These could shake things up in smart contract development. This game plan helps developers learn step-by-step how to write, deploy, and keep smart contracts running. It’s key for building decentralized apps you can count on.
Also Check Out: How to Build Your First Blockchain with Plutus: A Step-by-Step Tutorial