Kaip įdiegti išmaniąją sutartį Ethereum tinkle naudojant dRPC API raktą ir galinį tašką

Kaip įdiegti išmaniąją sutartį Ethereum tinkle naudojant dRPC API raktą

Įvadas

Suprasdami Web3 DApp kūrimo technologijų rinkinį, turite išmokti pagrindines žiniatinklio 3 dApp kūrimo technologijas, RPC vaidmenį kuriant dApp ir kaip naudoti dRPC kuriant paskyrą, generuojant API raktą, galinius taškus, galinių taškų analizę. , pridėkite lėšų į savo dRPC sąskaitą ir patikrinkite balansą.

dRPC vaidmuo diegiant išmaniąsias sutartis yra supaprastinti Ethereum mazgo nustatymo procesą, kad kūrėjams būtų lengviau bendrauti ir diegti naudojant tik vieną kodo eilutę.

Šiame straipsnyje jūs parašysite, sudarysite, išbandysite ir įdiegsite išmaniąją kavos mokėjimo sutartį su Ethereum Sepolia Testnet naudodami dRPC galutinį tašką ir API raktą.

Funkcijos apima:

  1. Apmokėjimas už kavą
  2. Kavos kainos peržiūra
  3. Nuskaitomas bendras parduotos kavos skaičius ir bendra uždirbtų pinigų suma

Sutepsim rankas.

Būtinos sąlygos

  1. Jau papildykite savo sąskaitą naudodami Sepolia Faucet.
  2. Turėkite piniginę, pvz., „Metamask“.
  3. Kodo redaktorius.
  4. Jau įdiegėte visas jūsų pasirinktas Js bibliotekas ar sistemas (pvz., React.js, Next.js ir tt).
  5. Stiklainis vandens.
  1. Solidumas.
  2. React.js naudojant Vite.js(Typescript)
  3. Hardhat.
  4. Web3.js.
  5. Dotenv.
  6. dRPC API raktas ir galutinis taškas.
  7. Jūsų paskyros privatus raktas.
  8. MetaMask

Išmaniosios kavos mokėjimo sutarties rašymas

  1. Sukurkite aplanką savo šakniniame kataloge ir pavadinkite jį contracts.
  2. Sukurkite failą po contracts aplanką ir pavadinkite jį coffee.sol.

    Rodomas failų katalogas su aplanku pavadinimu "sutartys" ir failas pavadinimu "kava.sol" aplanko viduje.

rašydami išmaniąją sutartį naudosite solidumą. Solidity failai pavadinti su .sol plėtinį, nes tai yra standartinis „Solidity“ šaltinio kodo failo plėtinys.

  1. Pridėkite šį šaltinio kodą prie coffee.sol :
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.8.0 <0.9.0;
    
    contract Coffee {
        uint256 public constant coffeePrice  = 0.0002 ether;
        uint256 public totalCoffeesSold;
        uint256 public totalEtherReceived;
    
        // Custom error definitions
        error QuantityMustBeGreaterThanZero();
        error InsufficientEtherSent(uint256 required, uint256 sent);
        error DirectEtherTransferNotAllowed();
    
        // Event to log coffee purchases
        event CoffeePurchased(address indexed buyer, uint256 quantity, uint256 totalCost);
    
        // Function to buy coffee
        function buyCoffee(uint256 quantity) external payable {
            if (quantity <= 0) {
                revert QuantityMustBeGreaterThanZero();
            }
    
            uint256 totalCost = coffeePrice * quantity;
            
            if (msg.value > totalCost) {
                revert InsufficientEtherSent(totalCost, msg.value);
            }
    
            // Update the total coffees sold and total ether received
            totalCoffeesSold += quantity;
            totalEtherReceived += totalCost;
            console.log("Total ether received updated:", totalEtherReceived);
            console.log("Total coffee sold updated:", totalCoffeesSold);
            // Emit the purchase event
            emit CoffeePurchased(msg.sender, quantity, totalCost);
    
            // Refund excess Ether sent
            if (msg.value > totalCost) {
                uint256 refundAmount = msg.value - totalCost;
                payable(msg.sender).transfer(refundAmount);
            }
        }
    
        // Fallback function to handle Ether sent directly to the contract
        receive() external payable {
            revert DirectEtherTransferNotAllowed();
        }
    
        // Public view functions to get totals
        function getTotalCoffeesSold() external view returns (uint256) {
            console.log("getTotalCoffeesSold :", totalCoffeesSold);
            return totalCoffeesSold;
        }
    
        function getTotalEtherReceived() external view returns (uint256) {
             console.log("getTotalEtherReceived :", totalEtherReceived);
                    return totalEtherReceived;
        }
    }
    

