During my Blockchain Internship at EtherAuthority, I built a fully functional DeFi staking platform from scratch โ a smart contract deployed on SCAI Mainnet, a React frontend connected via MetaMask, and real-time blockchain event tracking. Here's everything I learned.
๐ Live Demo & Code
Live App: https://defi-staking-platform-wc8n.vercel.app
GitHub: https://github.com/Tanisha-aggarwal1085/Defi-Staking-Platform
What is a DeFi Staking Platform?
A DeFi (Decentralized Finance) staking platform allows users to lock up cryptocurrency tokens in a smart contract and earn rewards over time โ similar to a savings account, but fully on-chain with no central authority.
In this project, users can:
Stake SCAI tokens and earn 12% APY
Withdraw their stake at any time (no lock-up period)
Claim accrued rewards
View full transaction history from blockchain events
Tech Stack
LayerTechnologySmart ContractSolidity ^0.8.20DevelopmentHardhatFrontendReact + ViteBlockchain Libraryethers.js v6WalletMetaMaskNetworkSCAI Mainnet (Chain ID: 34)HostingVercel
Smart Contract Design
The core of the platform is Staking.sol. Here's the key logic:
solidity// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Staking {
uint256 public constant APY = 12;
uint256 public constant YEAR = 365 days;
mapping(address => uint256) public stakes;
mapping(address => uint256) public rewards;
mapping(address => uint256) public lastUpdated;
event Staked(address indexed user, uint256 amount, uint256 newTotal);
event Withdrawn(address indexed user, uint256 amount, uint256 newTotal);
event RewardClaimed(address indexed user, uint256 amount);
function _updateReward(address user) internal {
if (stakes[user] > 0) {
uint256 timeElapsed = block.timestamp - lastUpdated[user];
uint256 earned = (stakes[user] * APY * timeElapsed) / (100 * YEAR);
rewards[user] += earned;
}
lastUpdated[user] = block.timestamp;
}
function stake() public payable {
require(msg.value > 0, "Amount must be greater than 0");
_updateReward(msg.sender);
stakes[msg.sender] += msg.value;
emit Staked(msg.sender, msg.value, stakes[msg.sender]);
}
function withdraw(uint256 amount) public {
require(stakes[msg.sender] >= amount, "Not enough stake");
_updateReward(msg.sender);
stakes[msg.sender] -= amount;
(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Transfer failed");
emit Withdrawn(msg.sender, amount, stakes[msg.sender]);
}
function claimReward() public {
_updateReward(msg.sender);
uint256 reward = rewards[msg.sender];
require(reward > 0, "No rewards");
rewards[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: reward}("");
require(success, "Transfer failed");
emit RewardClaimed(msg.sender, reward);
}
}
Key Design Decisions:
Time-based APY โ Rewards accrue continuously using block.timestamp
Checks-Effects-Interactions โ State changes happen before external calls (reentrancy prevention)
Events โ Every action emits an event for transparent on-chain history
Reward Calculation Formula
earned = (stakes[user] ร APY ร timeElapsed) / (100 ร YEAR)
This calculates rewards proportionally โ the longer you stake, the more you earn.
Frontend Architecture
The React app uses a Context-based architecture to share blockchain state across all pages:
App.jsx (Router)
โโโ Web3Context.jsx โ wallet + contract logic
โโโ Dashboard.jsx โ stake/withdraw/claim UI
โโโ MyStakes.jsx โ balance overview
โโโ Transactions.jsx โ blockchain event history
โโโ About.jsx โ platform info
Connecting to MetaMask with ethers.js v6:
javascriptconst connectWallet = async () => {
const provider = new ethers.BrowserProvider(window.ethereum);
await window.ethereum.request({ method: "eth_requestAccounts" });
const signer = await provider.getSigner();
const walletAddress = await signer.getAddress();
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer);
// read stake and reward...
};
Network Auto-Switch:
javascriptawait window.ethereum.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: "0x22" }], // SCAI Mainnet = 34
});
Deployment to SCAI Mainnet
javascript// hardhat.config.js
module.exports = {
solidity: "0.8.20",
networks: {
scai: {
url: "https://mainnet-rpc.scai.network",
accounts: [process.env.PRIVATE_KEY],
chainId: 34
}
}
};
bashnpx hardhat run scripts/deploy.js --network scai
Contract deployed to: 0xCd279499974Ac556a7DA538e5F1f1B501E46c14c
Challenges I Faced & How I Solved Them
- Invalid Contract Address My first deployment had a 41-character address (should be 40). MetaMask flagged every transaction as suspicious. Fix: Always verify address length after deployment.
- Shared Loading State All three buttons (Stake, Withdraw, Claim) showed "Processing..." simultaneously because they shared one loading state. Fix: Created separate stakeLoading, withdrawLoading, claimLoading states.
- Wrong Network The app was initially deployed on local Hardhat โ mentors couldn't test it. Fix: Deployed to SCAI Mainnet and added automatic network switching.
- Transaction History Not Persisting Blockchain events (queryFilter) sometimes failed on SCAI RPC. Fix: Dual approach โ immediate in-memory update + async blockchain event sync.
What I Learned
โ
How DeFi staking protocols work under the hood
โ
Writing production-safe Solidity with CEI pattern
โ
Deploying to real mainnets (not just testnets)
โ
Debugging MetaMask transaction issues
โ
Building multi-page Web3 dApps with React
Conclusion
Building this DeFi staking platform gave me hands-on experience with the full blockchain development stack โ from smart contract design to frontend deployment. The biggest takeaway: real-world blockchain development is 20% writing code and 80% debugging transactions, network issues, and wallet quirks.
If you want to explore the code or try the live app:
๐ Live: https://defi-staking-platform-wc8n.vercel.app
๐ GitHub: https://github.com/Tanisha-aggarwal1085/Defi-Staking-Platform
Built during Blockchain Internship at EtherAuthority
United States
NORTH AMERICA
Related News
Secret Claude Tracker Shocks Users After Anthropic's Anti-Surveillance Stance
12h ago
EV Batteries Defy Expectations, Last Hundreds of Thousands of Miles
1d ago
GBase 8a Performance Anomaly Case Study: How a Single Parameter Change Sparked a Chain Reaction
1d ago
Who Else Has Inherited a Codebase With Zero Comments and a Prayer?
1d ago
ๅฎ็พ็ๅนณๅบธ
4h ago