[Ethereum] Hello World!

Solidityでは、入出力などはアクセスできない 関数のみ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const GreeterContract = artifacts.require("Greeter");
 
contract("Greeter", () => {
    it("has been deployed successfully", async() => {
        const greeter = await GreeterContract.deployed();
        assert(greeter, "contract was not deployed");
    });
 
    describe("greet()", () => {
        it("returns 'Hello World!'", async() => {
            const greeter = await GreeterContract.deployed();
            const expected = "Hello World!"
            const actual = await greeter.greet();
            assert.equal(actual, expected, "Greeted with 'Hello World!'")
        })
    })
});

コントラクトに関数を追加

1
2
3
4
5
6
contract Greeter {
     
    function greet() external pure returns(string memory){
        return "Hello World!";
    }
}

$ truffle test
Contract: Greeter
✓ has been deployed successfully
greet()
✓ returns ‘Hello World!’

2 passing (78ms)

状態を変更しない関数は pure または view

### Contractを動的にする
greeter_test.js

1
2
3
4
5
6
7
8
9
10
11
12
13
contract("Greeter: update greeting", ()=> {
    describe("setGreeting(string)", ()=> {
        it("sets greeting to passed in string", async() => {
            const greeter = await GreeterContract.deployed();
            const expected = "Hi there!";
 
            await greeter.setGreeting(expected);
            const actual = await greeter.greet();
 
            assert.equal(actual, expected, "greeting was not updated");
        });
    });
});

Greeter.sol

1
2
3
4
5
6
7
8
9
10
11
contract Greeter {
    string private _greeting = "Hello World!";
     
    function greet() external view returns(string memory){
        return _greeting;
    }
 
    function setGreeting(string calldata greeting) external {
        _greeting = greeting;
    }
}

テストにパスする

### GreeterをOwnableにする
geter関数ownerを呼び出すことで誰が所有者か確認する

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
contract("Greeter", () => {
    it("has been deployed successfully", async() => {
        const greeter = await GreeterContract.deployed();
        assert(greeter, "contract was not deployed");
    });
 
    describe("greet()", () => {
        it("returns 'Hello World!'", async() => {
            const greeter = await GreeterContract.deployed();
            const expected = "Hello World!"
            const actual = await greeter.greet();
            assert.equal(actual, expected, "Greeted with 'Hello World!'")
        })
    })
 
    describe("owner()", () => {
        it("returns the address of the owner", async()=> {
            const greeter = await GreeterContract.deployed();
            const owner = await greeter.owner();
            assert(owner, "the current owner");
        })
    })
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
contract Greeter {
    string private _greeting = "Hello World!";
    address private _owner;
 
    function greet() external view returns(string memory){
        return _greeting;
    }
 
    function setGreeting(string calldata greeting) external {
        _greeting = greeting;
    }
 
    function owner() public view returns(address){
        return _owner;
    }
}

所有者のアドレスがデプロイ元のアドレスと同じであることをテストしたい
truffleではaccounts変数を使ってアカウントにアクセスできる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
contract("Greeter", (accounts) => {
    it("has been deployed successfully", async() => {
        const greeter = await GreeterContract.deployed();
        assert(greeter, "contract was not deployed");
    });
 
    describe("greet()", () => {
        it("returns 'Hello World!'", async() => {
            const greeter = await GreeterContract.deployed();
            const expected = "Hello World!"
            const actual = await greeter.greet();
            assert.equal(actual, expected, "Greeted with 'Hello World!'")
        })
    })
 
    describe("owner()", () => {
        it("returns the address of the owner", async()=> {
            const greeter = await GreeterContract.deployed();
            const owner = await greeter.owner();
            assert(owner, "the current owner");
        });
 
        it("matches the address that originally deployed the contract", async() => {
            const greeter = await GreeterContract.deployed();
            const owner = await greeter.owner();
            const expected = accounts[0];
            assert.equal(owner, expected, "matches address used to deploy contract");
        })
    })
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
contract Greeter {
    string private _greeting = "Hello World!";
    address private _owner;
 
    constructor() public {
        _owner = msg.sender;
    }
 
    function greet() external view returns(string memory){
        return _greeting;
    }
 
    function setGreeting(string calldata greeting) external {
        _greeting = greeting;
    }
 
    function owner() public view returns(address){
        return _owner;
    }
}

$ npm install openzeppelin-solidity

変更前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
pragma solidity >= 0.4.0 < 0.7.0;
 
contract Greeter {
    string private _greeting = "Hello World!";
    address private _owner;
 
    constructor() public {
        _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;
    }
 
 
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
    }
 
}

tuffle-config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
compilers: {
  solc: {
    version: "0.6.0",    // Fetch exact version from solc-bin (default: truffle's version)
    // docker: true,        // Use "0.5.1" you've installed locally with docker (default: false)
    // settings: {          // See the solidity docs for advice about optimization and evmVersion
    //  optimizer: {
    //    enabled: false,
    //    runs: 200
    //  },
    //  evmVersion: "byzantium"
    // }
  }
}

うーむ、普通にやっとるが、レベル高いな…