Pragma

  • pragma solidity >=0.8.0 <0.9.0;: nurodoma, kad kodas parašytas Solidity versijoms nuo 0.8.0 (imtinai) iki 0.9.0 (išskyrus).

Būsenos kintamasis

    uint256 public constant coffeePrice  = 0.0002 ether;
    uint256 public totalCoffeesSold;
    uint256 public totalEtherReceived;
  • coffeePrice: nustatyta kaip pastovi reikšmė 0.0002 ether.
  • totalCoffeesSold: seka parduotų kavos rūšių skaičių.
  • totalEtherReceived: seka bendrą eterio kiekį, gautą pagal sutartį.

Pasirinktinės klaidos

Pasirinktinės Solidity klaidos yra klaidų pranešimai, pritaikyti konkrečiam naudojimo atvejui, o ne numatytieji klaidų pranešimai, kuriuos pateikia programavimo kalba. Jie gali padėti pagerinti vartotojo patirtį, taip pat gali padėti derinti ir palaikyti išmaniąsias sutartis.

Norėdami apibrėžti tinkintą klaidą Solidity, galite naudoti šią sintaksę:

  • error: šis raktinis žodis naudojamas pasirinktinei klaidai apibrėžti
  • Unikalus pavadinimas: klaida turi turėti unikalų pavadinimą
  • Parametrai: jei norite įtraukti konkrečią informaciją ar parametrus į klaidos pranešimą, galite juos įtraukti skliausteliuose po klaidos pavadinimu.
    error QuantityMustBeGreaterThanZero();
    error InsufficientEtherSent(uint256 required, uint256 sent);
    error DirectEtherTransferNotAllowed();
  • QuantityMustBeGreaterThanZero(): Užtikrina, kad kiekis didesnis nei nulis.
  • InsufficientEtherSent(uint256 required, uint256 sent): Užtikrina, kad atsiųsto eterio pakanka.
  • DirectEtherTransferNotAllowed(): Neleidžia tiesiogiai perduoti eterio į sutartį.

Renginiai

Įvykis yra sutarties dalis, kurioje saugomi argumentai, perduoti operacijų žurnaluose, kai jie išsiunčiami. Įvykiai paprastai naudojami informuoti skambinančią programą apie dabartinę sutarties būseną, naudojant EVM registravimo funkciją. Jie praneša programoms apie atliktus sutarčių pakeitimus, kurie vėliau gali būti naudojami susijusiai logikai vykdyti.

    event CoffeePurchased(address indexed buyer, uint256 quantity, uint256 totalCost);
  • CoffeePurchased(address indexed buyer, uint256 quantity, uint256 totalCost): Registruoja kavos pirkimus.

Funkcijos

Funkcijos yra savarankiški kodo moduliai, kurie atlieka konkrečią užduotį. Jie pašalina tos pačios kodo dalies perrašymo perteklių. Vietoj to, kūrėjai gali iškviesti funkciją programoje, kai tai būtina.

   
  function buyCoffee(uint256 quantity) external payable {
        if (quantity <= 0) {
            revert QuantityMustBeGreaterThanZero();
        }

        uint256 totalCost = coffeePrice * quantity;
        
        if (msg.value > totalCost) {
            revert InsufficientEtherSent(totalCost, msg.value);
        }

        // Update the total coffees sold and total ether received
        totalCoffeesSold += quantity;
        totalEtherReceived += totalCost;
        console.log("Total ether received updated:", totalEtherReceived);
        console.log("Total coffee sold updated:", totalCoffeesSold);
        // Emit the purchase event
        emit CoffeePurchased(msg.sender, quantity, totalCost);

        // Refund excess Ether sent
        if (msg.value > totalCost) {
            uint256 refundAmount = msg.value - totalCost;
            payable(msg.sender).transfer(refundAmount);
        }
    }

   receive() external payable {
        revert DirectEtherTransferNotAllowed();
    }


  function getTotalCoffeesSold() external view returns (uint256) {
        console.log("getTotalCoffeesSold :", totalCoffeesSold);
        return totalCoffeesSold;
    }

    function getTotalEtherReceived() external view returns (uint256) {
         console.log("getTotalEtherReceived :", totalEtherReceived);
                return totalEtherReceived;
    }
  • buyCoffee(uint256 quantity) external payable: tvarko kavos pirkimą ir atlieka šias operacijas:
    • Patikrinkite, ar kiekis tinkamas.
    • Apskaičiuoja bendrą kainą.
    • Užtikrina, kad būtų išsiųsta pakankamai eterio.
    • Atnaujina būsenos kintamuosius.
    • Išleidžia pirkimo įvykį.
    • Grąžina eterio perteklių.
  • receive() external payable: Grąžina tiesioginius eterio pervedimus, jei kas nors siunčia lėšas tiesiogiai sutarties adresu.
  • getTotalCoffeesSold() external view returns (uint256): grąžina visą parduotą kavos kiekį.
  • getTotalEtherReceived() external view returns (uint256): grąžina visą gautą eterį.

