Onboarding TDD Solidity Typescript Hardhat Nextjs - Environment

Onboarding TDD Solidity Typescript Hardhat Nextjs - Environment

https://github.com/maximilianou/weekly59

  • Local Environment - Step by Step - Sample Code
  • TDD for blockchain to be tested, like:
  • Solidity Event
  • Solidity Modifiers - AccessControl and Constraints
  • Solidity Custom Errors
  • Solidity Errors PANIC Overflow
  • Solidity Smart Contracts Instance Value
  • Solidity Smart Contracts Storage vs Memory

{

name: "Maximiliano Usich",

email: "",

role: ["Husband", "Dad", "Software Developer", "Mentor", "Full Stack nodejs Javascript Typescript"],

github: github.com/maximilianou,

aCryptoCoffe: buymeacryptocoffee.xyz/simpledoers.eth,

aCoffe: buymeacoffee.com/simpledoers,

mirror: mirror.xyz/simpledoers.eth/subscribe,

}

weekly59: 20220715

Onboarding TDD Solidity Typescript Hardhat Nextjs - Environment


Web 3 - First things First - Environment is one of the keys to do any staff

In this case I use environment that can help me do the site that will use the contracts in next steps


step 1 - environment

  • Environment Tools Version
    • Solidity 0.8.9
    • Nextjs 12.2.2
    • Hardhat 2.10.1

step 1.1


Web 3 - In this Next step I have some code that I will be transforming in next weeks I hope to have the Full Stack Sample



  • Nodejs version 18
    • @latest
    • Always start with the @latest
    • Or testing or beta, but not LTS ( is my personal opinion, break and fix or inform ;)
nvm install 18
nvm use 18
node --version
v18.3.0

Web 3, Solidity - In this step add HardHat the simplest way to local development in web 3 and Solidity


step 1.2

  • Creating Hardhat environment

  • tsconfig.json

    • take care module: esnext
      {
      "compilerOptions": {
      "target": "es2020",
      "lib": ["dom", "dom.iterable", "esnext"],
      "allowJs": true,
      "skipLibCheck": true,
      "strict": true,
      "forceConsistentCasingInFileNames": true,
      "noEmit": true,
      "esModuleInterop": true,
      "module": "esnext", 
      "moduleResolution": "node",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "jsx": "preserve",
      "incremental": true
      },
      "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
      "exclude": ["node_modules"]
      }
      
  • [error] try to hardhat compile at once ... :o
    • But I mix create-next-app and hardhat creation
    • Step by step, baby steps
npx hardhat compile
Error HH13: Your Hardhat project uses typescript, but ts-node is not installed.

Please run: npm install --save-dev ts-node
  • [ok] fix install ts-node ;)

    npm install -D ts-node
    
  • [error] try to hardhat compile ... :o

    • I am missing something, lets read the error and docs ``` npx hardhat compile An unexpected error occurred:

/home/debian/projects/weekly59/blog4/hardhat.config.ts:1 import "@nomicfoundation/hardhat-toolbox"; ^^^^^^


- [ok] install hardhat-toolbox dependencies ;)
  - Just reading the docs <https://hardhat.org>, **Thank you Hardhat Team!!**

npm install -D @nomicfoundation/hardhat-toolbox


- [error]
  - HO, I have to read the error :()

npx hardhat compile An unexpected error occurred:

/home/debian/projects/weekly59/blog4/hardhat.config.ts:1 import "@nomicfoundation/hardhat-toolbox"; ^^^^^^

SyntaxError: Cannot use import statement outside a module


- [ok] 
  - Again! Thanks **Nextjs Team** and **Hardhat Team** 
  - **module: CommonJS**
```js
{
  "compilerOptions": {
    "target": "es2020",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "CommonJS",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
  • [ok] now hardhat compile ;)
    npx hardhat compile
    Generating typings for: 2 artifacts in dir: typechain-types for target: ethers-v5
    Successfully generated 6 typings!
    Compiled 2 Solidity files successfully
    

web 3, Solidity - Compile Environment Complete, lets continue with TDD


  • [ok] run hardhat test
    • Just before touching any solidity code
    • Hardhat team exelent work ;)
    • With Complete Sample :()
