Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 国产亚洲精品国产福利在线观看,亚洲精品专区一区二区三区,91精品在线视频观看

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          簡單的html網(wǎng)頁(社保計算器)

          lt;!DOCTYPE html>

          <html>

          <head>

          <meta charset="UTF-8">

          <title>個人社保計算器--網(wǎng)頁版</title>

          <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>

          <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>

          <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">

          <script><!--腳本-->

          function calc(){

          //1.把用戶輸入的工資拿到

          //jQuery函數(shù)

          sal = $("#salary").val();

          //2.把sal轉(zhuǎn)成數(shù)字

          salnum = parseInt(sal);

          //3.開始計算

          //3.1 算各種數(shù)據(jù)

          ylgr = salnum * 0.08;

          ylgs = salnum * 0.2;

          ybgr = salnum * 0.02;

          ybgs = salnum * 0.06;

          sygr = salnum * 0.0005;

          sygs = salnum * 0.0015;

          gsgs = salnum * 0.0005;

          sybx = salnum * 0.0008;

          gjjgr = salnum * 0.12;

          gjjgs = salnum * 0.12;

          grhj = ylgr+ybgr+sygr+gjjgr;

          gshj = ylgs+ybgs+sygs+gsgs+sybx+gjjgs;

          total = grhj+gshj;

          //4.把計算結(jié)果放到格子里

          $("#ylgr").text(ylgr);

          $("#ylgs").text(ylgs);

          $("#ybgr").text(ybgr);

          $("#ybgs").text(ybgs);

          $("#sygr").text(sygr);

          $("#sygs").text(sygs);

          $("#gsgs").text(gsgs);

          $("#sybx").text(sybx);

          $("#gjjgr").text(gjjgr);

          $("#gjjgs").text(gjjgs);

          $("#grhj").text(grhj);

          $("#gshj").text(gshj);

          $("#total").text(total);


          }

          </script>

          </head>

          <body>

          <div class="container text-center">

          <h1>個人社保計算器</h1>

          <table class="table table-bordered">

          <tr>

          <td>工資</td>

          <td colspan="3">

          <input id="salary" class="form-control" placeholder="請輸入工資" type="text" >

          </td>

          <td>

          <button onclick="calc()" class="btn btn-danger btn-block">計算</button>

          </td>

          </tr>

          <tr class="bg-primary">

          <td>險種</td>

          <td>個人%</td>

          <td>個人</td>

          <td>公司%</td>

          <td>公司</td>

          </tr>

          <tr>

          <td>養(yǎng)老</td>

          <td>8%</td>

          <td id="ylgr"></td>

          <td>20%</td>

          <td id="ylgs"></td>

          </tr>

          <tr>

          <td>醫(yī)保</td>

          <td>2%</td>

          <td id="ybgr"></td>

          <td>6%</td>

          <td id="ybgs"></td>

          </tr>

          <tr>

          <td>失業(yè)</td>

          <td>0.5%</td>

          <td id="sygr"></td>

          <td>1.5%</td>

          <td id="sygs"></td>

          </tr>

          <tr>

          <td>工傷</td>

          <td></td>

          <td></td>

          <td>0.5%</td>

          <td id="gsgs"></td>

          </tr>

          <tr>

          <td>生育</td>

          <td></td>

          <td></td>

          <td>0.8%</td>

          <td id="sybx"></td>

          </tr>

          <tr>

          <td>公積金</td>

          <td>12%</td>

          <td id="gjjgr"></td>

          <td>12%</td>

          <td id="gjjgs"></td>

          </tr>

          <tr>

          <td>合計</td>

          <td>個人合計</td>

          <td id="grhj"></td>

          <td>公司合計</td>

          <td id="gshj"></td>

          </tr>

          <tr>

          <td>總額</td>

          <td colspan="4" id="total"></td>

          </tr>

          </table>

          開發(fā)者:一字賭團隊2021

          </div>

          </body>

          </html>

          本教程中,您將學(xué)習如何開發(fā)一個具有利息累加、削減和存款/取款功能的簡單質(zhì).押. DApp。

          在過去課程中,我們學(xué)習了很多不同的Solidity和Javascript原語,這些原語為我們提供了Web3開發(fā)的基本構(gòu)件。

          我們學(xué)會了如何從頭開始使用Hardhat,建立我們自己的前臺,甚至編寫Solidity。

          雖然所有這些技能對于希望建立堅實基礎(chǔ)的開發(fā)者來說都是非常有價值的,但也有一些工具可以幫助抽象出一些復(fù)雜的環(huán)境設(shè)置和依賴關(guān)系,使構(gòu)建者可以更容易地進行修補

          我們推薦的這些工具之一是Scaffold-eth[1]!

          Scaffold-eth的核心是為以太坊上的快速原型開發(fā)提供了一個現(xiàn)成的堆棧,使開發(fā)者能夠獲得最先進的工具來快速學(xué)習/交付基于以太坊的dApp。

          使用Scaffold-eth和Alchemy,你可以輕松地在區(qū)塊鏈上合成和部署代碼。

          在本教程中,我們將使用SpeedRunEthereum[2] Challenge #1[3]的基礎(chǔ)代碼,并且共同構(gòu)建一個簡單的質(zhì).押. dApp。

          如果你不熟悉加密貨幣質(zhì).押.,它最好被概括為將持有的加密貨幣鎖定/存入DeFi協(xié)議或智能合約以獲得利息的過程。

          質(zhì).押.加密貨幣已成為許多DeFi協(xié)議的基石,并允許開發(fā)人員創(chuàng)建復(fù)雜的金融衍生產(chǎn)品。

          雖然大多數(shù)DeFi質(zhì).押.合同都非常復(fù)雜,但我們將通過一個最基本的合同來學(xué)習關(guān)鍵概念。

          我們將一起學(xué)習以下有關(guān)質(zhì).押.的構(gòu)件。

          1. 用Scaffold-Eth構(gòu)建:? 一起破解前端 ? 打造 Solidity “后端”
          2. 將ETH從錢包轉(zhuǎn)移到智能合約,反之亦然
          3. 利用Solidity修改器

          讓我們從了解Scaffold-Eth的工作原理開始吧!

          1. 下載Scaffold-Eth

          在本教程中,我們將使用Scaffold-Eth開發(fā)者環(huán)境來制作我們的智能合約,并將我們的前端UI放在一起。

          在開始之前,我想傳達幾個重要的細節(jié),讓大家牢記在心!

          Scaffold-Eth在抽象化環(huán)境設(shè)置和前端依賴方面非常棒,這使它成為一個強大的工具。

          雖然有很多功能是由Scaffold-Eth自動處理的,但當你對整個開發(fā)者環(huán)境有了更扎實的掌握后,深入到代碼中去了解其中一些功能是如何產(chǎn)生的,這一點很重要。

          讓我們從Fork SpeedRunEthereum[4]Challenge #1[5] 的基礎(chǔ)代碼庫開始。

          git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git challenge-1-decentralized-staking
          
          cd challenge-1-decentralized-staking
          
          git checkout challenge-1-decentralized-staking
          
          yarn install

          如果你已經(jīng)成功跟上,你將能夠在你的基礎(chǔ)文件目錄中出現(xiàn)一個名為challenge-1-decentralized-staking的新文件夾。

          在運行上述命令后,我們留下了一個充滿文件的大文件夾。

          即使在繼續(xù)學(xué)習代碼之前,我們也應(yīng)該熟悉Scaffold-Eth中關(guān)鍵文件的存儲位置,這樣我們就知道應(yīng)該把重點放在哪里。

          在本教程中,我們將主要在Staker.solApp.jsx上工作。

          2. 設(shè)置你的環(huán)境

          接下來,你需要為以下三個命令建立三個獨立的終端。

          啟動你的React前端。

          yarn start

          啟動你的Hardhat后端。

          yarn chain

          編譯、部署和發(fā)布你的package/contracts文件中的所有合同。

          yarn deploy

          每當你更新你的合同時,運行yarn deploy --reset來 "刷新 "Scaffold-Eth中的合同。

          很好! 現(xiàn)在你應(yīng)該可以在http://localhost:3000/,看到這個倉庫的UI前臺了。

          3. 熟悉Scaffold-Eth

          雖然我知道你很想開始寫代碼,但還有一些細節(jié)需要處理

          在我們的默認視圖中,我們有兩個標簽--Staker UI & Debug Contracts。

          來吧,在你的前端頁面上來回切換,看看不同的功能。

          Staker UI包含了所有我們將主要與之互動的前端組件。

          如果你點擊所提供的按鈕,你會發(fā)現(xiàn)大多數(shù)按鈕還沒有完全連接起來,你會立即遇到錯誤。

          看一下Staker UI。你會注意到它是如此的簡陋的! 這就是我們主要要改變的東西。

          由于以太坊上的任何鏈上互動都需要testnet ETH,所以你需要本地testnet ETH來開始砍價。

          首先,抓住你的本地主機錢包地址。

          點擊右上角的 "復(fù)制 "按鈕。

          接下來,前往左下角。你將能夠在這里訪問本地龍頭。

          • ? 要么在打開的字段中復(fù)制/粘貼你的地址,要么點擊 "錢包 "圖標
          • ? 在擴展視圖中粘貼您的地址
          • ? 給自己發(fā)送一些測試ETH

          在為你的本地錢包充值后,你就可以與你的合約進行互動了

          第二個標簽,Debug Contracts,是另一個前端顯示,它包含了Scaffold-Eth的一個超級大功能!在這個標簽中,你可以看到你的合同。

          一旦你yarn deploy你的合約,并配置它正確地讀取合約數(shù)據(jù),它將自動生成一個裸露的UI,允許你與你的合約功能互動。

          例如,在下面的例子中,我們可以通過我們的智能合約讀取和寫入信息,只需放入?yún)?shù)并點擊 "發(fā)送"。有了Scaffold-Eth,我們不需要只使用CLI命令,而是有一個更直觀的原型設(shè)計方式。

          如果你想在Debug Contracts 標簽頁中存儲和查看一個變量,請確保將該變量設(shè)置為public!

          棒極了!

          現(xiàn)在我們已經(jīng)熟悉了Scaffold-Eth,我們可以更深入地研究代碼了。

          4. 潛入Solidity

          看一下我們的Staker.sol文件,我們發(fā)現(xiàn)我們有一個相當空的Solidity文件,里面有一堆注釋,說明需要填寫的內(nèi)容。

          由于教程偏離了Scaffold-Eth的 Challenge #1,我們可以忽略這些注釋,從以下代碼開始。

          pragma solidity >=0.6.0 <0.7.0;
          
          import "hardhat/console.sol";
          import "./ExampleExternalContract.sol";
          
          contract Staker {
            ExampleExternalContract public exampleExternalContract;
            
            constructor(address exampleExternalContractAddress) public {
                exampleExternalContract = ExampleExternalContract(exampleExternalContractAddress);
            }
            
          }

          項目參數(shù)

          在寫出我們的智能合約代碼之前,讓我們來看看我們期望我們的質(zhì).押.DApp如何工作

          1. 1. 為了簡單起見,我們只希望有一個用戶與我們的質(zhì).押.DApp互動
          2. 2. 我們需要能夠從Staker合約中存款和取款。? 質(zhì).押.是一個一次性的行為,這意味著一旦我們質(zhì).押.,就不能再重新質(zhì).押.。? 從合約中取款會移除整個本金余額和任何應(yīng)計利息
          3. 3. Staker合約的利息支付率為每秒鐘0.1個ETH,存入的ETH有資格獲得利息累積。
          4. 4. 合同部署后,Staker合同應(yīng)該從Hh2時間戳計數(shù)器開始。第一個期限應(yīng)設(shè)置為2分鐘,第二個期限設(shè)置為4分鐘? 2分鐘的期限決定了釘子戶能夠存入資金的時期。(在t=0分鐘和t=2分鐘之間,質(zhì).押.用戶可以存款)? 從存入資金到2分鐘期限之間發(fā)生的所有區(qū)塊都是有效的應(yīng)計利息。? 在2分鐘的提款期限過后,質(zhì).押.用戶可以提取全部本金余額和任何應(yīng)計利息,直到4分鐘的期限到來。? 在額外的2分鐘提款窗口過后,用戶被阻止提取他們的資金,因為他們已經(jīng)超時了。
          5. 5. 如果質(zhì).押.用戶還有資金,我們可以調(diào)用最后一個函數(shù),將資金 "鎖定 "在已經(jīng)預(yù)裝在Scaffold-Eth環(huán)境中的外部合同中,即ExampleExternalContract.sol。

          雖然上面列出的質(zhì).押.參數(shù)可能看起來有點復(fù)雜,但許多現(xiàn)實生活中的質(zhì).押.dApps都有類似的基元,用戶有一個有限的存款和提款期。

          而且,許多DApps將抑制 "非生產(chǎn)性 "資本,這些資本在質(zhì).押.期結(jié)束后只是閑置在那里。

          有時,DeFi協(xié)議甚至可能在等待期結(jié)束后吸收未付的存款,這與我們在教程中所說的最后一個參數(shù)類似。

          Solidity Mappingss

          在我們的智能合約中,我們將需要兩個映射來幫助我們存儲一些數(shù)據(jù)。

          特別是,我們需要一些東西來跟蹤。

          1. 1. 有多少ETH被存入合約中
          2. 2. 存款發(fā)生的時間

          我們可以通過以下方式實現(xiàn)這一目標。

          mapping(address => uint256) public balances; 
          mapping(address => uint256) public depositTimestamps;

          公共變量

          根據(jù)上面列出的準則[6],我們還需要一些不同的變量。

          uint256 public constant rewardRatePerSecond = 0.1 ether; 
          uint256 public withdrawalDeadline = block.timestamp + 120 seconds; 
          uint256 public claimDeadline = block.timestamp + 240 seconds; 
          uint256 public currentBlock = 0;

          獎勵率設(shè)定了質(zhì).押.本金的ETH的發(fā)放利率。

          提款和索賠的最后期限幫助我們設(shè)定質(zhì).押.機制開始/結(jié)束的最后期限。

          最后,我們有一個變量,用來保存當前區(qū)塊。

          我們使用block.timestamp + XXX seconds來創(chuàng)建最后期限,正好是我們的合約啟動后的XXX秒。作為一種計時機制,這肯定有點 "天真";你能想出更好的方法來實現(xiàn)這一點,例如,它更具有通用性?

          事件

          盡管我們不會將事件推送到我們的前端,但我們?nèi)匀粦?yīng)該確保我們在合同的關(guān)鍵部分發(fā)出事件,以確保我們保持最佳的編程實踐。

          event Stake(address indexed sender, uint256 amount); 
          event Received(address, uint); 
          event Execute(address indexed sender, uint256 amount);

          現(xiàn)在我們已經(jīng)鎖定了關(guān)鍵參數(shù)/變量,我們可以繼續(xù)制作我們將在教程中使用的具體函數(shù)。

          只讀的時間函數(shù)

          正如項目參數(shù)中所述,許多不同的質(zhì).押.DApp的功能都受制于 "時間鎖",在特定的時間點啟用/禁止某些行動。

          在這里,我們有兩個不同的功能來管理提款窗口的開始和結(jié)束。

            function withdrawalTimeLeft() public view returns (uint256 withdrawalTimeLeft) {
              if( block.timestamp >= withdrawalDeadline) {
                return (0);
              } else {
                return (withdrawalDeadline - block.timestamp);
              }
            }
          
            function claimPeriodLeft() public view returns (uint256 claimPeriodLeft) {
              if( block.timestamp >= claimDeadline) {
                return (0);
              } else {
                return (claimDeadline - block.timestamp);
              }
            }

          這兩個函數(shù)在設(shè)計上其實都非常熟悉。

          它們都有一個標準的if -> else語句。

          條件只是檢查當前時間是否大于或小于公共變量部分[7]規(guī)定的最后期限。

          如果當前時間大于預(yù)先安排的最后期限,我們就知道最后期限已過,并返回0以表示 "狀態(tài)變化 "已經(jīng)發(fā)生。

          否則,我們只是返回在最后期限到來之前的剩余時間。

          修改器

          對于一個更深入的修改器的例子,請看 Solidity By Example[8]

          簡而言之,Solidity 修改器是可以在函數(shù)調(diào)用之前和/或之后運行的代碼片段。

          雖然它們有許多不同的用途,但最常見和最基本的用例之一是在特定條件未完全滿足的情況下限制對某些功能的訪問。

          在本教程中,我們將精確地使用修改器來幫助對關(guān)鍵功能進行把關(guān),這些功能決定了我們的入股、提款和返還功能。

          下面是我們使用的三個修改器。

            modifier withdrawalDeadlineReached( bool requireReached ) {
              uint256 timeRemaining = withdrawalTimeLeft();
              if( requireReached ) {
                require(timeRemaining == 0, "Withdrawal period is not reached yet");
              } else {
                require(timeRemaining > 0, "Withdrawal period has been reached");
              }
              _;
            }
          
            modifier claimDeadlineReached( bool requireReached ) {
              uint256 timeRemaining = claimPeriodLeft();
              if( requireReached ) {
                require(timeRemaining == 0, "Claim deadline is not reached yet");
              } else {
                require(timeRemaining > 0, "Claim deadline has been reached");
              }
              _;
            }
          
            modifier notCompleted() {
              bool completed = exampleExternalContract.completed();
              require(!completed, "Stake already completed!");
              _;
            }

          修改器 withdrawalDeadlineReached(bool requireReached) &claimDeadlineReached(bool requireReached)都接受一個布爾參數(shù),并檢查以確保其各自的最后期限為真或假。

          修改器notCompleted()的操作方式類似,但實際上它的性質(zhì)更復(fù)雜一點,盡管它包含的代碼行數(shù)更少。

          它實際上是從Staker外部的合同中調(diào)用一個函數(shù) completed(),并檢查它的返回值是真還是假,以確認該標志是否被切換。

          現(xiàn)在,讓我們在接下來的幾個函數(shù)上實現(xiàn)我們剛剛創(chuàng)建的修改器,用閘門限制訪問。

          存款/質(zhì).押.功能

          在我們的入金函數(shù)中,我們使用先前創(chuàng)建的修改器,將withdrawingDeadlineReached()中的參數(shù)設(shè)置為false,將claimDeadlineReached()設(shè)置為false,因為我們不希望這兩個期限已經(jīng)過去。

            // Stake function for a user to stake ETH in our contract
            
            function stake() public payable withdrawalDeadlineReached(false) claimDeadlineReached(false) {
              balances[msg.sender] = balances[msg.sender] + msg.value;
              depositTimestamps[msg.sender] = block.timestamp;
              emit Stake(msg.sender, msg.value);
            }

          該函數(shù)的其余部分在一個典型的 "存款 "場景中是相當標準的,我們的余額映射被更新以包括送入的資金。

          我們還用存款的當前時間來設(shè)置我們的存款時間戳,這樣我們就可以在以后的利息計算中訪問這個存儲值。

          提款功能

          在我們的取款函數(shù)中,我們再次使用先前創(chuàng)建的修改器,但這次我們希望drawalDeadlineReached()為真, claimDeadlineReached()為假。

          這組修改器/參數(shù)意味著我們處于提款窗口的最佳位置,因為提款時間到了,不會有任何處罰,而且我們還能得到利息。

            /*
            Withdraw function for a user to remove their staked ETH inclusive
            of both the principle balance and any accrued interest
            */
            
            function withdraw() public withdrawalDeadlineReached(true) claimDeadlineReached(false) notCompleted{
              require(balances[msg.sender] > 0, "You have no balance to withdraw!");
              uint256 individualBalance = balances[msg.sender];
              uint256 indBalanceRewards = individualBalance + ((block.timestamp-depositTimestamps[msg.sender])*rewardRatePerBlock);
              balances[msg.sender] = 0;
          
              // Transfer all ETH via call! (not transfer) cc: https://solidity-by-example.org/sending-ether
              (bool sent, bytes memory data) = msg.sender.call{value: indBalanceRewards}("");
              require(sent, "RIP; withdrawal failed :( ");
            }

          該函數(shù)的其余部分做了幾個重要步驟。

          1. 1. 它檢查以確保試圖提取ETH的人實際上有一個非零的股份。
          2. 2. 它通過計算從存款到取款的區(qū)塊數(shù),并乘以我們的利息常數(shù),來計算欠下的ETH的利息金額。
          3. 3. 它將用戶的余額質(zhì).押.ETH設(shè)為0,這樣就不會發(fā)生重復(fù)計算。
          4. 4. 它將ETH從智能合約轉(zhuǎn)移回用戶的錢包。

          執(zhí)行返還功能

          在這里,我們希望 claimDeadlineReached() 為真,因為非生產(chǎn)性資金的返還只能在4分鐘后發(fā)生。

          同樣地,我們希望notCompleted為真,因為這個DApp只設(shè)計為單一用途。

            /*
            Allows any user to repatriate "unproductive" funds that are left in the staking contract
            past the defined withdrawal period
            */
            
            function execute() public claimDeadlineReached(true) notCompleted {
              uint256 contractBalance = address(this).balance;
              exampleExternalContract.complete{value: address(this).balance}();
            }

          其余的功能。

          1. 1. 抓取Staker合約中的ETH的當前余額
          2. 2. 將ETH發(fā)送到repo的exampleExternalContract中。

          如果你到目前為止一直跟著Solidity走,你的Staker.sol應(yīng)該是下面這個樣子。

          // SPDX-License-Identifier: MIT
          pragma solidity 0.8.4;
          
          import "hardhat/console.sol";
          import "./ExampleExternalContract.sol";
          
          contract Staker {
          
            ExampleExternalContract public exampleExternalContract;
          
            mapping(address => uint256) public balances;
            mapping(address => uint256) public depositTimestamps;
          
            uint256 public constant rewardRatePerSecond = 0.1 ether;
            uint256 public withdrawalDeadline = block.timestamp + 120 seconds;
            uint256 public claimDeadline = block.timestamp + 240 seconds;
            uint256 public currentBlock = 0;
          
            // Events
            event Stake(address indexed sender, uint256 amount);
            event Received(address, uint);
            event Execute(address indexed sender, uint256 amount);
          
            // Modifiers
            /*
            Checks if the withdrawal period has been reached or not
            */
            modifier withdrawalDeadlineReached( bool requireReached ) {
              uint256 timeRemaining = withdrawalTimeLeft();
              if( requireReached ) {
                require(timeRemaining == 0, "Withdrawal period is not reached yet");
              } else {
                require(timeRemaining > 0, "Withdrawal period has been reached");
              }
              _;
            }
          
            /*
            Checks if the claim period has ended or not
            */
            modifier claimDeadlineReached( bool requireReached ) {
              uint256 timeRemaining = claimPeriodLeft();
              if( requireReached ) {
                require(timeRemaining == 0, "Claim deadline is not reached yet");
              } else {
                require(timeRemaining > 0, "Claim deadline has been reached");
              }
              _;
            }
          
            /*
            Requires that the contract only be completed once!
            */
            modifier notCompleted() {
              bool completed = exampleExternalContract.completed();
              require(!completed, "Stake already completed!");
              _;
            }
          
            constructor(address exampleExternalContractAddress){
                exampleExternalContract = ExampleExternalContract(exampleExternalContractAddress);
            }
          
            // Stake function for a user to stake ETH in our contract
            function stake() public payable withdrawalDeadlineReached(false) claimDeadlineReached(false){
              balances[msg.sender] = balances[msg.sender] + msg.value;
              depositTimestamps[msg.sender] = block.timestamp;
              emit Stake(msg.sender, msg.value);
            }
          
            /*
            Withdraw function for a user to remove their staked ETH inclusive
            of both principal and any accrued interest
            */
            function withdraw() public withdrawalDeadlineReached(true) claimDeadlineReached(false) notCompleted{
              require(balances[msg.sender] > 0, "You have no balance to withdraw!");
              uint256 individualBalance = balances[msg.sender];
              uint256 indBalanceRewards = individualBalance + ((block.timestamp-depositTimestamps[msg.sender])*rewardRatePerBlock);
              balances[msg.sender] = 0;
          
              // Transfer all ETH via call! (not transfer) cc: https://solidity-by-example.org/sending-ether
              (bool sent, bytes memory data) = msg.sender.call{value: indBalanceRewards}("");
              require(sent, "RIP; withdrawal failed :( ");
            }
          
            /*
            Allows any user to repatriate "unproductive" funds that are left in the staking contract
            past the defined withdrawal period
            */
            function execute() public claimDeadlineReached(true) notCompleted {
              uint256 contractBalance = address(this).balance;
              exampleExternalContract.complete{value: address(this).balance}();
            }
          
            /*
            READ-ONLY function to calculate the time remaining before the minimum staking period has passed
            */
            function withdrawalTimeLeft() public view returns (uint256 withdrawalTimeLeft) {
              if( block.timestamp >= withdrawalDeadline) {
                return (0);
              } else {
                return (withdrawalDeadline - block.timestamp);
              }
            }
          
            /*
            READ-ONLY function to calculate the time remaining before the minimum staking period has passed
            */
            function claimPeriodLeft() public view returns (uint256 claimPeriodLeft) {
              if( block.timestamp >= claimDeadline) {
                return (0);
              } else {
                return (claimDeadline - block.timestamp);
              }
            }
          
            /*
            Time to "kill-time" on our local testnet
            */
            function killTime() public {
              currentBlock = block.timestamp;
            }
          
            /*
            \Function for our smart contract to receive ETH
            cc: https://docs.soliditylang.org/en/latest/contracts.html#receive-ether-function
            */
            receive() external payable {
                emit Received(msg.sender, msg.value);
            }
          
          }
          

          5. 進入前臺

          太棒了! 我們剛剛經(jīng)歷了一堆Solidity。當涉及到前端顯示時,Scaffold-Eth試圖讓事情變得簡單而美好。它包含了很多不同的反應(yīng)組件,為用戶提供了低代碼的解決方案,以實現(xiàn)令人敬畏的UI!我鼓勵你玩玩這些組件。我鼓勵你玩玩不同的組件,但與此同時,我們將在spartan方面學(xué)習更多。

          看看我們的App.jsx文件,特別是在鏈接573附近的代碼塊[9],我們看到一個代碼塊,用于從我們的Solidity合約中捕獲發(fā)射的事件,并將其顯示為一個列表。

          有效地,它允許我們記錄從我們的智能合約發(fā)射的不同行動,解析存儲的信息,然后直觀地允許dApp用戶查看他們的鏈上歷史。

          雖然我們將通過在Solidity合約中發(fā)射事件來實踐良好的編程標準,但這次,為了簡單起見,我們將在前端忽略事件,所以讓我們完全刪除這個代碼塊。

          如果你看一下你的Staker UI標簽,你會發(fā)現(xiàn)事件框已經(jīng)被抹去了。

          前臺編輯

          在大多數(shù)情況下,前臺的許多代碼將保持與默認的相同 在前面的步驟中,我們已經(jīng)刪除了事件反應(yīng)組件。

          我們的最終目標是要有一個漂亮的、簡單的用戶界面,看起來像下面這樣。

          請注意,默認的前臺缺少一些默認 repo 的視覺元素。

          每秒獎勵率

          為了構(gòu)建這部分內(nèi)容,我們在Staker合同塊下直接插入以下代碼。

            <div style={{ padding: 8, marginTop: 16 }}>
              <div>Reward Rate Per Second:</div>
              <Balance balance={rewardRatePerSecond} fontSize={64} /> ETH
            </div>

          在這里,我們利用了Scaffold-Eth的平衡反應(yīng)組件來幫助格式化!

          最后期限的UI元素

          為了構(gòu)建截止日期視覺組件,我們使用了以下2段代碼。

            // ** keep track of a variable from the contract in the local React state:
            const claimPeriodLeft = useContractReader(readContracts, "Staker", "claimPeriodLeft");
            console.log("? Claim Period Left:", claimPeriodLeft);
          
            const withdrawalTimeLeft = useContractReader(readContracts, "Staker", "withdrawalTimeLeft");
            console.log("? Withdrawal Time Left:", withdrawalTimeLeft);
          <div style={{ padding: 8, marginTop: 16, fontWeight: "bold" }}>
            <div>Claim Period Left:</div>
            {claimPeriodLeft && humanizeDuration(claimPeriodLeft.toNumber() * 1000)}
          </div>
          
          <div style={{ padding: 8, marginTop: 16, fontWeight: "bold"}}>
            <div>Withdrawal Period Left:</div>
            {withdrawalTimeLeft && humanizeDuration(withdrawalTimeLeft.toNumber() * 1000)}
          </div>

          雖然第二個代碼片斷很熟悉,與我們已經(jīng)看到的相似,但第一個代碼塊有點獨特。不是說我們調(diào)用 claimPeriodLeft withdrawalTimeLeft來訪問前端的存儲變量值。

          然而,我們實際上必須先從智能合約中讀取這些值本身。第一個代碼片斷處理了這個邏輯!

          雜項:對其他現(xiàn)有的UI組件的編輯

          現(xiàn)在你已經(jīng)看到了2個不同的前臺UI組件的例子,你能想出如何對前臺進行其余的修改,使其看起來像上面提供的樣本嗎?。?/span>

          你應(yīng)該只需要在這里調(diào)整一些參數(shù),所以不要想得太多了

          對用戶界面的自由發(fā)揮

          雖然Scaffold-Eth有很多默認組件,使用戶能夠簡單地利用 "低代碼 "解決方案,但它也使用戶能夠訪問更大的前端庫。

          默認情況下,它有一個與Ant Design react components(https://ant.design/components/overview/)的掛鉤,允許任何人從那里提取組件

          在我們的前端樣本中,我們實際上看到了 "線 "來劃分每個大塊的視覺組件。

          通過探索Ant Design中的不同選項,可以重現(xiàn)這些線條

          如果你想得到提示,請看一下Ant Dividers!

          不要忘記,我們需要在App.jsx文件的頂部導(dǎo)入我們計劃使用的組件

          從 "antd "導(dǎo)入 { Alert, Button, Col, Menu, Row, List, Divider }。

          如果你已經(jīng)跟上了前端的代碼,你的App.jsx應(yīng)該看起來像下面這樣。

          import WalletConnectProvider from "@walletconnect/web3-provider";
          //import Torus from "@toruslabs/torus-embed"
          import WalletLink from "walletlink";
          import { Alert, Button, Col, Menu, Row, List, Divider } from "antd";
          import "antd/dist/antd.css";
          import React, { useCallback, useEffect, useState } from "react";
          import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
          import Web3Modal from "web3modal";
          import "./App.css";
          import { Account, Address, Balance, Contract, Faucet, GasGauge, Header, Ramp, ThemeSwitch } from "./components";
          import { INFURA_ID, NETWORK, NETWORKS } from "./constants";
          import { Transactor } from "./helpers";
          import {
            useBalance,
            useContractLoader,
            useContractReader,
            useGasPrice,
            useOnBlock,
            useUserProviderAndSigner,
          } from "eth-hooks";
          import { useEventListener } from "eth-hooks/events/useEventListener";
          import { useExchangeEthPrice } from "eth-hooks/dapps/dex";
          // import Hints from "./Hints";
          import { ExampleUI, Hints, Subgraph } from "./views";
          
          import { useContractConfig } from "./hooks";
          import Portis from "@portis/web3";
          import Fortmatic from "fortmatic";
          import Authereum from "authereum";
          import humanizeDuration from "humanize-duration";
          
          const { ethers } = require("ethers");
          /*
              Welcome to  scaffold-eth !
          
              Code:
              https://github.com/austintgriffith/scaffold-eth
          
              Support:
              https://t.me/joinchat/KByvmRe5wkR-8F_zz6AjpA
              or DM @austingriffith on Twitter or Telegram
          
              You should get your own Infura.io ID and put it in `constants.js`
              (this is your connection to the main Ethereum network for ENS etc.)
          
          
               EXTERNAL CONTRACTS:
              You can also bring in contract artifacts in `constants.js`
              (and then use the `useExternalContractLoader()` hook!)
          */
          
          ///  What chain are your contracts deployed to?
          const targetNetwork = NETWORKS.localhost; // <------- select your target frontend network (localhost, rinkeby, xdai, mainnet)
          
          //  Sorry for all the console logging
          const DEBUG = true;
          const NETWORKCHECK = true;
          
          //  providers
          if (DEBUG) console.log(" Connecting to Mainnet Ethereum");
          // const mainnetProvider = getDefaultProvider("mainnet", { infura: INFURA_ID, etherscan: ETHERSCAN_KEY, quorum: 1 });
          // const mainnetProvider = new InfuraProvider("mainnet",INFURA_ID);
          //
          // attempt to connect to our own scaffold eth rpc and if that fails fall back to infura...
          // Using StaticJsonRpcProvider as the chainId won't change see https://github.com/ethers-io/ethers.js/issues/901
          const scaffoldEthProvider = navigator.onLine
            ? new ethers.providers.StaticJsonRpcProvider("https://rpc.scaffoldeth.io:48544")
            : null;
          const poktMainnetProvider = navigator.onLine
            ? new ethers.providers.StaticJsonRpcProvider(
                "https://eth-mainnet.gateway.pokt.network/v1/lb/611156b4a585a20035148406",
              )
            : null;
          const mainnetInfura = navigator.onLine
            ? new ethers.providers.StaticJsonRpcProvider("https://mainnet.infura.io/v3/" + INFURA_ID)
            : null;
          // ( ?? Getting "failed to meet quorum" errors? Check your INFURA_ID
          
          //  Your local provider is usually pointed at your local blockchain
          const localProviderUrl = targetNetwork.rpcUrl;
          // as you deploy to other networks you can set REACT_APP_PROVIDER=https://dai.poa.network in packages/react-app/.env
          const localProviderUrlFromEnv = process.env.REACT_APP_PROVIDER ? process.env.REACT_APP_PROVIDER : localProviderUrl;
          if (DEBUG) console.log(" Connecting to provider:", localProviderUrlFromEnv);
          const localProvider = new ethers.providers.StaticJsonRpcProvider(localProviderUrlFromEnv);
          
          //  block explorer URL
          const blockExplorer = targetNetwork.blockExplorer;
          
          // Coinbase walletLink init
          const walletLink = new WalletLink({
            appName: "coinbase",
          });
          
          // WalletLink provider
          const walletLinkProvider = walletLink.makeWeb3Provider(`https://mainnet.infura.io/v3/${INFURA_ID}`, 1);
          
          // Portis ID: 6255fb2b-58c8-433b-a2c9-62098c05ddc9
          /*
            Web3 modal helps us "connect" external wallets:
          */
          const web3Modal = new Web3Modal({
            network: "mainnet", // Optional. If using WalletConnect on xDai, change network to "xdai" and add RPC info below for xDai chain.
            cacheProvider: true, // optional
            theme: "light", // optional. Change to "dark" for a dark theme.
            providerOptions: {
              walletconnect: {
                package: WalletConnectProvider, // required
                options: {
                  bridge: "https://polygon.bridge.walletconnect.org",
                  infuraId: INFURA_ID,
                  rpc: {
                    1: `https://mainnet.infura.io/v3/${INFURA_ID}`, // mainnet // For more WalletConnect providers: https://docs.walletconnect.org/quick-start/dapps/web3-provider#required
                    42: `https://kovan.infura.io/v3/${INFURA_ID}`,
                    100: "https://dai.poa.network", // xDai
                  },
                },
              },
              portis: {
                display: {
                  logo: "https://user-images.githubusercontent.com/9419140/128913641-d025bc0c-e059-42de-a57b-422f196867ce.png",
                  name: "Portis",
                  description: "Connect to Portis App",
                },
                package: Portis,
                options: {
                  id: "6255fb2b-58c8-433b-a2c9-62098c05ddc9",
                },
              },
              fortmatic: {
                package: Fortmatic, // required
                options: {
                  key: "pk_live_5A7C91B2FC585A17", // required
                },
              },
              // torus: {
              //   package: Torus,
              //   options: {
              //     networkParams: {
              //       host: "https://localhost:8545", // optional
              //       chainId: 1337, // optional
              //       networkId: 1337 // optional
              //     },
              //     config: {
              //       buildEnv: "development" // optional
              //     },
              //   },
              // },
              "custom-walletlink": {
                display: {
                  logo: "https://play-lh.googleusercontent.com/PjoJoG27miSglVBXoXrxBSLveV6e3EeBPpNY55aiUUBM9Q1RCETKCOqdOkX2ZydqVf0",
                  name: "Coinbase",
                  description: "Connect to Coinbase Wallet (not Coinbase App)",
                },
                package: walletLinkProvider,
                connector: async (provider, _options) => {
                  await provider.enable();
                  return provider;
                },
              },
              authereum: {
                package: Authereum, // required
              },
            },
          });
          
          function App(props) {
            const mainnetProvider =
              poktMainnetProvider && poktMainnetProvider._isProvider
                ? poktMainnetProvider
                : scaffoldEthProvider && scaffoldEthProvider._network
                ? scaffoldEthProvider
                : mainnetInfura;
          
            const [injectedProvider, setInjectedProvider] = useState();
            const [address, setAddress] = useState();
          
            const logoutOfWeb3Modal = async () => {
              await web3Modal.clearCachedProvider();
              if (injectedProvider && injectedProvider.provider && typeof injectedProvider.provider.disconnect == "function") {
                await injectedProvider.provider.disconnect();
              }
              setTimeout(() => {
                window.location.reload();
              }, 1);
            };
          
            /*  This hook will get the price of ETH from  Uniswap: */
            const price = useExchangeEthPrice(targetNetwork, mainnetProvider);
          
            /*  This hook will get the price of Gas from ?? EtherGasStation */
            const gasPrice = useGasPrice(targetNetwork, "fast");
            // Use your injected provider from  Metamask or if you don't have it then instantly generate a  burner wallet.
            const userProviderAndSigner = useUserProviderAndSigner(injectedProvider, localProvider);
            const userSigner = userProviderAndSigner.signer;
          
            useEffect(() => {
              async function getAddress() {
                if (userSigner) {
                  const newAddress = await userSigner.getAddress();
                  setAddress(newAddress);
                }
              }
              getAddress();
            }, [userSigner]);
          
            // You can warn the user if you would like them to be on a specific network
            const localChainId = localProvider && localProvider._network && localProvider._network.chainId;
            const selectedChainId =
              userSigner && userSigner.provider && userSigner.provider._network && userSigner.provider._network.chainId;
          
            // For more hooks, check out eth-hooks at: https://www.npmjs.com/package/eth-hooks
          
            // The transactor wraps transactions and provides notificiations
            const tx = Transactor(userSigner, gasPrice);
          
            // Faucet Tx can be used to send funds from the faucet
            const faucetTx = Transactor(localProvider, gasPrice);
          
            //  scaffold-eth is full of handy hooks like this one to get your balance:
            const yourLocalBalance = useBalance(localProvider, address);
          
            // Just plug in different  providers to get your balance on different chains:
            const yourMainnetBalance = useBalance(mainnetProvider, address);
          
            const contractConfig = useContractConfig();
          
            // Load in your local  contract and read a value from it:
            const readContracts = useContractLoader(localProvider, contractConfig);
          
            // If you want to make  write transactions to your contracts, use the userSigner:
            const writeContracts = useContractLoader(userSigner, contractConfig, localChainId);
          
            // EXTERNAL CONTRACT EXAMPLE:
            //
            // If you want to bring in the mainnet DAI contract it would look like:
            const mainnetContracts = useContractLoader(mainnetProvider, contractConfig);
          
            // If you want to call a function on a new block
            useOnBlock(mainnetProvider, () => {
              console.log(`? A new mainnet block is here: ${mainnetProvider._lastBlockNumber}`);
            });
          
            // Then read your DAI balance like:
            const myMainnetDAIBalance = useContractReader(mainnetContracts, "DAI", "balanceOf", [
              "0x34aA3F359A9D614239015126635CE7732c18fDF3",
            ]);
          
            //keep track of contract balance to know how much has been staked total:
            const stakerContractBalance = useBalance(
              localProvider,
              readContracts && readContracts.Staker ? readContracts.Staker.address : null,
            );
            if (DEBUG) console.log(" stakerContractBalance", stakerContractBalance);
          
            const rewardRatePerSecond = useContractReader(readContracts, "Staker", "rewardRatePerSecond");
            console.log(" Reward Rate:", rewardRatePerSecond);
          
            // ** keep track of a variable from the contract in the local React state:
            const balanceStaked = useContractReader(readContracts, "Staker", "balances", [address]);
            console.log(" balanceStaked:", balanceStaked);
          
            // **  Listen for broadcast events
            const stakeEvents = useEventListener(readContracts, "Staker", "Stake", localProvider, 1);
            console.log(" stake events:", stakeEvents);
          
            const receiveEvents = useEventListener(readContracts, "Staker", "Received", localProvider, 1);
            console.log(" receive events:", receiveEvents);
          
            // ** keep track of a variable from the contract in the local React state:
            const claimPeriodLeft = useContractReader(readContracts, "Staker", "claimPeriodLeft");
            console.log("? Claim Period Left:", claimPeriodLeft);
          
            const withdrawalTimeLeft = useContractReader(readContracts, "Staker", "withdrawalTimeLeft");
            console.log("? Withdrawal Time Left:", withdrawalTimeLeft);
          
          
            // ** Listen for when the contract has been 'completed'
            const complete = useContractReader(readContracts, "ExampleExternalContract", "completed");
            console.log("? complete:", complete);
          
            const exampleExternalContractBalance = useBalance(
              localProvider,
              readContracts && readContracts.ExampleExternalContract ? readContracts.ExampleExternalContract.address : null,
            );
            if (DEBUG) console.log(" exampleExternalContractBalance", exampleExternalContractBalance);
          
            let completeDisplay = "";
            if (complete) {
              completeDisplay = (
                <div style={{padding: 64, backgroundColor: "#eeffef", fontWeight: "bold", color: "rgba(0, 0, 0, 0.85)" }} >
                  --  Staking App Fund Repatriation Executed  --
                  <Balance balance={exampleExternalContractBalance} fontSize={32} /> ETH locked!
                </div>
              );
            }
          
            /*
            const addressFromENS = useResolveName(mainnetProvider, "austingriffith.eth");
            console.log(" Resolved austingriffith.eth as:", addressFromENS)
            */
          
            //
            //  DEBUG ?
            //
            useEffect(() => {
              if (
                DEBUG &&
                mainnetProvider &&
                address &&
                selectedChainId &&
                yourLocalBalance &&
                yourMainnetBalance &&
                readContracts &&
                writeContracts &&
                mainnetContracts
              ) {
                console.log("_____________________________________  scaffold-eth _____________________________________");
                console.log(" mainnetProvider", mainnetProvider);
                console.log(" localChainId", localChainId);
                console.log("? selected address:", address);
                console.log("?♂? selectedChainId:", selectedChainId);
                console.log(" yourLocalBalance", yourLocalBalance ? ethers.utils.formatEther(yourLocalBalance) : "...");
                console.log(" yourMainnetBalance", yourMainnetBalance ? ethers.utils.formatEther(yourMainnetBalance) : "...");
                console.log(" readContracts", readContracts);
                console.log(" DAI contract on mainnet:", mainnetContracts);
                console.log(" yourMainnetDAIBalance", myMainnetDAIBalance);
                console.log(" writeContracts", writeContracts);
              }
            }, [
              mainnetProvider,
              address,
              selectedChainId,
              yourLocalBalance,
              yourMainnetBalance,
              readContracts,
              writeContracts,
              mainnetContracts,
            ]);
          
            let networkDisplay = "";
            if (NETWORKCHECK && localChainId && selectedChainId && localChainId !== selectedChainId) {
              const networkSelected = NETWORK(selectedChainId);
              const networkLocal = NETWORK(localChainId);
              if (selectedChainId === 1337 && localChainId === 31337) {
                networkDisplay = (
                  <div style={{ zIndex: 2, position: "absolute", right: 0, top: 60, padding: 16 }}>
                    <Alert
                      message="?? Wrong Network ID"
                      description={
                        <div>
                          You have <b>chain id 1337</b> for localhost and you need to change it to <b>31337</b> to work with
                          HardHat.
                          <div>(MetaMask -> Settings -> Networks -> Chain ID -> 31337)</div>
                        </div>
                      }
                      type="error"
                      closable={false}
                    />
                  </div>
                );
              } else {
                networkDisplay = (
                  <div style={{ zIndex: 2, position: "absolute", right: 0, top: 60, padding: 16 }}>
                    <Alert
                      message="?? Wrong Network"
                      description={
                        <div>
                          You have <b>{networkSelected && networkSelected.name}</b> selected and you need to be on{" "}
                          <Button
                            onClick={async () => {
                              const ethereum = window.ethereum;
                              const data = [
                                {
                                  chainId: "0x" + targetNetwork.chainId.toString(16),
                                  chainName: targetNetwork.name,
                                  nativeCurrency: targetNetwork.nativeCurrency,
                                  rpcUrls: [targetNetwork.rpcUrl],
                                  blockExplorerUrls: [targetNetwork.blockExplorer],
                                },
                              ];
                              console.log("data", data);
          
                              let switchTx;
                              // https://docs.metamask.io/guide/rpc-api.html#other-rpc-methods
                              try {
                                switchTx = await ethereum.request({
                                  method: "wallet_switchEthereumChain",
                                  params: [{ chainId: data[0].chainId }],
                                });
                              } catch (switchError) {
                                // not checking specific error code, because maybe we're not using MetaMask
                                try {
                                  switchTx = await ethereum.request({
                                    method: "wallet_addEthereumChain",
                                    params: data,
                                  });
                                } catch (addError) {
                                  // handle "add" error
                                }
                              }
          
                              if (switchTx) {
                                console.log(switchTx);
                              }
                            }}
                          >
                            <b>{networkLocal && networkLocal.name}</b>
                          </Button>
                        </div>
                      }
                      type="error"
                      closable={false}
                    />
                  </div>
                );
              }
            } else {
              networkDisplay = (
                <div style={{ zIndex: -1, position: "absolute", right: 154, top: 28, padding: 16, color: targetNetwork.color }}>
                  {targetNetwork.name}
                </div>
              );
            }
          
            const loadWeb3Modal = useCallback(async () => {
              const provider = await web3Modal.connect();
              setInjectedProvider(new ethers.providers.Web3Provider(provider));
          
              provider.on("chainChanged", chainId => {
                console.log(`chain changed to ${chainId}! updating providers`);
                setInjectedProvider(new ethers.providers.Web3Provider(provider));
              });
          
              provider.on("accountsChanged", () => {
                console.log(`account changed!`);
                setInjectedProvider(new ethers.providers.Web3Provider(provider));
              });
          
              // Subscribe to session disconnection
              provider.on("disconnect", (code, reason) => {
                console.log(code, reason);
                logoutOfWeb3Modal();
              });
            }, [setInjectedProvider]);
          
            useEffect(() => {
              if (web3Modal.cachedProvider) {
                loadWeb3Modal();
              }
            }, [loadWeb3Modal]);
          
            const [route, setRoute] = useState();
            useEffect(() => {
              setRoute(window.location.pathname);
            }, [setRoute]);
          
            let faucetHint = "";
            const faucetAvailable = localProvider && localProvider.connection && targetNetwork.name.indexOf("local") !== -1;
          
            const [faucetClicked, setFaucetClicked] = useState(false);
            if (
              !faucetClicked &&
              localProvider &&
              localProvider._network &&
              localProvider._network.chainId === 31337 &&
              yourLocalBalance &&
              ethers.utils.formatEther(yourLocalBalance) <= 0
            ) {
              faucetHint = (
                <div style={{ padding: 16 }}>
                  <Button
                    type="primary"
                    onClick={() => {
                      faucetTx({
                        to: address,
                        value: ethers.utils.parseEther("0.01"),
                      });
                      setFaucetClicked(true);
                    }}
                  >
                     Grab funds from the faucet ??
                  </Button>
                </div>
              );
            }
          
            return (
              <div className="App">
                {/* ?? Edit the header and change the title to your project name */}
                <Header />
                {networkDisplay}
                <BrowserRouter>
                  <Menu style={{ textAlign: "center" }} selectedKeys={[route]} mode="horizontal">
                    <Menu.Item key="/">
                      <Link
                        onClick={() => {
                          setRoute("/");
                        }}
                        to="/"
                      >
                        Staker UI
                      </Link>
                    </Menu.Item>
                    <Menu.Item key="/contracts">
                      <Link
                        onClick={() => {
                          setRoute("/contracts");
                        }}
                        to="/contracts"
                      >
                        Debug Contracts
                      </Link>
                    </Menu.Item>
                  </Menu>
          
                  <Switch>
                    <Route exact path="/">
                      {completeDisplay}
          
                      <div style={{ padding: 8, marginTop: 16 }}>
                        <div>Staker Contract:</div>
                        <Address value={readContracts && readContracts.Staker && readContracts.Staker.address} />
                      </div>
          
                      <Divider />
          
                      <div style={{ padding: 8, marginTop: 16 }}>
                        <div>Reward Rate Per Second:</div>
                        <Balance balance={rewardRatePerSecond} fontSize={64} /> ETH
                      </div>
          
                      <Divider />
          
                      <div style={{ padding: 8, marginTop: 16, fontWeight: "bold" }}>
                        <div>Claim Period Left:</div>
                        {claimPeriodLeft && humanizeDuration(claimPeriodLeft.toNumber() * 1000)}
                      </div>
          
                      <div style={{ padding: 8, marginTop: 16, fontWeight: "bold"}}>
                        <div>Withdrawal Period Left:</div>
                        {withdrawalTimeLeft && humanizeDuration(withdrawalTimeLeft.toNumber() * 1000)}
                      </div>
          
                      <Divider />
          
                      <div style={{ padding: 8, fontWeight: "bold"}}>
                        <div>Total Available ETH in Contract:</div>
                        <Balance balance={stakerContractBalance} fontSize={64} />
                      </div>
          
                      <Divider />
          
                      <div style={{ padding: 8,fontWeight: "bold" }}>
                        <div>ETH Locked  in Staker Contract:</div>
                        <Balance balance={balanceStaked} fontSize={64} />
                      </div>
          
                      <div style={{ padding: 8 }}>
                        <Button
                          type={"default"}
                          onClick={() => {
                            tx(writeContracts.Staker.execute());
                          }}
                        >
                           Execute!
                        </Button>
                      </div>
          
                      <div style={{ padding: 8 }}>
                        <Button
                          type={"default"}
                          onClick={() => {
                            tx(writeContracts.Staker.withdraw());
                          }}
                        >
                           Withdraw
                        </Button>
                      </div>
          
                      <div style={{ padding: 8 }}>
                        <Button
                          type={balanceStaked ? "success" : "primary"}
                          onClick={() => {
                            tx(writeContracts.Staker.stake({ value: ethers.utils.parseEther("0.5") }));
                          }}
                        >
                           Stake 0.5 ether!
                        </Button>
                      </div>
          
                      {/*
                           this scaffolding is full of commonly used components
                          this <Contract/> component will automatically parse your ABI
                          and give you a form to interact with it locally
                      */}
          
                      {/* uncomment for a second contract:
                      <Contract
                        name="SecondContract"
                        signer={userProvider.getSigner()}
                        provider={localProvider}
                        address={address}
                        blockExplorer={blockExplorer}
                        contractConfig={contractConfig}
                      />
                      */}
                    </Route>
                    <Route path="/contracts">
                      <Contract
                        name="Staker"
                        signer={userSigner}
                        provider={localProvider}
                        address={address}
                        blockExplorer={blockExplorer}
                        contractConfig={contractConfig}
                      />
                      <Contract
                        name="ExampleExternalContract"
                        signer={userSigner}
                        provider={localProvider}
                        address={address}
                        blockExplorer={blockExplorer}
                        contractConfig={contractConfig}
                      />
                    </Route>
                  </Switch>
                </BrowserRouter>
          
                <ThemeSwitch />
          
                {/* ? Your account is in the top right with a wallet at connect options */}
                <div style={{ position: "fixed", textAlign: "right", right: 0, top: 0, padding: 10 }}>
                  <Account
                    address={address}
                    localProvider={localProvider}
                    userSigner={userSigner}
                    mainnetProvider={mainnetProvider}
                    price={price}
                    web3Modal={web3Modal}
                    loadWeb3Modal={loadWeb3Modal}
                    logoutOfWeb3Modal={logoutOfWeb3Modal}
                    blockExplorer={blockExplorer}
                  />
                  {faucetHint}
                </div>
          
                <div style={{ marginTop: 32, opacity: 0.5 }}>
                  {/* Add your address here */}
                  Created by <Address value={"Your...address"} ensProvider={mainnetProvider} fontSize={16} />
                </div>
          
                <div style={{ marginTop: 32, opacity: 0.5 }}>
                  <a target="_blank" style={{ padding: 32, color: "#000" }} href="https://github.com/scaffold-eth/scaffold-eth">
                     Fork me!
                  </a>
                </div>
          
                {/*  Extra UI like gas price, eth price, faucet, and support: */}
                <div style={{ position: "fixed", textAlign: "left", left: 0, bottom: 20, padding: 10 }}>
                  <Row align="middle" gutter={[4, 4]}>
                    <Col span={8}>
                      <Ramp price={price} address={address} networks={NETWORKS} />
                    </Col>
          
                    <Col span={8} style={{ textAlign: "center", opacity: 0.8 }}>
                      <GasGauge gasPrice={gasPrice} />
                    </Col>
                    <Col span={8} style={{ textAlign: "center", opacity: 1 }}>
                      <Button
                        onClick={() => {
                          window.open("https://t.me/joinchat/KByvmRe5wkR-8F_zz6AjpA");
                        }}
                        size="large"
                        shape="round"
                      >
                        <span style={{ marginRight: 8 }} role="img" aria-label="support">
                          
                        </span>
                        Support
                      </Button>
                    </Col>
                  </Row>
          
                  <Row align="middle" gutter={[4, 4]}>
                    <Col span={24}>
                      {
                        /*  if the local provider has a signer, let's show the faucet:  */
                        faucetAvailable ? (
                          <Faucet localProvider={localProvider} price={price} ensProvider={mainnetProvider} />
                        ) : (
                          ""
                        )
                      }
                    </Col>
                  </Row>
                </div>
              </div>
            );
          }
          
          export default App;
          

          真棒!我們已經(jīng)做了很多工作。

          在開發(fā)者環(huán)境、Solidity和前端代碼方面,我們已經(jīng)一起完成了很多新的組件。

          驗證您的dApp的功能是否符合預(yù)期!

          1. 1. dApp是否具有單次使用押金的功能?
          2. 2. 提款/資金返還條件是否得到尊重?繼續(xù)點擊yarn deploy --reset幾次,檢查每個時間窗口。

          挑戰(zhàn)時間!

          好了,現(xiàn)在到了最精彩的部分。我將留給你一些擴展挑戰(zhàn),讓你自己去嘗試,看看你是否完全理解了你在這里學(xué)到的東西!

          1. 1. 更新Staker.sol合約中的利息機制,這樣你就可以根據(jù)存款和提款之間的區(qū)塊獲得 "非線性 "的ETH數(shù)額

          我建議實現(xiàn)一個基本的指數(shù)函數(shù)!

          1. 1. 允許用戶向智能合約存入任意數(shù)量的ETH,而不僅僅是0.5ETH。
          2. 2. 不要使用vanilla ExampleExternalContract合約,在Staker.sol中實現(xiàn)一個函數(shù),允許你取回鎖定在ExampleExternalContract中的ETH,并將其重新存入Staker合約中。
          • ? 請確保只有 "白名單 "中的一個地址可以調(diào)用這個新函數(shù),以控制其使用。
          • ? 確保你創(chuàng)建了邏輯/刪除了現(xiàn)有的代碼,以確保用戶能夠一次又一次地與Staker合同互動 我們希望能夠反復(fù)地從Staker -> ExampleExternalContract進行ping-pong。

          引用鏈接

          [1] Scaffold-eth: http://scaffoldeth.io/
          [2] SpeedRunEthereum:
          https://speedrunethereum.com/
          [3] Challenge #1:
          https://speedrunethereum.com/challenge/decentralized-staking
          [4] SpeedRunEthereum:
          https://speedrunethereum.com/
          [5] Challenge #1:
          https://speedrunethereum.com/challenge/decentralized-staking
          [6] 準則:
          https://docs.alchemy.com/docs/how-to-build-a-staking-dapp#project-parameters
          [7] 公共變量部分:
          https://docs.alchemy.com/docs/how-to-build-a-staking-dapp#public-variables
          [8] Solidity By Example:
          https://solidity-by-example.org/function-modifier
          [9] 鏈接573附近的代碼塊:
          https://github.com/scaffold-eth/scaffold-eth/blob/challenge-1-decentralized-staking/packages/react-app/src/App.jsx#L573

          到前端技術(shù),不少朋友一定會感到有些陌生。但其實,前端,你每天都在接觸。

          你正在使用的APP,你正在瀏覽的網(wǎng)頁,這些你能看到的界面,都屬于前端。

          而前端最重要的三大技術(shù),HTML,CSS,JavaScript,則是每一個前端開發(fā)者必須具備的技能。

          掌握這些技能,你可以快速地做出一個酷炫的APP界面或者一個簡單大方的網(wǎng)站頁面。因此,就讓我們一起來快速學(xué)習一下這三門技術(shù)吧。



          以下內(nèi)容節(jié)選自實驗樓訓(xùn)練營課程《Vue.js 和 Node.js 構(gòu)建內(nèi)容發(fā)布系統(tǒng)》。

          實驗介紹

          本實驗主要介紹一下前端的基礎(chǔ)知識,對比認識一下各個框架的代碼編寫方式,并介紹我們本次技術(shù)選型的主要思路。對于前端三大技術(shù) HTML、CSS、JavaScript,簡單的介紹了基本情況和常用語法。中間介紹了現(xiàn)代框架的一些情況,并通過實際的案例,用代碼直觀的認識一下各種框架的實現(xiàn)方式。最后分析一下項目的技術(shù)選型。

          知識點

          • HTML、CSS、JavaScript 快速概覽
          • 前端框架概覽和選型
          • 后端選型
          • 數(shù)據(jù)庫選型
          • Web 服務(wù)器選型

          前端技術(shù)簡介

          本節(jié)我們簡單介紹一下前端最基礎(chǔ) HTML, CSS, JavaScript 三駕馬車。雖然本課程預(yù)設(shè)的讀者為零基礎(chǔ)開發(fā)者,但是前端開發(fā)一定會這三種技術(shù)的運用有要求。建議抽空學(xué)習 《 Web 前端工程師路徑》 中的階段 1 甚至階段 2。這里僅做語法介紹和基本使用的概覽。

          在此之前先認識一下實驗環(huán)境。實驗環(huán)境和 VS Code 使用體驗基本一致。你可以啟動一個終端,并在其中輸入 Linux 命令。

          后面的命令無特殊說明的都是在此終端命令行中輸入。大多數(shù)命令可以多開終端窗口分別執(zhí)行。

          那么下面我們就快速的了解一下。

          HTML

          HTML 全稱超文本標記語言,幾乎是從萬維網(wǎng)和瀏覽器產(chǎn)生伊始就存在的。主要用于結(jié)構(gòu)化信息來方便瀏覽器展示。

          以標簽對作為主要特征,如<p>這是一個段落</p>。這些標簽會被瀏覽器解析成不同的模塊,比如 p 標簽就是一個段落,img 標簽就是一個圖片,a 標簽就是一個超鏈接,標簽名不區(qū)分大小寫。

          立刻就來嘗試一下吧。首先通過命令行新建一個 demo 目錄:

          mkdir demo

          然后命令行進入 demo 目錄:

          cd ./demo

          新建一個 hello.html 文件,可以在實驗環(huán)境左邊的瀏覽框內(nèi)在 demo 上右鍵選擇 New File 然后命名為 hello.html;或者也可在命令行終端輸入 touch hello.html,同樣是新建文件。

          在其中輸入以下內(nèi)容:

          <!DOCTYPE html>
          <html>
            <head>
              <meta charset="UTF-8" />
              <title>標題</title>
            </head>
            <body>
              正文
            </body>
          </html>

          然后右擊文件選擇 Open With → Preview。

          看到了嗎?其實我們就是新建了一個 .html 后綴的文本文件,然后瀏覽器就可以將其中的內(nèi)容展示出來。你也可以在自己的桌面上新建一個,然后使用瀏覽器打開看看效果。

          這里嵌套代碼的縮進格式是為了美觀和可讀性,并無嚴格要求。

          head 標簽中是一些暫時無需用到的頭部信息,渲染的主體是 body 標簽。下面我們修改 body 標簽里面的內(nèi)容,填入一些常用標簽來直觀感受一下。

          <body>
            <h1>頁面標題</h1>
            <div>一個塊容器</div>
            <div>又一個塊容器</div>
            <p>這里是段落了,間距變大</p>
            <div>一個塊容器</div>
            <div>
              <div>
                多層嵌套:
                <div>內(nèi)部第一個</div>
                <div>內(nèi)部第二個</div>
              </div>
            </div>
          </body>

          保存之后切換到瀏覽標簽看一看,有沒有感覺被忽悠了?嵌套沒嵌套根本沒體現(xiàn)出來,就像 Word 里排了一下版,按了幾個回車。

          因為我們沒有對顯示樣式進行修改,那是 CSS 的事。HTML 主要管內(nèi)容的組織結(jié)構(gòu)。

          這里有一點針對學(xué)習的小建議,本課程中給到的全部代碼請手動輸入,忘記復(fù)制和粘貼快捷鍵。

          而且最好不要機械的一個字符一個字符照著抄,盡量看過一行或一小段代碼之后,靠短暫的印象去輸出,別怕出錯,只有過腦子并輸出實踐,才是最快掌握一項技能的捷徑。

          以上兩句話是本課程中最有價值內(nèi)容之一。

          下面我們接著修改剛才的代碼,再給 body 中添加幾個常用標簽。每次修改和保存之后記得到預(yù)覽頁看看樣式的變化。

          <h4>4 級標題</h4>
          <ul>
            <li>
              HTML
            </li>
            <li>
              CSS
            </li>
            <li>
              JavaScript
            </li>
          </ul>
          <div>
            <a href="https://www.shiyanlou.com" target="_blank"
              >點擊超鏈接跳轉(zhuǎn)至實驗樓首頁</a
            >
          </div>
          <div>
            <img
              src="https://static.shiyanlou.com/frontend/dist/img/9f43b00.svg"
              alt=""
              width="200"
            />
          </div>

          最后的鏈接標簽 a 和圖片標簽 img 出現(xiàn)了標簽屬性,屬性為 attr="value" 格式,可以給標簽增加更豐富的信息。

          同時 img 標簽還是一個單標簽,不需要在后面添加 </img> 配合使用。

          至此對 HTML 的簡要介紹告一段落。

          互聯(lián)網(wǎng)上看到的各種五彩繽紛網(wǎng)頁都是由這些 HTML 組成的,但是為什么我們寫的這么難看?下一節(jié)我們就要學(xué)習一下如何用 CSS 美化頁面。

          CSS

          CSS 全稱層疊樣式表,是專門用來修飾 HTML 樣式的一種語言。我們修改一下上節(jié)的 hello.html 文件來直觀感受一下。


          內(nèi)部代碼塊引入

          在 head 標簽內(nèi)部增加以下 style 代碼塊:

          <head>
            <meta charset="UTF-8" />
            <title>標題</title>
            <style type="text/css">
              div {
                border: 1px solid blue;
                padding: 2px;
                margin: 10px;
              }
            </style>
          </head>

          這是再切換到預(yù)覽頁,發(fā)現(xiàn)沒那么平鋪直敘了。

          這就是 CSS 的第一種引入方式,HTML 內(nèi)置代碼塊。

          大括號外面的 div 是標簽選擇器,這里選中了本頁面中的所有 div 元素。大括號里面是屬性名與賦值,屬性名都是固定的關(guān)鍵字,并已規(guī)定好了值的類型和可選范圍。

          讀代碼也就大概知道了,我們將 div 的邊框設(shè)置為 1 像素寬、固體(單線型)、藍色,填充(內(nèi)邊距)2 像素,邊緣空白(外邊距)10 像素?,F(xiàn)在可以練習調(diào)整一下各個數(shù)字,預(yù)覽看看發(fā)生了什么?

          再說點題外話,懂一些英文對程序員來說非常必要,除了可以憑感覺就讀懂沒學(xué)過的代碼,還可以在面向 Google 編程、面向 Stack Overflow 編程、面向 Github Issues 編程時游刃有余。


          外部文件引入

          然后我們再試一下外部文件引入,在 hello.html 的同級目錄新建 hello.css,輸入以下內(nèi)容保存:

          div {
            color: green;
            border: 2px dotted red;
          }

          然后修改 hello.html,在 style 標簽后面增加一行 link 標簽,添加引入類型和地址:

          <style type="text/css">
            div {
              border: 1px solid blue;
              padding: 2px;
              margin: 10px;
            }
          </style>
          <link rel="stylesheet" href="hello.css" />

          預(yù)覽看看,文字顏色變?yōu)榫G色,邊框的樣式也被更新為 2 像素寬、點線型紅色。

          同樣是 div 選擇器,為什么邊框的樣式被覆蓋了呢?注意 CSS 在同樣條件下會后面代碼覆蓋前面,可以嘗試交換 link 標簽和 style 標簽塊的順序看看。


          行間樣式

          最后一種叫行間樣式,這個結(jié)構(gòu)更簡單。修改 hello.html 中的 <div>內(nèi)部第一個</div> 為

          <div style="margin: 60px 0 10px 30px ;color:purple;">內(nèi)部第一個</div>

          樣式覆蓋前兩種方式了,因為行間樣式的優(yōu)先級較高。這里涉及到選擇器權(quán)重,先給一個簡單公式了解一下。

          !important > 行間樣式 > ID > class | 偽類 | 屬性選擇 > 標簽 > 繼承 | 通配符。

          多個選擇器作用時權(quán)重相加。這里算 CSS 里有點復(fù)雜的部分,暫時不展開。

          這里還有個小知識點是內(nèi)外邊距 margin 和 padding 接受的完整的值是四個,順序固定為“上 右 下 左”。如果省略參數(shù)則從末尾計算對向合并。比如:

          • margin:40px 20px 50px; 三個參數(shù)時,左右同為 20px。
          • margin:40px 20px; 兩個參數(shù)時 上下同為 40px, 左右同為 20px。
          • margin:40px; 一個參數(shù)時呢?請自行嘗試理解。

          CSS 先講這么多,雖然沒有把我們的頁面變多好看,但最起碼知道努力的方向了。

          JavaScript

          制作 JavaScript 的快速入門簡直非常傷腦筋。比起前兩種技術(shù) HTML 和 CSS,這是貨真價實的編程語言了。

          也是我們后面要用到的 Vue.js 和 Node.js 中的根基,一下子又很難講很多,所以還是希望同學(xué)們能重視起來系統(tǒng)學(xué)習一下,最起碼讀到后面的代碼時不至于陷入“這是啥這又是啥”的窘境。

          來段代碼直觀認知一下,還是先內(nèi)部代碼塊引入。

          在 hello.html 的 head 標簽內(nèi)增加一個代碼塊:

              <link rel="stylesheet" href="./hello.css">
              <script>
                let message = "字符串提示";
                function showMSG(msg) {
                  alert(msg);
                }
              </script>

          修改 hello.html 的 h1 標簽為:

          <h1 onclick="showMSG(message)">頁面標題</h1>

          保存預(yù)覽,點擊“頁面標題”,會彈出提示框。

          JavaScript 代碼加載之后就會執(zhí)行,不存在編譯階段。行末的分號絕大多數(shù)時候可以省略。

          我們先定義了一個變量 message,并賦值為“字符串提示”。定義變量關(guān)鍵字原是 var,ES6 新增關(guān)鍵字 let 有更清晰的作用域,可替代使用。

          學(xué)習 JavaScript 經(jīng)常會碰到 ES6、ES7 之類的名詞,實際上是 ECMAScript 標準的版本號的意思??梢院唵卫斫鉃樾掳鏄藴蕿?JavaScript 添加特定新特性。

          然后我們定義了一個函數(shù) showMSG,并添加一個形參 msg。在函數(shù)體內(nèi)部調(diào)用瀏覽器彈框方法,顯示 msg 的值。function 是定義函數(shù)的關(guān)鍵字,暫時先把它當做一個功能封閉的盒子,當函數(shù)調(diào)用時,執(zhí)行函數(shù)體內(nèi)的代碼。

          調(diào)用部分是先給 h1 標簽添加了 onclick 點擊事件,被點擊時觸發(fā) showMSG(message),也就是把 message 傳給了 msg。

          之后再試一下調(diào)用外部 js 文件,新建 demo.js 文件,寫入下面內(nèi)容并保存。

          message = "修改一下字符串";

          然后修改 hello.html 文件,在 script 代碼塊后面增加一行:

          <script src="./demo.js"></script>

          這次保存預(yù)覽,點擊“頁面標題”,可以看到彈窗的文字變了。這個演示了 script 代碼塊在頁面可以同時存在多個,也是順序調(diào)用,而且互相之間可以直接訪問。文件命名也沒有要求,希望不會逼死強迫癥。

          JavaScript 就是為什么網(wǎng)頁可以做那么多交互的源頭了。掌握起來任重道遠。

          以上內(nèi)容節(jié)選自實驗樓訓(xùn)練營課程《Vue.js 和 Node.js 構(gòu)建內(nèi)容發(fā)布系統(tǒng)》。


          這三門前端技術(shù)先了解到這里,想要更深入學(xué)習如何使用前端技術(shù)構(gòu)建內(nèi)容發(fā)布系統(tǒng),比如做個高逼格的博客,搭建一個交流社區(qū),或者為企業(yè)制作官網(wǎng)等,可以訪問實驗樓官網(wǎng),搜索《Vue.js 和 Node.js 構(gòu)建內(nèi)容發(fā)布系統(tǒng)》這門課。

          課程會提供完整的虛擬機環(huán)境,手把手教大家如何從頭構(gòu)建實現(xiàn)一個前后端分離的內(nèi)容發(fā)布系統(tǒng),包括了前端頁面、后端服務(wù)、數(shù)據(jù)庫等。


          主站蜘蛛池模板: 亚洲国产精品一区二区久久hs| 日韩综合无码一区二区| 一区二区三区观看| 一区二区三区在线免费看| 日韩一区二区三区在线 | 香蕉免费一区二区三区| 国产亚洲福利精品一区二区 | 日韩一区二区三区免费播放| 国产精品一区二区久久精品| 人妻少妇一区二区三区| 国产伦精品一区二区三区视频猫咪 | 一区二区免费视频| 亚洲人成人一区二区三区| 亚洲AV无码一区二三区| 精品一区精品二区| 欧洲精品码一区二区三区免费看 | 日韩动漫av在线播放一区| 亚洲国产成人久久一区二区三区| 久久久精品人妻一区二区三区蜜桃 | 亚洲AV永久无码精品一区二区国产| 成人在线观看一区| 精品国产一区二区三区在线| 无码人妻精品一区二区三区不卡| 亚洲欧美日韩国产精品一区| 国产一区二区成人| 国产福利酱国产一区二区| 国产日产久久高清欧美一区| 久久精品成人一区二区三区| 无码一区二区三区在线| 日本v片免费一区二区三区| 日本韩国黄色一区二区三区 | 国产91精品一区二区麻豆网站| 日本免费一区二区三区四区五六区 | 日韩精品一区二区亚洲AV观看| 日本大香伊一区二区三区| 亚洲伦理一区二区| eeuss鲁片一区二区三区| 无码日韩人妻AV一区免费l| 日韩AV无码一区二区三区不卡毛片 | 无码人妻一区二区三区免费视频| 亚洲视频在线一区二区|