Išmaniosios kavos mokėjimo sutarties sudarymas

Čia jūs naudosite „Hardhat“, kad sudarytumėte išmaniąją sutartį.

  1. Įdiekite „Hardhat“ naudodami šią komandų eilutę.
    npm install --save-dev hardhat
    

    Po sėkmingo įdiegimo gausite atsakymą žemiau.

    Terminalas, rodantis hardhat diegimo išvestį..

  2. Tame pačiame kataloge, kuriame inicijuojate hardhat naudodami šią komandų eilutę:
    npx hardhat init
    
  3. Pasirinkite Create a Javascript project naudodami rodyklės žemyn mygtuką ir paspauskite enter.

  4. Paspauskite Enter, kad įdiegtumėte šakniniame aplanke

  5. Priimkite visus raginimus naudodami y klaviatūroje, įskaitant @nomicfoundation/hardhat-toolbox priklausomybės

  6. Žemiau matote šį atsakymą, rodantį, kad sėkmingai inicijavote

Pastebėsite, kad prie jūsų projekto buvo pridėta naujų aplankų ir failų. pvz., Lock.sol, iginition/modules, test/Lock.js ir hardhat.config.cjs. Nesijaudink dėl jų.

Vieninteliai naudingi yra iginition/modules ir hardhat.config.cjs. Vėliau sužinosite, kam jie naudojami. Nedvejodami ištrinkite Lock.sol pagal contracts aplankas ir Lock.js pagal iginition/modules aplanką.

  1. Sudarykite sutartį naudodami šią komandų eilutę:
    npx hardhat compile
    

  1. Matote papildomų aplankų ir failų, tokių kaip šis.

  1. Viduje Coffee.json failas yra ABI kodas JSON formatu, kurį iškviesite bendraudami su išmaniąja sutartimi.
{
  "_format": "hh-sol-artifact-1",
  "contractName": "Coffee",
  "sourceName": "contracts/coffee.sol",
  "abi": (
    {
      "inputs": (),
      "name": "DirectEtherTransferNotAllowed",
      "type": "error"
    },
    {
      "inputs": (
        {
          "internalType": "uint256",
          "name": "required",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "sent",
          "type": "uint256"
        }
      ),
      "name": "InsufficientEtherSent",
      "type": "error"
    },
    {
      "inputs": (),
      "name": "QuantityMustBeGreaterThanZero",
      "type": "error"
    },
    {
      "anonymous": false,
      "inputs": (
        {
          "indexed": true,
          "internalType": "address",
          "name": "buyer",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "quantity",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "totalCost",
          "type": "uint256"
        }
      ),
      "name": "CoffeePurchased",
      "type": "event"
    },
    {
      "inputs": (
        {
          "internalType": "uint256",
          "name": "quantity",
          "type": "uint256"
        }
      ),
      "name": "buyCoffee",
      "outputs": (),
      "stateMutability": "payable",
      "type": "function"
    },
    {
      "inputs": (),
      "name": "coffeePrice",
      "outputs": (
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ),
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": (),
      "name": "getTotalCoffeesSold",
      "outputs": (
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ),
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": (),
      "name": "getTotalEtherReceived",
      "outputs": (
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ),
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": (),
      "name": "totalCoffeesSold",
      "outputs": (
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ),
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": (),
      "name": "totalEtherReceived",
      "outputs": (
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ),
      "stateMutability": "view",
      "type": "function"
    },
    {
      "stateMutability": "payable",
      "type": "receive"
    }
  ),
  "bytecode": "0x608060405234801561001057600080fd5b506107d7806100206000396000f3fe6080604052600436106100595760003560e01c80631c8a403814610094578063657b2d89146100bf5780637ef3e741146100ea5780639fd66f9014610115578063b03b4a2914610140578063e926b8d01461015c5761008f565b3661008f576040517ebbbfa300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080fd5b3480156100a057600080fd5b506100a9610187565b6040516100b69190610537565b60405180910390f35b3480156100cb57600080fd5b506100d4610191565b6040516100e19190610537565b60405180910390f35b3480156100f657600080fd5b506100ff6101dc565b60405161010c9190610537565b60405180910390f35b34801561012157600080fd5b5061012a6101e2565b6040516101379190610537565b60405180910390f35b61015a60048036038101906101559190610583565b6101e8565b005b34801561016857600080fd5b506101716103e7565b60405161017e9190610537565b60405180910390f35b65b5e620f4800081565b60006101d46040518060400160405280601781526020017f676574546f74616c45746865725265636569766564203a000000000000000000815250600154610432565b600154905090565b60015481565b60005481565b60008111610222576040517f0cdcd02000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008165b5e620f4800061023691906105df565b90508034111561027f5780346040517f8ad0844f000000000000000000000000000000000000000000000000000000008152600401610276929190610621565b60405180910390fd5b81600080828254610290919061064a565b9250508190555080600160008282546102a9919061064a565b925050819055506102f16040518060400160405280601d81526020017f546f74616c20657468657220726563656976656420757064617465643a000000815250600154610432565b6103326040518060400160405280601a81526020017f546f74616c20636f6666656520736f6c6420757064617465643a000000000000815250600054610432565b3373ffffffffffffffffffffffffffffffffffffffff167fb706f7a46856e7a0e4f8f504c23f2ac26950209db23c2125108eed5ef9e333d3838360405161037a929190610621565b60405180910390a2803411156103e35760008134610398919061067e565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156103e0573d6000803e3d6000fd5b50505b5050565b600061042a6040518060400160405280601581526020017f676574546f74616c436f6666656573536f6c64203a0000000000000000000000815250600054610432565b600054905090565b6104ca8282604051602401610448929190610742565b6040516020818303038152906040527fb60e72cc000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506104ce565b5050565b6104e5816104dd6104e8610509565b63ffffffff16565b50565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b610514819050919050565b61051c610772565b565b6000819050919050565b6105318161051e565b82525050565b600060208201905061054c6000830184610528565b92915050565b600080fd5b6105608161051e565b811461056b57600080fd5b50565b60008135905061057d81610557565b92915050565b60006020828403121561059957610598610552565b5b60006105a78482850161056e565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006105ea8261051e565b91506105f58361051e565b92508282026106038161051e565b9150828204841483151761061a576106196105b0565b5b5092915050565b60006040820190506106366000830185610528565b6106436020830184610528565b9392505050565b60006106558261051e565b91506106608361051e565b9250828201905080821115610678576106776105b0565b5b92915050565b60006106898261051e565b91506106948361051e565b92508282039050818111156106ac576106ab6105b0565b5b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156106ec5780820151818401526020810190506106d1565b60008484015250505050565b6000601f19601f8301169050919050565b6000610714826106b2565b61071e81856106bd565b935061072e8185602086016106ce565b610737816106f8565b840191505092915050565b6000604082019050818103600083015261075c8185610709565b905061076b6020830184610528565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfea264697066735822122006c7d91368c8390cb4f21f6314ccd362b6d56cb17994af7009b53e7fb92411a864736f6c63430008180033",
  "deployedBytecode": "0x6080604052600436106100595760003560e01c80631c8a403814610094578063657b2d89146100bf5780637ef3e741146100ea5780639fd66f9014610115578063b03b4a2914610140578063e926b8d01461015c5761008f565b3661008f576040517ebbbfa300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080fd5b3480156100a057600080fd5b506100a9610187565b6040516100b69190610537565b60405180910390f35b3480156100cb57600080fd5b506100d4610191565b6040516100e19190610537565b60405180910390f35b3480156100f657600080fd5b506100ff6101dc565b60405161010c9190610537565b60405180910390f35b34801561012157600080fd5b5061012a6101e2565b6040516101379190610537565b60405180910390f35b61015a60048036038101906101559190610583565b6101e8565b005b34801561016857600080fd5b506101716103e7565b60405161017e9190610537565b60405180910390f35b65b5e620f4800081565b60006101d46040518060400160405280601781526020017f676574546f74616c45746865725265636569766564203a000000000000000000815250600154610432565b600154905090565b60015481565b60005481565b60008111610222576040517f0cdcd02000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008165b5e620f4800061023691906105df565b90508034111561027f5780346040517f8ad0844f000000000000000000000000000000000000000000000000000000008152600401610276929190610621565b60405180910390fd5b81600080828254610290919061064a565b9250508190555080600160008282546102a9919061064a565b925050819055506102f16040518060400160405280601d81526020017f546f74616c20657468657220726563656976656420757064617465643a000000815250600154610432565b6103326040518060400160405280601a81526020017f546f74616c20636f6666656520736f6c6420757064617465643a000000000000815250600054610432565b3373ffffffffffffffffffffffffffffffffffffffff167fb706f7a46856e7a0e4f8f504c23f2ac26950209db23c2125108eed5ef9e333d3838360405161037a929190610621565b60405180910390a2803411156103e35760008134610398919061067e565b90503373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156103e0573d6000803e3d6000fd5b50505b5050565b600061042a6040518060400160405280601581526020017f676574546f74616c436f6666656573536f6c64203a0000000000000000000000815250600054610432565b600054905090565b6104ca8282604051602401610448929190610742565b6040516020818303038152906040527fb60e72cc000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506104ce565b5050565b6104e5816104dd6104e8610509565b63ffffffff16565b50565b60006a636f6e736f6c652e6c6f679050600080835160208501845afa505050565b610514819050919050565b61051c610772565b565b6000819050919050565b6105318161051e565b82525050565b600060208201905061054c6000830184610528565b92915050565b600080fd5b6105608161051e565b811461056b57600080fd5b50565b60008135905061057d81610557565b92915050565b60006020828403121561059957610598610552565b5b60006105a78482850161056e565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006105ea8261051e565b91506105f58361051e565b92508282026106038161051e565b9150828204841483151761061a576106196105b0565b5b5092915050565b60006040820190506106366000830185610528565b6106436020830184610528565b9392505050565b60006106558261051e565b91506106608361051e565b9250828201905080821115610678576106776105b0565b5b92915050565b60006106898261051e565b91506106948361051e565b92508282039050818111156106ac576106ab6105b0565b5b92915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156106ec5780820151818401526020810190506106d1565b60008484015250505050565b6000601f19601f8301169050919050565b6000610714826106b2565b61071e81856106bd565b935061072e8185602086016106ce565b610737816106f8565b840191505092915050565b6000604082019050818103600083015261075c8185610709565b905061076b6020830184610528565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052605160045260246000fdfea264697066735822122006c7d91368c8390cb4f21f6314ccd362b6d56cb17994af7009b53e7fb92411a864736f6c63430008180033",
  "linkReferences": {},
  "deployedLinkReferences": {}
}