npx hardhat test
  Lock
    Deployment
      ✔ Should set the right unlockTime (1637ms)
      ✔ Should set the right owner
      ✔ Should receive and store the funds to lock
      ✔ Should fail if the unlockTime is not in the future (92ms)
    Withdrawals
      Validations
Unlock time is '1689365381' and block timestamp is '1657829383'
        ✔ Should revert with the right error if called too soon (81ms)
Unlock time is '1689365381' and block timestamp is '1689365382'
        ✔ Should revert with the right error if called from another account (99ms)
Unlock time is '1689365381' and block timestamp is '1689365382'
        ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it (95ms)
      Events
Unlock time is '1689365381' and block timestamp is '1689365382'
        ✔ Should emit an event on withdrawals (81ms)
      Transfers
Unlock time is '1689365381' and block timestamp is '1689365382'
        ✔ Should transfer the funds to the owner (73ms)
  9 passing (2s)

web 3, Solidity, TDD - Test Environment Complete, lets write down TDD with Typescript Nextjs Solidity


step 2 - Start Solidity by TDD Typescript Hardhat


  • contracts/SafeMath.sol 0.8 strict math overflow
    • Reference: starting point https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p
      // SPDX-License-Identifier: MIT
      pragma solidity ^0.8.9;
      import "hardhat/console.sol";
      contract SafeMath {
      function testUnderflow() public pure returns (uint) {
      uint x = 0;
      x--; // check safe underflow ;)
      return x;
      }
      function testUncheckedUndeflow() public pure returns (int){
      int x = 0;
      unchecked { // out of safe check underflow :o
        x--; 
      }
      return x;
      }
      }
      
  • test/SafeMath.ts solidity 0.8 overflow test PANIC ARITHMETIC OVERFLOW
    • I need to write code
    • Step by step
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";
import { expect } from "chai";
import { ethers } from "hardhat";
describe(`SafeMath`, () => {
  async function deployFixture() {
    // Contracts are deployed using the first signer/account by default
    const [owner, otherAccount] = await ethers.getSigners();
    const SafeMath = await ethers.getContractFactory("SafeMath");
    const safeMath = await SafeMath.deploy();
    return { safeMath, owner, otherAccount };
  }
  describe(`Deployment Safe Math`, () => {
    it(`Should check Underflow OK`, async () => {
      const { safeMath } = await loadFixture(deployFixture);
      // <https://hardhat.org/hardhat-chai-matchers/docs/reference#.revertedwithpanic>
      await expect(safeMath.testUnderflow()).to.be
      .revertedWithPanic( PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW ) ;
    });
    it(`Should NOT check or uncheck Underflow calculus error prone.`, async () => {
      const { safeMath } = await loadFixture(deployFixture);
      await expect(safeMath.testUncheckedUndeflow()).to.be.not.null;
    });
  });
});
  • [ok] test result
    npx hardhat test
    SafeMath
      Deployment Safe Math
        ✔ Should check Underflow OK (101ms)
        ✔ Should NOT check or uncheck Underflow mmmm calculus error prone.
    

web 3, Solidity, TDD catch Custom Error with Typescript Nextjs from Solidity


step 2.2


  • contracts/VendingMachine.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.9;
    error VENDING_MACHINE__UNAUTORIZED(); // custom error
    // <https://docs.soliditylang.org/en/v0.8.14/contracts.html#errors-and-the-revert-statement>
    contract VendingMachine {
    address payable owner = payable(msg.sender);
    function withdraw() public {
      if(msg.sender == owner) // == instead of != only for testing purposes
        revert VENDING_MACHINE__UNAUTORIZED(); 
      owner.transfer( address(this).balance );
    }
    }
    
  • tests/VendingMachine.ts ``js import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; import { expect } from "chai"; import { ethers } from "hardhat"; describe(VendingMachine, () => { async function deployFixture() { // Contracts are deployed using the first signer/account by default const [owner, otherAccount] = await ethers.getSigners(); const VendingMachine = await ethers.getContractFactory("VendingMachine"); const vendingMachine = await VendingMachine.deploy(); return { vendingMachine, owner, otherAccount }; } describe(Deployment VendingMachine, () => { it(Should Custom Error OK`, async () => {
    const { vendingMachine, otherAccount } = await loadFixture(deployFixture);
    await expect(vendingMachine.withdraw()).to.be
       .revertedWithCustomError( vendingMachine,"VENDING_MACHINE__UNAUTORIZED" ) ;
    //<https://hardhat.org/hardhat-chai-matchers/docs/reference#.revertedwithcustomerror>
    
    }); }); });
