Truffle on wsl

## Originally

I have copied the code from the following book.
[Hands-On Smart Contract Development with Solidity and Ethereum](https://www.oreilly.com/library/view/hands-on-smart-contract/9781492045250/)

## Environment

- Windows 11
- wsl2
- Ubuntu 18.04
- nvm : 0.39.0
- node : 16.13.2
- npm : 8.1.2
- Truffle v5.4.30 (core: 5.4.30)
- Solidity - 0.8.11 (solc-js)
- Node v16.13.2
- Web3.js v1.5.3

## Prepare

wsl2
https://docs.microsoft.com/en-us/windows/wsl/install

open ubuntu on wsl.

nvm
https://github.com/nvm-sh/nvm

## Install Truffle

```bash:command
# sometime you should install gcc and package before.
# sudo apt install g++-7 libstdc++-7-dev
nvm install 16.13.2 # DO NOT USE >=17.0.0
nvm use 16.13.2
npm i -g truffle  # DO NOT USE sudo
```

## Create Project and Greeter Contract

```bash:command
mkdir greeter
cd greeter
truffle init
truffle create contract Greeter
truffle create test Greeter
truffle create migration Greeter
```

## Install prettier for vscode

```bash:command
npm install --save-dev prettier prettier-plugin-solidity
code --install-extension esbenp.prettier-vscode
code --install-extension JuanBlanco.solidity
```

```json:.vscode/settings.json
{
  "editor.formatOnSave": true,
  "solidity.formatter": "prettier",
  "[solidity]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}
```

```js:prettier.config.js
module.exports = {
  overrides: [
    {
      files: "*.sol",
      options: {
        printWidth: 80,
        tabWidth: 2,
        useTabs: false,
        singleQuote: false,
        bracketSpacing: false,
        explicitTypes: "always",
      },
    },
  ],
};
```


## Edit Migration File
Edit migration file. It may in `./migraionts` folder

```js:migrations/12345678_greeter.js
const Greeter = artifacts.require("Greeter");
module.exports = function(_deployer) {
  _deployer.deploy(Greeter);
};
```

## Run First Test

```bash:command
truffle test
# Using network 'test'.
#Compiling your contracts...
#===========================
#> Compiling ./contracts/Greeter.sol
#> Compiling ./contracts/Migrations.sol
#> Compilation warnings encountered:
#> Artifacts written to /tmp/test--2064-vQs8uxlslsyw
#> Compiled successfully using:
#   - solc: 0.8.11+commit.d7f03943.Emscripten.clang
#
#  Contract: Greeter
#    ✓ should assert true
#
#  1 passing (20ms)
```

If you have some compile errors, please read [this article](https://qiita.com/daei/items/eb911ab5b979de1dcdb7).


## Hello World!

```solidity:contracts/Greeter.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
// remove constructor
contract Greeter {
  function greet() external pure returns(string memory){
    return "Hello, World!";
  }
}
```

```js:test/greeter.js
const Greeter = artifacts.require("Greeter");
contract("Greeter", function (/* accounts */) {
  it("should assert true", async function () {
    await Greeter.deployed();
    return assert.isTrue(true);
  });
describe("greet()", () => {
    it("returns 'Hello, World!'", async () => {
      const greeter = await Greeter.deployed();
      const expected = "Hello, World!";
      const actual = await greeter.greet();
      assert.equal(actual, expected, "greeted with'Hello, World!'");
    })
  })
});
```
```bash:command
truffle test
#  Contract: Greeter
#    ✓ should assert true
#    greet()
#      ✓ returns 'Hello, World!'
#
#  2 passing (31ms)
```

## Update Message
So far it has only returned a fixed "Hello World!", but I will try to update the message.

```solidity:contracts/Greeter.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract Greeter {
  string private _greeting = "Hello, World!";

  function greet() external view returns (string memory) {
    return _greeting;
  }

  function setGreeting(string calldata greeting) external {
    _greeting = greeting;
  }
}
```

```js:test/greeter.js
const Greeter = artifacts.require("Greeter");
contract("Greeter", function (/* accounts */) {
  it("should assert true", async function () {
    await Greeter.deployed();
    return assert.isTrue(true);
  });
  describe("greet()", () => {
    it("returns 'Hello, World!'", async () => {
      const greeter = await Greeter.deployed();
      const expected = "Hello, World!";
      const actual = await greeter.greet();
      assert.equal(actual, expected, "greeted with 'Hello, World!'");
    });
  });
});
contract("Greeter: update greeting", function (/* accounts */) {
  it("sets greeting to passed in string", async function () {
    const greeter = await Greeter.deployed();
    const expected = "Hi there!";
    await greeter.setGreeting(expected);
    const actual = await greeter.greet();
    assert.equal(actual, expected, "greeing updated'");
  });
});
```
```bash:command
truffle test
#  Contract: Greeter
#    ✓ should assert true
#    greet()
#      ✓ returns 'Hello, World!'
#  Contract: Greeter: update greeting
#    ✓ sets greeting to passed in string (1060ms)```
#  3 passing (1s)
```
## Check Ownership

Ensure that only the Owner can update messages.

```solidity:contracts/Greeter.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

contract Greeter {
  string private _greeting = "Hello, World!";
  address private _owner;

  constructor() {
    _owner = msg.sender;
  }

  modifier onlyOwner() {
    require(msg.sender == _owner, "Ownable: caller is not the owner");
    _;
  }

  function greet() external view returns (string memory) {
    return _greeting;
  }

  function setGreeting(string calldata greeting) external onlyOwner {
    _greeting = greeting;
  }

  function owner() public view returns (address) {
    return _owner;
  }
}
```

```js:test/greeter.js
const Greeter = artifacts.require("Greeter");
contract("Greeter: update greeting", (accounts) => {
  describe("when  message is sent by the owner", () => {
    it("sets greeting is sent by the owner", async () => {
      const greeter = await Greeter.deployed();
      const expected = "The owner changed the mssage";
      await greeter.setGreeting(expected);
      const actual = await greeter.greet();
      assert.equal(actual, expected, "greeting updated");
    });
  });
  describe("when message is sent by another account", () => {
    it("does not set the greeting", async () => {
      const greeter = await Greeter.deployed();
      const expected = await greeter.greet();
      try {
        await greeter.setGreeting("Not the owner", { from: accounts[1] });
      } catch (err) {
        const errorMessage = "Ownable: caller is not the owner";
        assert.equal(err.reason, errorMessage, "greeting should not update");
        return;
      }
      assert(false, "greeting shoud not update");
    });
  });
});
```
```bash:command
truffle test
#  Contract: Greeter: update greeting
#    when  message is sent by the owner
#      ✓ sets greeting is sent by the owner (1066ms)
#    when message is sent by another account
#      ✓ does not set the greeting (1083ms)
#  2 passing (2s)
```

## Use OpenZeppelin

Use OpenZeppelin module.

```bash:command
npm init -y
npm i openzeppelin-solidity
```


```solidity:contracts/Greeter.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
import "openzeppelin-solidity/contracts/access/Ownable.sol";

contract Greeter is Ownable {
  string private _greeting = "Hello, World!";

  function greet() external view returns (string memory) {
    return _greeting;
  }

  function setGreeting(string calldata greeting) external onlyOwner {
    _greeting = greeting;
  }
}
```

## [Next Step](https://qiita.com/daei/items/84c55dbe03ebb81da162)