Išmaniosios sutarties testavimas

Sudarant išmaniąją sutartį labai svarbu ir labai rekomenduojama parašyti automatinį bandomąjį scenarijų. Jis veikia kaip dviejų veiksnių autentifikavimas (2FA), užtikrinantis, kad jūsų išmanioji sutartis veiktų taip, kaip tikėtasi, prieš įdiegiant ją į tiesioginį tinklą.

Pagal test aplanke sukurkite naują failą ir pavadinkite jį Coffee.cjs. Failo viduje įklijuokite šį kodą žemiau:

const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers.js");
const { expect } = require("chai");
const pkg = require("hardhat");
const ABI = require('../artifacts/contracts/coffee.sol/Coffee.json');
const { web3 } = pkg;

describe("Coffee Contract", function () {
  // Fixture to deploy the Coffee contract
  async function deployCoffeeFixture() {
    const coffeeContract = new web3.eth.Contract(ABI.abi);
    coffeeContract.handleRevert = true;

    const (deployer, buyer) = await web3.eth.getAccounts();
    const rawContract = coffeeContract.deploy({
      data: ABI.bytecode,
    });

    // Estimate gas for the deployment
    const estimateGas = await rawContract.estimateGas({ from: deployer });

    // Deploy the contract
    const coffee = await rawContract.send({
      from: deployer,
      gas: estimateGas.toString(),
      gasPrice: "10000000000",
    });

    console.log("Coffee contract deployed to: ", coffee.options.address);
    return { coffee, deployer, buyer, rawContract };
  }

  describe("Deployment", function () {
    // Test to check initial values after deployment
    it("Should set the initial values correctly", async function () {
      const { coffee } = await loadFixture(deployCoffeeFixture);
      const totalCoffeesSold = await coffee.methods.totalCoffeesSold().call();
      const totalEtherReceived = await coffee.methods.totalEtherReceived().call();

      expect(totalCoffeesSold).to.equal("0");
      expect(totalEtherReceived).to.equal("0");
    });
  });

  describe("Buying Coffee", function () {
    // Test to check coffee purchase and event emission
    it("Should purchase coffee and emit an event", async function () {
      const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
      const quantity = 3;
      const totalCost = web3.utils.toWei("0.0006", "ether");

      // Buyer purchases coffee
      const receipt = await coffee.methods.buyCoffee(quantity).send({ from: buyer, value: totalCost });

      // Check event
      const event = receipt.events.CoffeePurchased;
      expect(event).to.exist;
      expect(event.returnValues.buyer).to.equal(buyer);
      expect(event.returnValues.quantity).to.equal(String(quantity));
      expect(event.returnValues.totalCost).to.equal(totalCost);
    });

    // Test to check revert when quantity is zero
    it("Should revert if the quantity is zero", async function () {
            const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
            expect(
              coffee.methods.buyCoffee(0).send({ from: buyer, value: web3.utils.toWei("0.0002", "ether") })
            ).to.be.revertedWith("QuantityMustBeGreaterThanZero");
          });

          
    // Test to check if totalCoffeesSold and totalEtherReceived are updated correctly
    it("Should update totalCoffeesSold and totalEtherReceived correctly", async function () {
      const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
      const quantity = 5;
      const totalCost = web3.utils.toWei("0.001", "ether");

      await coffee.methods.buyCoffee(quantity).send({ from: buyer, value: totalCost });

      const totalCoffeesSold = await coffee.methods.totalCoffeesSold().call();
      const totalEtherReceived = await coffee.methods.totalEtherReceived().call();

      expect(totalCoffeesSold).to.equal(String(quantity));
      expect(totalEtherReceived).to.equal(totalCost);
    });

   
  });

  describe("Fallback function", function () {
    // Test to check revert when ether is sent directly to the contract
    it("Should revert if ether is sent directly to the contract", async function () {
      const { coffee, buyer } = await loadFixture(deployCoffeeFixture);

      expect(
        web3.eth.sendTransaction({
          from: buyer,
          to: coffee.options.address,
          value: web3.utils.toWei("0.001", "ether"),
        })
      ).to.be.revertedWith("DirectEtherTransferNotAllowed");
    });
  });
});