- [ok] 
  - Custom Error Code ( Naming Error Code ) :()
  - TDD Catch rejection ;)

VendingMachine Deployment VendingMachine ✔ Should Custom Error OK (132ms)


------
*web 3, Solidity, TDD **passing parameter values** - call functions with parameter values from Typescript Nextjs run Solidity and **Catch Error** when this parameter values make them*
------


------
### step 2.3
#### **TDD [ok,  rejected] function** SafeMath solidity 0.8 default 
------

- contracts/FunctionIntro.sol  
```js
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
// import "hardhat/console.sol";
// function log( uint msg ){ // So we can have a function outside of Contract Instance, like.. tolling purpose reusable piece of soft ;)
//   console.log( msg );
// }
contract FunctionIntro {
  function add(uint x, uint y) external pure returns (uint) {
    return x + y;
  }
  function sub(uint x, uint y) external pure returns (uint) {
    return x - y;
  }
}
  • test/FunctionIntro.ts ```js import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic"; import { expect } from "chai"; import { ethers } from "hardhat";

describe(FunctionIntro, () => { async function deployFixture() { // Contracts are deployed using the first signer/account by default const [owner, otherAccount] = await ethers.getSigners(); const FunctionIntro = await ethers.getContractFactory("FunctionIntro"); const functionIntro = await FunctionIntro.deploy(); return { functionIntro, owner, otherAccount }; } describe(Deployment FunctionIntro, () => { it(Should add a + b = c, async () => { const { functionIntro } = await loadFixture(deployFixture); console.log( await functionIntro.add( 3, 7)); expect( await functionIntro.add( 3, 7) ).to.be.equal(10); // look where the await is ;) }); it(Should sub Reject Arithmetic a - b = d, async () => { const { functionIntro } = await loadFixture(deployFixture); await expect( functionIntro.sub( 3, 7) ).to.be .revertedWithPanic( PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW ); // look where the await is ;) }); it(Should sub a - b = d [ok], async () => { const { functionIntro } = await loadFixture(deployFixture); expect( await functionIntro.sub( 7, 5) ).to.be.equal(2); // look where the await is ;) }); }); });

- [ok] Verify tdd functions 
  - change state
  - rejection status

FunctionIntro Deployment FunctionIntro BigNumber { value: "10" } ✔ Should add a + b = c (167ms) ✔ Should sub Reject Arithmetic a - b = d (38ms) ✔ Should sub a - b = d [ok]


------
*web 3, Solidity,  **Instance State Variables**, **Instance of a Contract** TDD change state variables - call functions that change instance state values from Typescript Nextjs run Solidity and catch Error when this parameter values make them*
------


------
### STEP 3 - Solidity Contract looking for storage memory instance Typescript TDD Hardhat
------
- contracts/Counter.sol
```js
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
contract Counter {
  uint public count;
  function inc() external {
    count += 1;
  }
  function dec() external {
    count -= 1;
  }
}
  • test/Counter.ts
    import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
    import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";
    import { expect } from "chai";
    import { ethers } from "hardhat";
    describe(`Counter`, () => {
    async function deployFixture() {
      // Contracts are deployed using the first signer/account by default
      const [owner, otherAccount] = await ethers.getSigners();
      const Counter = await ethers.getContractFactory("Counter");
      const counter = await Counter.deploy();
      return { counter, owner, otherAccount };
    }
    describe(`Deployment Counter`, () => {
      it(`Should increment storage data in contract Counter`, async () => {
        const { counter } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        expect( await counter.count() ).to.be.equal(0);
        expect( await counter.inc() ).to.be.not.reverted; // look where the await is ;)
        expect( await counter.count() ).to.be.equal(1);
      });
      it(`Should decrement storage data in counter to 0 [ok]`, async () => {
        const { counter } = await loadFixture(deployFixture); // Give an instance 2 of the contract counter
        expect( await counter.count() ).to.be.equal(0);
        expect( await counter.inc() ).to.be.not.reverted; // look where the await is ;)
        expect( await counter.count() ).to.be.equal(1);
        expect( await counter.dec() ).to.be.not.reverted; // look where the await is ;)
        expect( await counter.count() ).to.be.equal(0);
      });
      it(`Should decrement Reject Arithmetic Underflow `, async () => {
        const { counter } = await loadFixture(deployFixture); // Give an instance 3 of the contract counter
        await expect( counter.dec() ).to.be
        .revertedWithPanic( PANIC_CODES.ARITHMETIC_UNDER_OR_OVERFLOW ); // look where the await is ;)
      });
    });
    });
    
  • [ok] Result

    • Instance variable in blockchain contract
    • Change state variable in blockchain
    • Catch rejection of SafeMath Underflow
      ```js npx hardhat test

    Counter Deployment Counter

    ✔ Should increment storage data in contract Counter (1424ms)
    ✔ Should decrement storage data in counter to 0 [ok] (95ms)
    ✔ Should decrement Reject Arithmetic Underflow  (47ms)
    

    FunctionIntro Deployment FunctionIntro BigNumber { value: "10" }

    ✔ Should add a + b = c (167ms)
    ✔ Should sub Reject Arithmetic a - b = d (38ms)
    ✔ Should sub a - b = d [ok]
    

    Lock Deployment

    ✔ Should set the right unlockTime (166ms)
    ✔ Should set the right owner (48ms)
    ✔ Should receive and store the funds to lock
    ✔ Should fail if the unlockTime is not in the future (85ms)
    

    Withdrawals

    Validations
    

    Unlock time is '1689450825' and block timestamp is '1657914827'

      ✔ Should revert with the right error if called too soon (59ms)
    

    Unlock time is '1689450825' and block timestamp is '1689450826'

      ✔ Should revert with the right error if called from another account (75ms)
    

    Unlock time is '1689450825' and block timestamp is '1689450826'

      ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it (80ms)
    Events
    

    Unlock time is '1689450825' and block timestamp is '1689450826'

      ✔ Should emit an event on withdrawals (57ms)
    Transfers
    

    Unlock time is '1689450825' and block timestamp is '1689450826'

      ✔ Should transfer the funds to the owner (70ms)
    

    SafeMath Deployment Safe Math

    ✔ Should check Underflow OK (140ms)
    ✔ Should NOT check or uncheck Underflow calculus error prone.
    

    VendingMachine Deployment VendingMachine

    Should Custom Error OK (132ms)
    

    18 passing (3s) ```



web 3, Solidity, Modifiers TDD add/extract/refactor restrictions/guards/validations - call functions that change instance state values from Typescript Nextjs run Solidity and catch Error when this conditions din't pass the guard/validation/restriction/constraint


STEP 4 - Solidity Modifier TDD Typescript Hardhat


  • Solidity Modifiers

    • Always check isolated code
    • When there is an error or problem, isolate the problem
  • contracts/FunctionModifier.sol

    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.9;
    contract FunctionModifier {
    bool public paused;
    uint public count;
    function setPaused(bool _paused) external {
      paused = _paused;
    }
    modifier whenNotPaused(){
      require(!paused, "Paused");
      _;
    }
    function inc() external whenNotPaused {
      count += 1;
    }
    function dec() external whenNotPaused {
      count -= 1;
    }
    modifier cap(uint _x){
      require(_x < 100, "x >= 100");
      // execute some code Before the main thread
      _; // execute back the main thread
      // execute some code After the main thread ( sandwich )
    }
    function incBy(uint _x) external whenNotPaused cap(_x) {
      count += _x;
    }
    }
    
  • test/FunctionModifier.ts
    import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
    import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";
    import { expect } from "chai";
    import { ethers } from "hardhat";
    describe(`FunctionModifier`, () => {
    async function deployFixture() {
      // Contracts are deployed using the first signer/account by default
      const [owner, otherAccount] = await ethers.getSigners();
      const FunctionModifier = await ethers.getContractFactory("FunctionModifier");
      const functionModifier = await FunctionModifier.deploy();
      return { functionModifier, owner, otherAccount };
    }
    describe(`Deployment FunctionModifier`, () => {
      it(`Should increment`, async () => {
        const { functionModifier } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        expect( await functionModifier.count() ).to.be.equal(0);
        expect( await functionModifier.inc() ).to.be.not.reverted; // look where the await is ;)
        expect( await functionModifier.count() ).to.be.equal(1);
      });
      it(`Should decrement`, async () => {
        const { functionModifier } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        expect( await functionModifier.count() ).to.be.equal(0);
        expect( await functionModifier.inc() ).to.be.not.reverted; // look where the await is ;)
        expect( await functionModifier.count() ).to.be.equal(1);
        expect( await functionModifier.dec() ).to.be.not.reverted; // look where the await is ;)
        expect( await functionModifier.count() ).to.be.equal(0);
      });
      it(`Should Revert "Paused" - modifier `, async () => {
        const { functionModifier } = await loadFixture(deployFixture); // Give an instance 3 of the contract counter
        await functionModifier.setPaused(true);
        await expect( functionModifier.dec() ).to.be
        .revertedWith( "Paused" ); // look where the await is ;)
      });
      it(`Should Revert "x >= 100" - modifier `, async () => {
        const { functionModifier } = await loadFixture(deployFixture); // Give an instance 3 of the contract counter
        await expect( functionModifier.incBy(200) ).to.be
        .revertedWith( "x >= 100" ); // look where the await is ;)
      });
    });
    });
    
  • [ok] Result - TDD modifier catch rejection revert assert

    npx hardhat test test/FunctionModifier.ts
    
    FunctionModifier
      Deployment FunctionModifier
        ✔ Should increment (1515ms)
        ✔ Should decrement (164ms)
        ✔ Should Revert "Paused" - modifier  (97ms)
        ✔ Should Revert "x >= 100" - modifier  (48ms)
    
    4 passing (2s)
    

STEP 5 - Solidity constructor() TDD Typescript Hardhat


  • Solidity constructor() methods in contracts

    • Let see some console.log() in solidity Thanks Hardhat Team
    • https://hardhat.org/tutorial/debugging-with-hardhat-network
    • inspect contract with console.log ethereum
    • https://docs.soliditylang.org/en/v0.8.13/introduction-to-smart-contracts.html
    • https://docs.soliditylang.org/en/v0.8.13/units-and-global-variables.html#special-variables-functions
    • data and variables in the contract block ( now I want to see them ;)
      Block and Transaction Properties
      blockhash(uint blockNumber) returns (bytes32): hash of the given block when blocknumber is one of the 256 most recent blocks; otherwise returns zero
      block.basefee (uint): current block’s base fee (EIP-3198 and EIP-1559)
      block.chainid (uint): current chain id
      block.coinbase (address payable): current block miner’s address
      block.difficulty (uint): current block difficulty
      block.gaslimit (uint): current block gaslimit
      block.number (uint): current block number
      block.timestamp (uint): current block timestamp as seconds since unix epoch
      gasleft() returns (uint256): remaining gas
      msg.data (bytes calldata): complete calldata
      msg.sender (address): sender of the message (current call)
      msg.sig (bytes4): first four bytes of the calldata (i.e. function identifier)
      msg.value (uint): number of wei sent with the message
      tx.gasprice (uint): gas price of the transaction
      tx.origin (address): sender of the transaction (full call chain)
      
  • [error] ok I forget to add a parameter value to call the constructor( _ ) ``` npx hardhat test test/Constructor An unexpected error occurred:

test/Constructor.ts:12:43 - error TS2554: Expected 1-2 arguments, but got 0.

12 const constructor = await Constructor.deploy();

                                         ~~~~~~~~

typechain-types/factories/Constructor__factory.ts:77:5 77 _x: PromiseOrValue, ~~~~~~~~ An argument for '_x' was not provided.


- [ok] first test Constructor solidity contract, hardhat tdd typescript console log
  - contracts/Constructor.sol
```js
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
// Import this file to use console.log
import "hardhat/console.sol";
contract Constructor { // this name Constuctor can be contract Banana but methods **constructor()** is reserved for any contractName as **constructor**
  address public owner;
  uint public x;
  constructor(uint _x){
    owner = msg.sender;
    x = _x;
    console.log("msg.sender:  %s", msg.sender);
    //console.log("msg.value: %o", msg.value); // only on payable constructor
    //console.log("msg.sig:   %o", msg.sig); 
    //console.log("msg.data:  %o", msg.data);
  }
}
  • test/Constructor.ts
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { ethers } from "hardhat";
const TEST_UINT_OK = 123;
describe(`Constructor`, () => {
  async function deployFixture() {
    // Contracts are deployed using the first signer/account by default
    const [owner, otherAccount] = await ethers.getSigners();
    const Constructor = await ethers.getContractFactory("Constructor");
    const constructor = await Constructor.deploy(TEST_UINT_OK);
    return { constructor, owner, otherAccount };
  }
  describe(`Deployment Constructor`, () => {
    it(`Should call Constructor, and show some debug info as tutorial weekly59`, async () => {
      const { constructor } = await loadFixture(deployFixture); // Give one **Constructor** instance.
      expect( await constructor.x() ).to.be.equal(TEST_UINT_OK);
    });
  });
});
  • [ok] Result, First call test Constructor console log msg sender
npx hardhat test test/Constructor
  Constructor
    Deployment Constructor
msg.sender:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
      ✔ Should call Constructor, and show some debug info as tutorial weekly59 (1650ms)
  1 passing (2s)
  • contracts/Constructor.sol more log tx block msg
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
// Import this file to use console.log
import "hardhat/console.sol";
contract Constructor { // this name Constuctor can be contract Banana but methods **constructor()** is reserved for any contractName as **constructor**
  address public owner;
  uint public x;
  constructor(uint _x){
    owner = msg.sender;
    x = _x;
    console.log("msg.sender:  %s", msg.sender);
    console.log("tx.origin:  %s", tx.origin);
    console.log("tx.gasprice:  %s", tx.gasprice);
    console.log("block.timestamp:  %s", block.timestamp);
    console.log("block.number:  %s", block.number);
    console.log("block.chainid:  %s", block.chainid);
  }
}
  • [ok] Result more Constructor.sol more log tx block msg
npx hardhat test test/Constructor
Compiled 1 Solidity file successfully
  Constructor
    Deployment Constructor
msg.sender:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
tx.origin:  0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
tx.gasprice:  1875000000
block.timestamp:  1658154619
block.number:  1
block.chainid:  31337
      ✔ Should call Constructor, and show some debug info as tutorial weekly59 (1839ms)
  1 passing (2s)

STEP 5 - Solidity state global error TDD Typescript Hardhat


  • contracts/Ownable.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.9;
    error OWNABLE__NOT_OWNER();
    error OWNABLE__INVALID_ADDRESS();
    contract Ownable {
    address public owner;
    constructor(){
      owner = msg.sender;
    }
    modifier onlyOwner() {
      if ( msg.sender != owner ) {
        revert OWNABLE__NOT_OWNER();
      }
      _; // continue execution of main thread
    }
    function setOwner(address _newOwner) external onlyOwner {
      if( _newOwner ==  owner ){ //address(0) ){
        revert OWNABLE__INVALID_ADDRESS();
      }
      owner = _newOwner;
    }
    function onlyOwnerCanCallThisFunction() external onlyOwner {    
    }
    function anyOneCanCallThisFunction() external {
    }
    }
    
  • test/Ownable.ts
    import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
    import { expect, assert } from "chai";
    import { ethers } from "hardhat";
    describe(`Ownable`, () => {
    async function deployFixture() {
      // Contracts are deployed using the first signer/account by default
      const [owner, otherAccount] = await ethers.getSigners();
      const Ownable = await ethers.getContractFactory("Ownable");
      const ownable = await Ownable.deploy();
      return { ownable, owner, otherAccount };
    }
    describe(`Deployment Ownable`, () => {
      it(`Should owner call ok`, async () => {
        const { ownable } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        expect( await ownable.onlyOwnerCanCallThisFunction() ).ok;
      });
      it(`Should not owner call rejected`, async () => {
        const { ownable, otherAccount } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        expect( await ownable.setOwner(otherAccount.address) ).to.be.ok;      
        try{
          await ownable.onlyOwnerCanCallThisFunction();
          assert.fail();        
        }catch(err){
          assert.isOk;
        }
      });
      it(`Should not owner call ok`, async () => {
        const { ownable, otherAccount } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        expect( await ownable.setOwner(otherAccount.address) ).to.be.ok;
        await expect( ownable.anyOneCanCallThisFunction() ).to.be.ok;
      });
      it(`Should reject same owner not change ownership rejected`, async () => {
        const { ownable, owner ,otherAccount } = await loadFixture(deployFixture); // Give an instance 1 of the contract counter
        try{
          await ownable.setOwner(owner.getAddress());
          assert.fail();        
        }catch(err){
          assert.isOk;
        }
      });
    });
    });
    
  • [ok] Result Ownable ``` npx hardhat test test/Ownable Ownable Deployment Ownable
    ✔ Should owner call ok (1536ms)
    ✔ Should not owner call rejected (128ms)
    ✔ Should not owner call ok (48ms)
    ✔ Should reject same owner not change ownership rejected (80ms)
    
    4 passing (2s)

------
- Struct - Object - Array - no execution code
```js
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
contract Structs {
  struct Car {
    string model;
    uint year;
    address owner;
  }
  Car public car;
  Car[] public cars;
  mapping( address => Car[] ) public carsByOwner;
  function examples() external  {
    Car memory toyota = Car("Toyota", 2020, msg.sender); // memory execution of the funcion
    Car memory lambo =  Car({ model: "Lamborghini", year: 2020, owner: msg.sender});
    // memory - ReadOnly data
    // storage - Write data in storage/blockchain state
    cars.push(toyota);
    cars.push(lambo);
    carsByOwner[msg.sender] = cars;
  }
  function exampleCallable(uint[] calldata y) external pure { // calldata by reference, memory by value
    _internal(y);
  }
  function _internal(uint[] memory _y) private pure {
    uint x = _y[0];
    x;
  }
}

web 3, Solidity, Events Emit TDD emit Soliditi event, and Receive in Typescript the Event


STEP 6 - Solidity event emit TDD Typescript Hardhat


  • Events
    • contracts/Events.sol
      // SPDX-License-Identifier: MIT
      pragma solidity 0.8.9;
      contract Events {
      event Log(string message, uint val);
      function example() external { // is a transactional function, not readonly or view because of the emit data
      emit Log("Thing the best of Others", 123456);
      }
      }
      
    • test/Events.ts
      import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
      import { expect, assert } from "chai";
      import { ethers } from "hardhat";
      describe(`Events`, () => {
      async function deployFixture() {
      const [owner, otherAccount] = await ethers.getSigners();
      const Events = await ethers.getContractFactory("Events");
      const events = await Events.deploy();
      return { events, owner, otherAccount };
      }
      describe(`Deployment Events`, () => {
      it(`Should check Event emit Log`, async () => {
        const { events } = await loadFixture(deployFixture);
        await expect( events.example() ).to.be.emit(events, "Log"); // Goooood ;)
        assert.isOk;
      });
      });
      });
      
    • [ok] Result
      npx hardhat test test/Events
      Events
      Deployment EventsShould  (1428ms)
      1 passing (1s)
      

  • constract/Inheritance.sol
    // SPDX-License-Identifier: MIT
    pragma solidity 0.8.9;
    contract Dad {
    function speak() public pure virtual returns (string memory){
    return "Sempre Avanti!";
    }
    }
    contract Son is Dad {
    function speak() public pure virtual override returns (string memory){
    return "Always Moving Forward!";
    }
    }
    contract Nipote is Son {
    function speak() public pure override returns (string memory){
    return "Siempre Hacia Adelante!";
    }
    }
    


{

name: "Maximiliano Usich",

email: "",

role: ["Husband", "Dad", "Software Developer", "Mentor", "Full Stack nodejs Javascript Typescript"],

github: https://github.com/maximilianou,

wallet: ,

eth: ipns://simpledoers.eth,

eth-https: https://simpledoers.eth.limo,

codersrank: https://profile.codersrank.io/user/maximilianou,

aCryptoCoffe: https://www.buymeacryptocoffee.xyz/simpledoers.eth,

aCoffe: https://www.buymeacoffee.com/simpledoers,

mirror: https://mirror.xyz/simpledoers.eth/subscribe,

twitter: https://twitter.com/maximilianou,

indeed: https://my.indeed.com/p/maximilianou-s1rmnyx,

linkedin: https://www.linkedin.com/in/maximilianou/

}