{"id":10390,"date":"2024-11-19T12:26:23","date_gmt":"2024-11-19T12:26:23","guid":{"rendered":"https:\/\/metaschool.so\/articles\/?p=10390"},"modified":"2024-11-19T12:26:54","modified_gmt":"2024-11-19T12:26:54","slug":"build-a-staking-platform","status":"publish","type":"post","link":"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/","title":{"rendered":"Building a Web3 Staking Platform: A Comprehensive Guide"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_56_1 ez-toc-wrap-left counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title \" >Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Why_Build_Your_Own_Staking_Platform\" title=\"Why Build Your Own Staking Platform?\">Why Build Your Own Staking Platform?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Planning_Our_Approach\" title=\"Planning Our Approach\">Planning Our Approach<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Choosing_Our_Technology_Stack\" title=\"Choosing Our Technology Stack\">Choosing Our Technology Stack<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Setting_Up_Our_Development_Environment\" title=\"Setting Up Our Development Environment\">Setting Up Our Development Environment<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Understanding_Smart_Contract_Architecture\" title=\"Understanding Smart Contract Architecture\">Understanding Smart Contract Architecture<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Building_the_Core_Staking_Logic\" title=\"Building the Core Staking Logic\">Building the Core Staking Logic<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Reward_Calculation_Mechanism\" title=\"Reward Calculation Mechanism\">Reward Calculation Mechanism<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Setting_up_Admin_Functions\" title=\"Setting up Admin Functions\">Setting up Admin Functions<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Write_your_token_smart_contract\" title=\"Write your token smart contract \">Write your token smart contract <\/a><ul class='ez-toc-list-level-3'><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Ethereum\" title=\"Ethereum\">Ethereum<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Building_the_User_Interface\" title=\"Building the User Interface\">Building the User Interface<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Testing_our_smart_contract\" title=\"Testing our smart contract \">Testing our smart contract <\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Deployment\" title=\"Deployment \">Deployment <\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/metaschool.so\/articles\/build-a-staking-platform\/#Conclusion\" title=\"Conclusion\">Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n\n<p>The world of cryptocurrency has evolved far beyond simple transactions. Today, one of the most compelling aspects of crypto is the ability to earn passive income through staking. But what exactly is staking, and why should we build a platform? Think of staking as the crypto equivalent of earning interest on a savings account, but with a crucial difference &#8211; instead of trusting a bank, you&#8217;re participating directly in a blockchain network&#8217;s operation. When users stake their tokens, they&#8217;re essentially putting up collateral to help secure the network, and in return, they earn rewards.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Why_Build_Your_Own_Staking_Platform\"><\/span>Why Build Your Own Staking Platform?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>You might wonder why we should build a staking platform when there are already existing solutions. The answer lies in control, customization, and understanding. By building your own platform, you gain intimate knowledge of how staking works from the ground up. More importantly, you can create features that existing platforms might lack, implement your own reward mechanisms, and ensure the security of your users&#8217; funds through carefully crafted code.<\/p>\n\n\n\n<p>The current staking landscape has several pain points. Many platforms are overly complex, have high minimum staking requirements, or lack transparency. By building our solution, we can address these issues head-on and create something that truly serves our users&#8217; needs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Planning_Our_Approach\"><\/span>Planning Our Approach<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Before we write a single line of code, let&#8217;s think about what our platform needs to accomplish. At its core, a staking platform needs to:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1404\" height=\"1238\" src=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-17.png\" alt=\"User flow for Staking Platform\n\" class=\"wp-image-10404\" srcset=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-17.png 1404w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-17-300x265.png 300w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-17-1024x903.png 1024w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-17-768x677.png 768w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-17-1320x1164.png 1320w\" sizes=\"auto, (max-width: 1404px) 100vw, 1404px\" \/><\/figure>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Accept user deposits of tokens<\/li>\n\n\n\n<li>Lock these tokens for a specified period<\/li>\n\n\n\n<li>Calculate and distribute rewards<\/li>\n\n\n\n<li>Allow users to withdraw their stakes and rewards when conditions are met<\/li>\n<\/ol>\n\n\n\n<p>But the technical implementation of these features requires careful consideration. We&#8217;ll need smart contracts to handle the blockchain interactions, a frontend interface for users to interact with these contracts, and potentially a backend service to track and display staking statistics.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Choosing_Our_Technology_Stack\"><\/span>Choosing Our Technology Stack<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The choice of technology stack is crucial for building a robust staking platform. For smart contracts, we&#8217;ll use Solidity &#8211; the industry standard for Ethereum development. It&#8217;s battle-tested, well-documented, and has a large community for support.<\/p>\n\n\n\n<p>For development and testing, we&#8217;ll use Hardhat as our development environment. Hardhat provides powerful debugging features, a testing framework, and excellent plugin support. This choice will make our development process smoother and more efficient.<\/p>\n\n\n\n<p>On the frontend, React makes the most sense. Its component-based architecture perfectly suits our needs for building a responsive and interactive user interface. We&#8217;ll pair it with ethers.js for blockchain interactions &#8211; a library chosen for its reliability and excellent TypeScript support.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Setting_Up_Our_Development_Environment\"><\/span>Setting Up Our Development Environment<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Let&#8217;s start by setting up our development environment. First, create a new directory for your project and initialize it with npm:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"mkdir staking-platform\ncd staking-platform\nnpm init -y\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">mkdir<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">staking<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">platform<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">cd<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">staking<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">platform<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">npm<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">init<\/span><span style=\"color: #D4D4D4\"> -<\/span><span style=\"color: #9CDCFE\">y<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Now we&#8217;ll install our core dependencies:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"npm install hardhat @openzeppelin\/contracts ethers\nnpm install -D typescript ts-node @types\/node\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">npm<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">install<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">hardhat<\/span><span style=\"color: #D4D4D4\"> @<\/span><span style=\"color: #9CDCFE\">openzeppelin<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">contracts<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ethers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">npm<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">install<\/span><span style=\"color: #D4D4D4\"> -<\/span><span style=\"color: #4FC1FF\">D<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">typescript<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ts<\/span><span style=\"color: #D4D4D4\">-<\/span><span style=\"color: #9CDCFE\">node<\/span><span style=\"color: #D4D4D4\"> @<\/span><span style=\"color: #9CDCFE\">types<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">node<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>These tools form the foundation of our development environment. <a href=\"https:\/\/hardhat.org\/\" data-type=\"link\" data-id=\"https:\/\/hardhat.org\/\" target=\"_blank\" rel=\"noopener\">Hardhat<\/a> will handle our smart contract compilation and testing, while OpenZeppelin provides secure, standard contract implementations on which we can build.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Understanding_Smart_Contract_Architecture\"><\/span>Understanding Smart Contract Architecture<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The heart of our staking platform lies in its smart contracts. We need to think carefully about how these contracts will interact with each other and with our users. The main components are:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>A staking contract that handles deposits and withdrawals<\/li>\n\n\n\n<li>A reward calculation mechanism<\/li>\n\n\n\n<li>A token contract (since we will be creating our token)<\/li>\n<\/ol>\n\n\n\n<p>Considering security while writing smart contracts is a very important factor to keep in mind. Test case scenarios need to be taken in consideration. While building a staking platform we need to consider scenarios like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>What happens if a user tries to withdraw early?<\/li>\n\n\n\n<li>How do we prevent the manipulation of reward calculations?<\/li>\n\n\n\n<li>What safeguards do we need against reentrancy attacks?<\/li>\n<\/ul>\n\n\n\n<p>Let&#8217;s look at the basic structure of our staking contract:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport &quot;@openzeppelin\/contracts\/token\/ERC20\/IERC20.sol&quot;;\nimport &quot;@openzeppelin\/contracts\/security\/ReentrancyGuard.sol&quot;;\nimport &quot;@openzeppelin\/contracts\/access\/Ownable.sol&quot;;\n\ncontract StakingPlatform is ReentrancyGuard, Ownable {\n    IERC20 public stakingToken;\n    \n    \/\/ Staking settings\n    uint256 public minimumStakingAmount = 100 * 10**18; \/\/ 100 tokens minimum\n    uint256 public rewardRate = 10; \/\/ 10% APR\n    uint256 public totalRewardsDistributed;\n    \n    struct Stake {\n        uint256 amount;\n        uint256 timestamp;\n        uint256 lastRewardCalculation;\n    }\n    \n    mapping(address =&gt; Stake) public stakes;\n    uint256 public totalStaked;\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/\/ SPDX-License-Identifier: MIT<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">pragma<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">solidity<\/span><span style=\"color: #D4D4D4\"> ^<\/span><span style=\"color: #B5CEA8\">0.8<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/token\/ERC20\/IERC20.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/security\/ReentrancyGuard.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/access\/Ownable.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">contract<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingPlatform<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ReentrancyGuard<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">Ownable<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4FC1FF\">IERC20<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Staking settings<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #B5CEA8\">100<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">10<\/span><span style=\"color: #D4D4D4\">**<\/span><span style=\"color: #B5CEA8\">18<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #6A9955\">\/\/ 100 tokens minimum<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">rewardRate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #B5CEA8\">10<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #6A9955\">\/\/ 10% APR<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">totalRewardsDistributed<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">struct<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Stake<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">mapping<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Stake<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">totalStaked<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Building_the_Core_Staking_Logic\"><\/span>Building the Core Staking Logic<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The core logic for the staking platform needs to handle several key functions like staking, withdrawing, and calculating rewards, as well as some admin functions like setting the minimum staking amount and setting up the reward rate. We will look into each one of them step by step. First, let us implement a staking function where users need to be able to stake their tokens. This involves transferring tokens from their wallet to our contract:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"function stake(uint256 _amount) external nonReentrant {\n        require(_amount &gt;= minimumStakingAmount, &quot;Amount below minimum staking amount&quot;);\n        require(stakingToken.transferFrom(msg.sender, address(this), _amount), &quot;Transfer failed&quot;);\n        \n        if (stakes[msg.sender].amount &gt; 0) {\n            \/\/ Calculate and add pending rewards to stake\n            uint256 reward = calculateReward(msg.sender);\n            stakes[msg.sender].amount += reward;\n        }\n        \n        stakes[msg.sender].amount += _amount;\n        stakes[msg.sender].timestamp = block.timestamp;\n        stakes[msg.sender].lastRewardCalculation = block.timestamp;\n        totalStaked += _amount;\n        \n        emit Staked(msg.sender, _amount);\n    }\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">nonReentrant<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\"> &gt;= <\/span><span style=\"color: #9CDCFE\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;Amount below minimum staking amount&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">transferFrom<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">address<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">this<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #CE9178\">&quot;Transfer failed&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> &gt; <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Calculate and add pending rewards to stake<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">totalStaked<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">emit<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Staked<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Reward_Calculation_Mechanism\"><\/span>Reward Calculation Mechanism<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>One of the most complex aspects of a staking platform is calculating rewards fairly and efficiently. We need to consider:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Should rewards be calculated in real-time or periodically?<\/li>\n\n\n\n<li>How do we handle different staking durations?<\/li>\n\n\n\n<li>What happens to rewards when users add to their stake?<\/li>\n<\/ul>\n\n\n\n<p>A simple reward calculation might look like this:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"function calculateReward(address _staker) public view returns (uint256) {\n        if (stakes[_staker].amount == 0) return 0;\n        \n        uint256 stakingDuration = block.timestamp - stakes[_staker].lastRewardCalculation;\n        uint256 reward = (stakes[_staker].amount * rewardRate * stakingDuration) \/ (365 days * 100);\n        \n        return reward;\n    }\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">view<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">returns<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingDuration<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\"> - <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\"> = (<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #9CDCFE\">rewardRate<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #9CDCFE\">stakingDuration<\/span><span style=\"color: #D4D4D4\">) \/ (<\/span><span style=\"color: #B5CEA8\">365<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">days<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">100<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>However, this basic calculation doesn&#8217;t account for many real-world considerations. We need to think about:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Gas efficiency for large numbers of users staking on the platform<\/li>\n\n\n\n<li>Precision loss in calculations<\/li>\n\n\n\n<li>Fairness in reward distribution<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Setting_up_Admin_Functions\"><\/span>Setting up Admin Functions<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>We need to write some functions that should only be controlled by the caller of the smart contract and no discrepancy is created. For example in this scenario we need a function to set up the minimum staking amount and setting up the reward rate for our staking platform<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"function setMinimumStakingAmount(uint256 _amount) external onlyOwner {\n        minimumStakingAmount = _amount;\n    }\n    \n    function setRewardRate(uint256 _rate) external onlyOwner {\n        rewardRate = _rate;\n    }\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">setMinimumStakingAmount<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">onlyOwner<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">setRewardRate<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_rate<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">onlyOwner<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">rewardRate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">_rate<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>You would have noticed that in the tiny bits of code that we have shared, there are emit functions being called. For every emit and event is triggered and thus we have an event that needs to be created. <\/p>\n\n\n\n<p><strong>Note: emit is a keyword used to trigger events. These events are inheritable members of contracts.\u00a0When you use emit , followed by the event name and its parameters, it logs the event to the blockchain. This means that the event is stored on the blockchain and can be accessed and listened to externally<\/strong><\/p>\n\n\n\n<p>This is how our entire code for the Staking Platform will look like :<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport &quot;@openzeppelin\/contracts\/token\/ERC20\/IERC20.sol&quot;;\nimport &quot;@openzeppelin\/contracts\/security\/ReentrancyGuard.sol&quot;;\nimport &quot;@openzeppelin\/contracts\/access\/Ownable.sol&quot;;\n\ncontract StakingPlatform is ReentrancyGuard, Ownable {\n    IERC20 public stakingToken;\n    \n    \/\/ Staking settings\n    uint256 public minimumStakingAmount = 100 * 10**18; \/\/ 100 tokens minimum\n    uint256 public rewardRate = 10; \/\/ 10% APR\n    uint256 public totalRewardsDistributed;\n    \n    struct Stake {\n        uint256 amount;\n        uint256 timestamp;\n        uint256 lastRewardCalculation;\n    }\n    \n    mapping(address =&gt; Stake) public stakes;\n    uint256 public totalStaked;\n    \n    event Staked(address indexed user, uint256 amount);\n    event Withdrawn(address indexed user, uint256 amount);\n    event RewardPaid(address indexed user, uint256 reward);\n    event RewardsAdded(uint256 amount);\n    \n    constructor(address _stakingToken) {\n        stakingToken = IERC20(_stakingToken);\n    }\n\n    \/\/ Function to add rewards to the contract\n    function addRewards(uint256 _amount) external {\n        require(stakingToken.transferFrom(msg.sender, address(this), _amount), &quot;Transfer failed&quot;);\n        emit RewardsAdded(_amount);\n    }\n    \n    function stake(uint256 _amount) external nonReentrant {\n        require(_amount &gt;= minimumStakingAmount, &quot;Amount below minimum staking amount&quot;);\n        require(stakingToken.transferFrom(msg.sender, address(this), _amount), &quot;Transfer failed&quot;);\n        \n        if (stakes[msg.sender].amount &gt; 0) {\n            \/\/ Calculate and add pending rewards to stake\n            uint256 reward = calculateReward(msg.sender);\n            stakes[msg.sender].amount += reward;\n        }\n        \n        stakes[msg.sender].amount += _amount;\n        stakes[msg.sender].timestamp = block.timestamp;\n        stakes[msg.sender].lastRewardCalculation = block.timestamp;\n        totalStaked += _amount;\n        \n        emit Staked(msg.sender, _amount);\n    }\n    \n    function withdraw(uint256 _amount) external nonReentrant {\n        require(stakes[msg.sender].amount &gt;= _amount, &quot;Insufficient staked amount&quot;);\n        \n        \/\/ Calculate rewards before withdrawal\n        uint256 reward = calculateReward(msg.sender);\n        uint256 totalAmount = _amount + reward;\n        \n        \/\/ Update state before transfer\n        stakes[msg.sender].amount -= _amount;\n        totalStaked -= _amount;\n        stakes[msg.sender].lastRewardCalculation = block.timestamp;\n        totalRewardsDistributed += reward;\n        \n        \/\/ Ensure contract has enough balance\n        require(stakingToken.balanceOf(address(this)) &gt;= totalAmount, &quot;Insufficient contract balance&quot;);\n        require(stakingToken.transfer(msg.sender, totalAmount), &quot;Transfer failed&quot;);\n        \n        emit Withdrawn(msg.sender, _amount);\n        if (reward &gt; 0) {\n            emit RewardPaid(msg.sender, reward);\n        }\n    }\n    \n    function calculateReward(address _staker) public view returns (uint256) {\n        if (stakes[_staker].amount == 0) return 0;\n        \n        uint256 stakingDuration = block.timestamp - stakes[_staker].lastRewardCalculation;\n        uint256 reward = (stakes[_staker].amount * rewardRate * stakingDuration) \/ (365 days * 100);\n        \n        return reward;\n    }\n    \n    function getStakeInfo(address _staker) external view returns (\n        uint256 stakedAmount,\n        uint256 stakingTime,\n        uint256 pendingRewards\n    ) {\n        Stake memory stake = stakes[_staker];\n        return (\n            stake.amount,\n            stake.timestamp,\n            calculateReward(_staker)\n        );\n    }\n    \n    \/\/ Admin functions\n    function setMinimumStakingAmount(uint256 _amount) external onlyOwner {\n        minimumStakingAmount = _amount;\n    }\n    \n    function setRewardRate(uint256 _rate) external onlyOwner {\n        rewardRate = _rate;\n    }\n}\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/\/ SPDX-License-Identifier: MIT<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">pragma<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">solidity<\/span><span style=\"color: #D4D4D4\"> ^<\/span><span style=\"color: #B5CEA8\">0.8<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/token\/ERC20\/IERC20.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/security\/ReentrancyGuard.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/access\/Ownable.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">contract<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingPlatform<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ReentrancyGuard<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">Ownable<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #4FC1FF\">IERC20<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Staking settings<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #B5CEA8\">100<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">10<\/span><span style=\"color: #D4D4D4\">**<\/span><span style=\"color: #B5CEA8\">18<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #6A9955\">\/\/ 100 tokens minimum<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">rewardRate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #B5CEA8\">10<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #6A9955\">\/\/ 10% APR<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">totalRewardsDistributed<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">struct<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Stake<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">mapping<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">=&gt;<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">Stake<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">totalStaked<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Staked<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">indexed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">user<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Withdrawn<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">indexed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">user<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">RewardPaid<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">indexed<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">user<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">event<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">RewardsAdded<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">constructor<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_stakingToken<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">IERC20<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_stakingToken<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Function to add rewards to the contract<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">addRewards<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">transferFrom<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">address<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">this<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #CE9178\">&quot;Transfer failed&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">emit<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">RewardsAdded<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">nonReentrant<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\"> &gt;= <\/span><span style=\"color: #9CDCFE\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;Amount below minimum staking amount&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">transferFrom<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #DCDCAA\">address<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">this<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #CE9178\">&quot;Transfer failed&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> &gt; <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #6A9955\">\/\/ Calculate and add pending rewards to stake<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">totalStaked<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">emit<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Staked<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">withdraw<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">nonReentrant<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> &gt;= <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;Insufficient staked amount&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\">\/\/ Calculate rewards before withdrawal<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">totalAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\"> + <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\">\/\/ Update state before transfer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> -= <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">totalStaked<\/span><span style=\"color: #D4D4D4\"> -= <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">totalRewardsDistributed<\/span><span style=\"color: #D4D4D4\"> += <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\">\/\/ Ensure contract has enough balance<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">balanceOf<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #DCDCAA\">address<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">this<\/span><span style=\"color: #D4D4D4\">)) &gt;= <\/span><span style=\"color: #9CDCFE\">totalAmount<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;Insufficient contract balance&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">transfer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">totalAmount<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #CE9178\">&quot;Transfer failed&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">emit<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">Withdrawn<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\"> &gt; <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">emit<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">RewardPaid<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">public<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">view<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">returns<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">if<\/span><span style=\"color: #D4D4D4\"> (<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> == <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingDuration<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">block<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\"> - <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">lastRewardCalculation<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\"> = (<\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">].<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #9CDCFE\">rewardRate<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #9CDCFE\">stakingDuration<\/span><span style=\"color: #D4D4D4\">) \/ (<\/span><span style=\"color: #B5CEA8\">365<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">days<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">100<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">getStakeInfo<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">view<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">returns<\/span><span style=\"color: #D4D4D4\"> (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakedAmount<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingTime<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">pendingRewards<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    ) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">Stake<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">memory<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stake<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">stakes<\/span><span style=\"color: #D4D4D4\">[<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">];<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #C586C0\">return<\/span><span style=\"color: #D4D4D4\"> (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">stake<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #9CDCFE\">stake<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">timestamp<\/span><span style=\"color: #D4D4D4\">,<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">            <\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">_staker<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Admin functions<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">setMinimumStakingAmount<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">onlyOwner<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">_amount<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">setRewardRate<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">_rate<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">onlyOwner<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">rewardRate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">_rate<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n<\/blockquote>\n<\/blockquote>\n\n\n\n<p>Before you jump into building the front end of the staking platform we need to write one more smart contract and that would be for building our token that we will be using in the staking platform. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Write_your_token_smart_contract\"><\/span>Write your token smart contract <span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>While writing a token smart contract we will be using Openzepplin&#8217;s ERC20 framework and importing it reduces the code to merely 6-7 lines. We will be creating a Cosmic Token and then use it in our staking platform to stake, reward, and withdraw tokens.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport &quot;@openzeppelin\/contracts\/token\/ERC20\/ERC20.sol&quot;;\nimport &quot;@openzeppelin\/contracts\/access\/Ownable.sol&quot;;\n\ncontract StakingToken is ERC20, Ownable {\n    constructor() ERC20(&quot;Cosmic Token&quot;, &quot;COSMIC&quot;) {\n        \/\/ Mint initial supply to the contract deployer\n        _mint(msg.sender, 1000000 * 10**decimals());\n    }\n    \n    function mint(address to, uint256 amount) external onlyOwner {\n        _mint(to, amount);\n    }\n}\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #6A9955\">\/\/ SPDX-License-Identifier: MIT<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">pragma<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">solidity<\/span><span style=\"color: #D4D4D4\"> ^<\/span><span style=\"color: #B5CEA8\">0.8<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #B5CEA8\">0<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/token\/ERC20\/ERC20.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C586C0\">import<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #CE9178\">&quot;@openzeppelin\/contracts\/access\/Ownable.sol&quot;<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">contract<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingToken<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">is<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">ERC20<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">Ownable<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">constructor<\/span><span style=\"color: #D4D4D4\">() <\/span><span style=\"color: #DCDCAA\">ERC20<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Cosmic Token&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;COSMIC&quot;<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #6A9955\">\/\/ Mint initial supply to the contract deployer<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">_mint<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">msg<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">sender<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #B5CEA8\">1000000<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">10<\/span><span style=\"color: #D4D4D4\">**<\/span><span style=\"color: #DCDCAA\">decimals<\/span><span style=\"color: #D4D4D4\">());<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">mint<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">uint256<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #DCDCAA\">external<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">onlyOwner<\/span><span style=\"color: #D4D4D4\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #DCDCAA\">_mint<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>If you are an absolute beginner in web3 and have stumbled upon this article here are a few resources to get started with your web3 journey on Ethereum and guess what we also have a course on how to create your own tokens in 30 minutes. <\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Ethereum\"><\/span>Ethereum<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Metaschool\u2019s hands-on&nbsp;<a href=\"https:\/\/metaschool.so\/courses?blockchain=Ethereum\">Ethereum development courses<\/a>&nbsp;are offered for free. These self-paced and structured courses guide you to write Smart Contracts in Solidity, build NFTs, and teach you to&nbsp;<a href=\"https:\/\/metaschool.so\/courses\/create-your-own-ethereum-token-in-just-30-mins\">create your own Ethereum Token in 30 mins<\/a>&nbsp;with expert instruction and a guided learning environment. Developers at every stage of their learning journey will benefit from Metaschool\u2019s Ethereum blockchain track and learn to build dApps quickly.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/08\/Screenshot-2024-08-01-at-2.11.54%E2%80%AFPM.png\" alt=\"from web2 to web3\n\" class=\"wp-image-7820\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Building_the_User_Interface\"><\/span>Building the User Interface<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The smart contract is only half the battle. Users need a clean, intuitive interface to interact with our platform. Our frontend needs to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Connect to user&#8217;s wallets<\/li>\n\n\n\n<li>Display staking options clearly<\/li>\n\n\n\n<li>Show real-time reward calculations<\/li>\n\n\n\n<li>Bonus: Add a slider button to be able to choose the number of tokens you want to stake<\/li>\n<\/ol>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1395\" src=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18.png\" alt=\"Staking Platform - user interface\n\" class=\"wp-image-10408\" srcset=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18.png 2560w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18-300x163.png 300w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18-1024x558.png 1024w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18-768x418.png 768w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18-1536x837.png 1536w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18-2048x1116.png 2048w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-18-1320x719.png 1320w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Testing_our_smart_contract\"><\/span>Testing our smart contract <span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Writing test cases for our smart contract is considered to be a good practice. Unit testing involves checking individual units or components of your code to ensure they function as intended. For smart contracts, this means testing specific functions, interactions, and behaviors in a controlled environment before deploying the contract on a live blockchain. For our staking platform, we will be writing unit tests for checking edge cases like:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Basic functionality (staking, withdrawing)<\/li>\n\n\n\n<li>Edge cases (zero amounts, maximum values)<\/li>\n\n\n\n<li>Security scenarios (attack vectors)<\/li>\n\n\n\n<li>Reward calculations accuracy<\/li>\n<\/ol>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"const { expect } = require(&quot;chai&quot;);\nconst { ethers } = require(&quot;hardhat&quot;);\n\ndescribe(&quot;Staking Platform&quot;, function () {\n  let StakingToken;\n  let stakingToken;\n  let StakingPlatform;\n  let stakingPlatform;\n  let owner;\n  let addr1;\n  let addr2;\n  \n  \/\/ Helper function to move time forward\n  async function moveTime(seconds) {\n    await network.provider.send(&quot;evm_increaseTime&quot;, [seconds]);\n    await network.provider.send(&quot;evm_mine&quot;);\n  }\n\n  beforeEach(async function () {\n    \/\/ Get test accounts\n    [owner, addr1, addr2] = await ethers.getSigners();\n\n    \/\/ Deploy StakingToken\n    StakingToken = await ethers.getContractFactory(&quot;StakingToken&quot;);\n    stakingToken = await StakingToken.deploy();\n    await stakingToken.deployed();\n\n    \/\/ Deploy StakingPlatform\n    StakingPlatform = await ethers.getContractFactory(&quot;StakingPlatform&quot;);\n    stakingPlatform = await StakingPlatform.deploy(stakingToken.address);\n    await stakingPlatform.deployed();\n\n    \/\/ Transfer tokens to test accounts and staking platform\n    await stakingToken.transfer(addr1.address, ethers.utils.parseEther(&quot;1000&quot;));\n    await stakingToken.transfer(addr2.address, ethers.utils.parseEther(&quot;1000&quot;));\n    \n    \/\/ Add rewards to the staking platform\n    await stakingToken.approve(stakingPlatform.address, ethers.utils.parseEther(&quot;10000&quot;));\n    await stakingPlatform.addRewards(ethers.utils.parseEther(&quot;1000&quot;)); \/\/ Add 1000 tokens as rewards\n  });\n\n  describe(&quot;Deployment&quot;, function () {\n    it(&quot;Should set the right token address&quot;, async function () {\n      expect(await stakingPlatform.stakingToken()).to.equal(stakingToken.address);\n    });\n\n    it(&quot;Should set the right owner&quot;, async function () {\n      expect(await stakingPlatform.owner()).to.equal(owner.address);\n    });\n  });\n\n  describe(&quot;Staking&quot;, function () {\n    beforeEach(async function () {\n      \/\/ Approve staking platform to spend tokens\n      await stakingToken.connect(addr1).approve(stakingPlatform.address, ethers.utils.parseEther(&quot;1000&quot;));\n    });\n\n    it(&quot;Should allow staking above minimum amount&quot;, async function () {\n      const stakeAmount = ethers.utils.parseEther(&quot;100&quot;);\n      await expect(stakingPlatform.connect(addr1).stake(stakeAmount))\n        .to.emit(stakingPlatform, &quot;Staked&quot;)\n        .withArgs(addr1.address, stakeAmount);\n\n      const stake = await stakingPlatform.stakes(addr1.address);\n      expect(stake.amount).to.equal(stakeAmount);\n    });\n\n    it(&quot;Should reject staking below minimum amount&quot;, async function () {\n      const stakeAmount = ethers.utils.parseEther(&quot;50&quot;);\n      await expect(\n        stakingPlatform.connect(addr1).stake(stakeAmount)\n      ).to.be.revertedWith(&quot;Amount below minimum staking amount&quot;);\n    });\n  });\n\n  describe(&quot;Rewards&quot;, function () {\n    beforeEach(async function () {\n      await stakingToken.connect(addr1).approve(stakingPlatform.address, ethers.utils.parseEther(&quot;1000&quot;));\n      await stakingPlatform.connect(addr1).stake(ethers.utils.parseEther(&quot;100&quot;));\n    });\n\n    it(&quot;Should calculate rewards correctly&quot;, async function () {\n      \/\/ Move time forward by 365 days\n      await moveTime(365 * 24 * 60 * 60);\n\n      const reward = await stakingPlatform.calculateReward(addr1.address);\n      \/\/ Expected reward should be 10% of staked amount after 1 year\n      expect(reward).to.be.closeTo(\n        ethers.utils.parseEther(&quot;10&quot;), \/\/ 10% of 100 tokens\n        ethers.utils.parseEther(&quot;0.1&quot;) \/\/ Allow for small rounding differences\n      );\n    });\n\n    it(&quot;Should track total rewards distributed&quot;, async function () {\n      await moveTime(365 * 24 * 60 * 60);\n      await stakingPlatform.connect(addr1).withdraw(ethers.utils.parseEther(&quot;100&quot;));\n      \n      expect(await stakingPlatform.totalRewardsDistributed()).to.be.closeTo(\n        ethers.utils.parseEther(&quot;10&quot;),\n        ethers.utils.parseEther(&quot;0.1&quot;)\n      );\n    });\n  });\n\n  describe(&quot;Withdrawals&quot;, function () {\n    beforeEach(async function () {\n      await stakingToken.connect(addr1).approve(stakingPlatform.address, ethers.utils.parseEther(&quot;1000&quot;));\n      await stakingPlatform.connect(addr1).stake(ethers.utils.parseEther(&quot;100&quot;));\n    });\n\n    it(&quot;Should allow full withdrawal with rewards&quot;, async function () {\n      \/\/ Move time forward by 365 days\n      await moveTime(365 * 24 * 60 * 60);\n\n      const initialBalance = await stakingToken.balanceOf(addr1.address);\n      await stakingPlatform.connect(addr1).withdraw(ethers.utils.parseEther(&quot;100&quot;));\n      const finalBalance = await stakingToken.balanceOf(addr1.address);\n\n      \/\/ Should receive original stake plus ~10% reward\n      expect(finalBalance.sub(initialBalance)).to.be.closeTo(\n        ethers.utils.parseEther(&quot;110&quot;),\n        ethers.utils.parseEther(&quot;0.1&quot;)\n      );\n    });\n\n    it(&quot;Should prevent withdrawal of more than staked amount&quot;, async function () {\n      await expect(\n        stakingPlatform.connect(addr1).withdraw(ethers.utils.parseEther(&quot;200&quot;))\n      ).to.be.revertedWith(&quot;Insufficient staked amount&quot;);\n    });\n\n    it(&quot;Should fail if contract has insufficient balance&quot;, async function () {\n      \/\/ Deploy new instance without rewards\n      const newStakingPlatform = await StakingPlatform.deploy(stakingToken.address);\n      await stakingToken.connect(addr1).approve(newStakingPlatform.address, ethers.utils.parseEther(&quot;1000&quot;));\n      await newStakingPlatform.connect(addr1).stake(ethers.utils.parseEther(&quot;100&quot;));\n      \n      await moveTime(365 * 24 * 60 * 60);\n      \n      await expect(\n        newStakingPlatform.connect(addr1).withdraw(ethers.utils.parseEther(&quot;100&quot;))\n      ).to.be.revertedWith(&quot;Insufficient contract balance&quot;);\n    });\n  });\n\n  describe(&quot;Admin Functions&quot;, function () {\n    it(&quot;Should allow owner to change minimum staking amount&quot;, async function () {\n      const newMinimum = ethers.utils.parseEther(&quot;200&quot;);\n      await stakingPlatform.connect(owner).setMinimumStakingAmount(newMinimum);\n      expect(await stakingPlatform.minimumStakingAmount()).to.equal(newMinimum);\n    });\n\n    it(&quot;Should allow owner to change reward rate&quot;, async function () {\n      const newRate = 20; \/\/ 20% APR\n      await stakingPlatform.connect(owner).setRewardRate(newRate);\n      expect(await stakingPlatform.rewardRate()).to.equal(newRate);\n    });\n\n    it(&quot;Should prevent non-owner from changing parameters&quot;, async function () {\n      await expect(\n        stakingPlatform.connect(addr1).setRewardRate(20)\n      ).to.be.revertedWith(&quot;Ownable: caller is not the owner&quot;);\n    });\n  });\n});\n\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #4FC1FF\">expect<\/span><span style=\"color: #D4D4D4\"> } = <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;chai&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> { <\/span><span style=\"color: #4FC1FF\">ethers<\/span><span style=\"color: #D4D4D4\"> } = <\/span><span style=\"color: #DCDCAA\">require<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;hardhat&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #DCDCAA\">describe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Staking Platform&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingToken<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingPlatform<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">owner<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">let<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">addr2<\/span><span style=\"color: #D4D4D4\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #6A9955\">\/\/ Helper function to move time forward<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">moveTime<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">seconds<\/span><span style=\"color: #D4D4D4\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">network<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">provider<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">send<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;evm_increaseTime&quot;<\/span><span style=\"color: #D4D4D4\">, [<\/span><span style=\"color: #9CDCFE\">seconds<\/span><span style=\"color: #D4D4D4\">]);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">network<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">provider<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">send<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;evm_mine&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  }<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">beforeEach<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Get test accounts<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    [<\/span><span style=\"color: #9CDCFE\">owner<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">addr2<\/span><span style=\"color: #D4D4D4\">] = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">getSigners<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Deploy StakingToken<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">StakingToken<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">getContractFactory<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;StakingToken&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">deploy<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">deployed<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Deploy StakingPlatform<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">StakingPlatform<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">getContractFactory<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;StakingPlatform&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">deploy<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">deployed<\/span><span style=\"color: #D4D4D4\">();<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Transfer tokens to test accounts and staking platform<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">transfer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">transfer<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr2<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #6A9955\">\/\/ Add rewards to the staking platform<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">approve<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;10000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">addRewards<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">)); <\/span><span style=\"color: #6A9955\">\/\/ Add 1000 tokens as rewards<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">describe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Deployment&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should set the right token address&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">stakingToken<\/span><span style=\"color: #D4D4D4\">()).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should set the right owner&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">owner<\/span><span style=\"color: #D4D4D4\">()).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">owner<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">describe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Staking&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">beforeEach<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #6A9955\">\/\/ Approve staking platform to spend tokens<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">approve<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should allow staking above minimum amount&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">stakeAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakeAmount<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">emit<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #CE9178\">&quot;Staked&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        .<\/span><span style=\"color: #DCDCAA\">withArgs<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">stakeAmount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">stake<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">stakes<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stake<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">amount<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakeAmount<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should reject staking below minimum amount&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">stakeAmount<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;50&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakeAmount<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      ).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">revertedWith<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Amount below minimum staking amount&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">describe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Rewards&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">beforeEach<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">approve<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should calculate rewards correctly&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #6A9955\">\/\/ Move time forward by 365 days<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">moveTime<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">365<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">24<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">reward<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">calculateReward<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #6A9955\">\/\/ Expected reward should be 10% of staked amount after 1 year<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">reward<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">closeTo<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;10&quot;<\/span><span style=\"color: #D4D4D4\">), <\/span><span style=\"color: #6A9955\">\/\/ 10% of 100 tokens<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;0.1&quot;<\/span><span style=\"color: #D4D4D4\">) <\/span><span style=\"color: #6A9955\">\/\/ Allow for small rounding differences<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should track total rewards distributed&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">moveTime<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">365<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">24<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">withdraw<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">totalRewardsDistributed<\/span><span style=\"color: #D4D4D4\">()).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">closeTo<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;10&quot;<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;0.1&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">describe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Withdrawals&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">beforeEach<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">approve<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should allow full withdrawal with rewards&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #6A9955\">\/\/ Move time forward by 365 days<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">moveTime<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">365<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">24<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">initialBalance<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">balanceOf<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">withdraw<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">finalBalance<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">balanceOf<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #6A9955\">\/\/ Should receive original stake plus ~10% reward<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">finalBalance<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">sub<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">initialBalance<\/span><span style=\"color: #D4D4D4\">)).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">closeTo<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;110&quot;<\/span><span style=\"color: #D4D4D4\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;0.1&quot;<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      );<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should prevent withdrawal of more than staked amount&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">withdraw<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;200&quot;<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      ).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">revertedWith<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Insufficient staked amount&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should fail if contract has insufficient balance&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #6A9955\">\/\/ Deploy new instance without rewards<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">newStakingPlatform<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">StakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">deploy<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingToken<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">approve<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">newStakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">address<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;1000&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">newStakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">stake<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">));<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">moveTime<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">365<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">24<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\"> * <\/span><span style=\"color: #B5CEA8\">60<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">newStakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">withdraw<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;100&quot;<\/span><span style=\"color: #D4D4D4\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      ).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">revertedWith<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Insufficient contract balance&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  <\/span><span style=\"color: #DCDCAA\">describe<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Admin Functions&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should allow owner to change minimum staking amount&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">newMinimum<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #9CDCFE\">ethers<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">utils<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">parseEther<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;200&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">owner<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">setMinimumStakingAmount<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">newMinimum<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">minimumStakingAmount<\/span><span style=\"color: #D4D4D4\">()).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">newMinimum<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should allow owner to change reward rate&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #569CD6\">const<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #4FC1FF\">newRate<\/span><span style=\"color: #D4D4D4\"> = <\/span><span style=\"color: #B5CEA8\">20<\/span><span style=\"color: #D4D4D4\">; <\/span><span style=\"color: #6A9955\">\/\/ 20% APR<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">owner<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">setRewardRate<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">newRate<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">rewardRate<\/span><span style=\"color: #D4D4D4\">()).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">equal<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">newRate<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    <\/span><span style=\"color: #DCDCAA\">it<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Should prevent non-owner from changing parameters&quot;<\/span><span style=\"color: #D4D4D4\">, <\/span><span style=\"color: #569CD6\">async<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #569CD6\">function<\/span><span style=\"color: #D4D4D4\"> () {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      <\/span><span style=\"color: #C586C0\">await<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #DCDCAA\">expect<\/span><span style=\"color: #D4D4D4\">(<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">        <\/span><span style=\"color: #9CDCFE\">stakingPlatform<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">connect<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #9CDCFE\">addr1<\/span><span style=\"color: #D4D4D4\">).<\/span><span style=\"color: #DCDCAA\">setRewardRate<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #B5CEA8\">20<\/span><span style=\"color: #D4D4D4\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">      ).<\/span><span style=\"color: #9CDCFE\">to<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">be<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #DCDCAA\">revertedWith<\/span><span style=\"color: #D4D4D4\">(<\/span><span style=\"color: #CE9178\">&quot;Ownable: caller is not the owner&quot;<\/span><span style=\"color: #D4D4D4\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">    });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">  });<\/span><\/span>\n<span class=\"line\"><span style=\"color: #D4D4D4\">});<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Deployment\"><\/span>Deployment <span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>There are multiple ways to go for deployment. You can either use RemixIDE for smart contract deployment or do it locally. In this case, we prefer to do it locally as we have to test the code working well with the the frontend of our application as well.<br>Run a local hardhat node, through which you will get multiple dummy accounts to deploy your contract. The next picture shows you the terminal output with all the accounts generated and their private keys. <\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#1E1E1E\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"npx hardhat node\nnpx hardhat run scripts\/deploy.js --network localhost\" style=\"color:#D4D4D4;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki dark-plus\" style=\"background-color: #1E1E1E\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #9CDCFE\">npx<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">hardhat<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">node<\/span><\/span>\n<span class=\"line\"><span style=\"color: #9CDCFE\">npx<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">hardhat<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">run<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">scripts<\/span><span style=\"color: #D4D4D4\">\/<\/span><span style=\"color: #9CDCFE\">deploy<\/span><span style=\"color: #D4D4D4\">.<\/span><span style=\"color: #9CDCFE\">js<\/span><span style=\"color: #D4D4D4\"> --<\/span><span style=\"color: #9CDCFE\">network<\/span><span style=\"color: #D4D4D4\"> <\/span><span style=\"color: #9CDCFE\">localhost<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"729\" src=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-19-1024x729.png\" alt=\"\" class=\"wp-image-10409\" srcset=\"https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-19-1024x729.png 1024w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-19-300x214.png 300w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-19-768x547.png 768w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-19-1320x940.png 1320w, https:\/\/metaschool.so\/articles\/wp-content\/uploads\/2024\/11\/image-19.png 1342w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Now all you need is to write integrate your smart contract and the front end and run the staking platform application to see if the code for our staking platform is working fine. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Building a staking platform is a complex but rewarding endeavor. By understanding each component thoroughly and planning carefully, we can create a secure and user-friendly platform that provides real value to users.<\/p>\n\n\n\n<p>The key to approaching any project is to layout a user flow diagram first and then think of the features to be added why each component is necessary and how it fits into the larger picture. Start small, test thoroughly, and gradually add features as you confirm each part works as intended. Remember, the goal isn&#8217;t just to build a platform that works &#8211; it&#8217;s to build one that users can trust with their assets and that provides real value to the ecosystem.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":24,"featured_media":10410,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[14],"tags":[],"class_list":["post-10390","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web3"],"_links":{"self":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts\/10390","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/users\/24"}],"replies":[{"embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/comments?post=10390"}],"version-history":[{"count":2,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts\/10390\/revisions"}],"predecessor-version":[{"id":10411,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/posts\/10390\/revisions\/10411"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/media\/10410"}],"wp:attachment":[{"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/media?parent=10390"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/categories?post=10390"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/metaschool.so\/articles\/wp-json\/wp\/v2\/tags?post=10390"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}