Šis kodas patikrina „Coffee smart contract“ funkcionalumą. Tai apima diegimo, kavos pirkimo ir tiesioginių eterio perkėlimų į sutartį tvarkymo testus.

Štai suskirstymas:

Tvirtinimo funkcija: deployCoffeeFixture

async function deployCoffeeFixture() {

  const coffeeContract = new web3.eth.Contract(ABI.abi);

  coffeeContract.handleRevert = true;

  const (deployer, buyer) = await web3.eth.getAccounts();

  const rawContract = coffeeContract.deploy({

    data: ABI.bytecode,

  });

  const estimateGas = await rawContract.estimateGas({ from: deployer });

  const coffee = await rawContract.send({

    from: deployer,

    gas: estimateGas.toString(),

  gasPrice: "10000000000",

  });

  console.log("Coffee contract deployed to: ", coffee.options.address);

  return { coffee, deployer, buyer, rawContract };

}
  • Taiko kavos sutartį: sukuria naują sutarties egzempliorių ir diegia jį naudojant diegimo paskyrą.
  • Apskaičiuoja dujas: apskaičiuoja, kiek dujų reikia diegimui.
  • Grąžina: įdiegtas sutarties egzempliorius, diegimo ir pirkėjo paskyros.

Diegimo testai

describe("Deployment", function () {
  it("Should set the initial values correctly", async function () {
    const { coffee } = await loadFixture(deployCoffeeFixture);
    const totalCoffeesSold = await coffee.methods.totalCoffeesSold().call();
    const totalEtherReceived = await coffee.methods.totalEtherReceived().call();
    expect(totalCoffeesSold).to.equal("0");
    expect(totalEtherReceived).to.equal("0");
  });
});
  • Tikrina pradines vertes: Tai užtikrina totalCoffeesSold ir totalEtherReceived po įdiegimo nustatomi į nulį.

Kavos pirkimo testai

describe("Buying Coffee", function () {
  it("Should purchase coffee and emit an event", async function () {
    const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
    const quantity = 3;
    const totalCost = web3.utils.toWei("0.0006", "ether");
    const receipt = await coffee.methods.buyCoffee(quantity).send({ from: buyer, value: totalCost });
    const event = receipt.events.CoffeePurchased;
    expect(event).to.exist;
    expect(event.returnValues.buyer).to.equal(buyer);
    expect(event.returnValues.quantity).to.equal(String(quantity));
    expect(event.returnValues.totalCost).to.equal(totalCost);
  });
  it("Should revert if the quantity is zero", async function () {
    const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
    expect(
      coffee.methods.buyCoffee(0).send({ from: buyer, value: web3.utils.toWei("0.0002", "ether") })
    ).to.be.revertedWith("QuantityMustBeGreaterThanZero");
  });
  it("Should update totalCoffeesSold and totalEtherReceived correctly", async function () {
    const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
    const quantity = 5;
    const totalCost = web3.utils.toWei("0.001", "ether");
    await coffee.methods.buyCoffee(quantity).send({ from: buyer, value: totalCost });
    const totalCoffeesSold = await coffee.methods.totalCoffeesSold().call();
    const totalEtherReceived = await coffee.methods.totalEtherReceived().call();
    expect(totalCoffeesSold).to.equal(String(quantity));
    expect(totalEtherReceived).to.equal(totalCost);

  });

});
  • Kavos pirkimas ir renginio išleidimas: Tikrina, kad kavos pirkimas atnaujina būseną ir išskiria CoffeePurchased renginys.
  • Grąžinama į nulinį kiekį: Užtikrina, kad operacija būtų grąžinta, jei kiekis lygus nuliui.
  • Teisingai atnaujinama būsena: Tai patvirtina totalCoffeesSold ir totalEtherReceived yra tinkamai atnaujinami po pirkimo.

Atsarginės funkcijos testas

describe("Fallback function", function () {
  it("Should revert if ether is sent directly to the contract", async function () {
    const { coffee, buyer } = await loadFixture(deployCoffeeFixture);
    expect(
      web3.eth.sendTransaction({
        from: buyer,
        to: coffee.options.address,
        value: web3.utils.toWei("0.001", "ether"),
      })
    ).to.be.revertedWith("DirectEtherTransferNotAllowed");
  });
});
  • Grįžtama prie tiesioginio eterio perdavimo: užtikrina, kad eterio siuntimas tiesiai į sutartį (neiškvietęs funkcijos) grąžintų operaciją.

Išmaniosios sutarties testavimas

Parašę testo scenarijų, atliksite toliau nurodytus veiksmus.

  1. Vykdydami sutartis ir testuodami „Hardhat Network“, galite spausdinti registravimo pranešimus ir sutarties kintamuosius skambinant console.log() iš jūsų solidumo kodo. Norėdami jį naudoti, turite importuoti hardhat/console.sol savo sutarties kode taip:
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

import "hardhat/console.sol"; 

contract Coffee {

//...

}
  1. Norėdami patikrinti sutartį, savo terminale paleiskite šią komandą:
    npx hardhat test
    
  2. Turėtumėte turėti tokią išvestį kaip žemiau:

Tai rodo, kad jūsų išmanioji sutartis veikia taip, kaip tikimasi.

Jei bėgate npx hardhat test ji automatiškai sukompiliuoja ir išbando išmaniąją sutartį. Galite tai išbandyti ir leiskite man sužinokite komentarų skiltyje.

Diegimas Išmanioji sutartis

Čia jūs įdiegsite savo išmaniąją sutartį su Sepolia Testnet. „Testnet“ leidžia išbandyti išmaniąją sutartį aplinkoje, kuri imituoja „Ethereum“ pagrindinį tinklą, nepatiriant didelių išlaidų. Jei gerai naudojate „dApp“ funkciją, galite perskirstyti ją į „Ethereum Mainnet“.

  1. Įdiekite dotenv paketą ir šias priklausomybes.
    npm install dotenv
    
    npm install --save-dev @nomicfoundation/hardhat-web3-v4 'web3@4'
    

    Tai pridės Web3.Js ir Dotenv prie jūsų projekto įtraukiant juos į aplanką „node_modules“.

  2. importuoti juos į savo hardhat.config.cjs failą
    require('dotenv').config();
    require("@nomicfoundation/hardhat-toolbox");
    require("@nomicfoundation/hardhat-web3-v4");
    const HardhatUserConfig = require("hardhat/config");
    
    module.exports = {
      solidity: "0.8.24",
      }
    };
    
  3. Sukurti an .env failą savo šakniniame aplanke.
  4. Gaukite paskyros privatų raktą iš savo MetaMask piniginės ir dRPC API rakto.
  5. Laikykite juos savo .env failą.
    DRPC_API_KEY=your_drpc_api_key
    PRIVATE_KEY=your_wallet_private_key
    
  6. Atnaujinkite hardhat.config.cjs failą, kad būtų įtraukta Sepolia Testnet konfigūracija:
    require('dotenv').config();
    require("@nomicfoundation/hardhat-toolbox");
    require("@nomicfoundation/hardhat-web3-v4");
    const HardhatUserConfig = require("hardhat/config");
    
    const dRPC_API_KEY = process.env.VITE_dRPC_API_KEY;
    const PRIVATE_KEY = process.env.VITE_PRIVATE_KEY;
    
    module.exports = {
      solidity: "0.8.24",
      networks: {
        sepolia: {
          url: `https://lb.drpc.org/ogrpc?network=sepolia&dkey=${dRPC_API_KEY}`,
          accounts: (`0x${PRIVATE_KEY}`),
        }
      }
    };
    
  7. Sukurkite naują scenarijaus failą pagal ignition/module aplanką ir pavadinkite jį deploy.cjs. Pridėkite šį kodą, kad įdiegtumėte išmaniąją sutartį:
    const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules");
    
    const CoffeeModule = buildModule("CoffeeModule", (m) => {
      const coffee = m.contract("Coffee");
    
      return { coffee };
    });
    
    module.exports = CoffeeModule;
    
  8. Įdiekite išmaniąją sutartį vykdydami šią komandą savo terminale:
    npx hardhat ignition deploy ./ignition/modules/deploy.cjs --network sepolia
    

    Paleidus komandų eilutę, jūsų bus paprašyta Confirm deploy to network sepolia (11155111)? (y/n)įveskite y . Sėkmingai įdiegę terminale turėtumėte matyti įdiegtos išmaniosios sutarties adresą.

    Sutarties adresą taip pat galite pasiekti deployed_addresses.json failą.

    Atidaryta Vite-Project failų naršyklės ir deployed_addresses.json failo ekrano kopija. Sveikiname, sėkmingai įdiegėte išmaniąją sutartį su „Sepolia Testnet“. 🎉

Išvada

Šis straipsnis išmokė jus parašyti išmaniąją mokėjimo sutartį, išbandyti, sudaryti ir įdiegti išmaniąją sutartį naudojant „hardhat CLI“.

Kitame straipsnyje sužinosite, kaip sukurti šios dApp priekinę dalį. Šią vartotojo sąsają sudarys:

  1. Įveskite nupirktų kavos skaičių.
  2. Mygtukas, kuris suaktyvina mokėjimo operaciją ir išskaito ją iš jūsų sąskaitos.
  3. Rodyti visą nupirktą kavą ir gautą sumą eteriu ir USD
  4. Pačios kavos kaina tiek eteriu, tiek USD.

Nuoroda

Be numatytųjų pranešimų: tinkintų klaidų įvaldymas solidumo srityje

Tinkintų klaidų įvaldymas solidumo srityje: padidinkite savo išmaniąsias sutartis daugiau nei numatytuosius pranešimus

Kas yra solidumo funkcijos?

Kas yra Solidity įvykiai?

← Ankstesnis straipsnis Kitas straipsnis →

Source link

Draugai: - Marketingo agentūra - Teisinės konsultacijos - Skaidrių skenavimas - Fotofilmų kūrimas - Miesto naujienos - Šeimos gydytojai - Saulius Narbutas - Įvaizdžio kūrimas - Veidoskaita - Nuotekų valymo įrenginiai - Teniso treniruotės - Pranešimai spaudai -