Nobiq
Nobiq

可視性と修飾子

持ち主だけが操作できるボタンの作り方

前回までの自動販売機には問題があります。誰でも setPrice で値段を変えられてしまうのです。今回は「持ち主だけが操作できるボタン」の作り方を学びます。

可視性 = 誰が使えるか

変数や関数に毎回付けてきた public。これは可視性——「誰がそれを使えるか」の指定です。4 種類あります。

指定意味
public誰でも外から使える
privateこのコントラクトの中からしか使えない
internalこのコントラクトと、その子ども(第7回の継承)から使える
external外からしか使えない(中からは使わない前提のボタン)

まずは「外に見せていいものは public、中だけの部品は private」と覚えれば十分です。

require = 門番

require(リクワイア)は、「条件を満たさなければ、そこで処理を中止して巻き戻す」命令です。関数の入り口に立つ門番だと思ってください。

require(条件, "条件を満たさないときのメッセージ");

条件が成り立てばなにもなかったように次へ進み、成り立たなければその操作全体が無かったことになります(途中まで書き換えた記録も巻き戻ります)。

modifier = 使い回せる門番

同じ門番を何個ものボタンに立てたいとき、毎回 require を書くのは大変です。そこでmodifier(モディファイア)——「名前をつけた門番」を作ります。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract VendingMachine {
    address public owner;
    uint256 public price = 120;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    function setPrice(uint256 newPrice) public onlyOwner {
        price = newPrice;
    }
}
  • modifier onlyOwner() = 「onlyOwner という名前の門番」を定義しています。中身は「操作している人(msg.sender)が持ち主(owner)でなければ止める」
  • _; は「門番のチェックを通ったら、ここから本来の手順を実行する」という差し込み位置の印です
  • function setPrice(...) public onlyOwner のように、関数に門番の名前を添えるだけで、そのボタンに門番が立ちます

== は「左と右が等しいか?」の質問です。=(入れる)と別物なので注意。

:::note Lab では onlyOwner が「全員通って」しまいます Lab のボタン操作は、みなさんの代わりに Lab の代行送信者(運営側のアカウント)がブロックチェーンへ送る仕組みです。デプロイも実行も同じ代行送信者なので、owner チェックは常に成立します(=「他人だから弾かれる」体験は Lab ではできません)。書き方と意味を覚えるのが今回のゴールです。本物の世界では、ウォレットごとに msg.sender が異なるので、この門番が資産を守る要になります。 :::

門番に止められる体験をする

せっかくなので、require に止められる体験もしましょう。「値段 0 円はおかしい」という門番を足します。

function setPrice(uint256 newPrice) public onlyOwner {
    require(newPrice > 0, "price must be positive");
    price = newPrice;
}

これをデプロイして、実行画面で setPrice0 を入れて実行すると——ログに ❌ とエラーが出て、price() は元の値のまま。巻き戻しが起きた証拠です。

今回覚えたこと

  • 可視性 = 誰が使えるか。まずは public(公開)と private(内部用)
  • require(条件, "メッセージ") = 門番。条件を満たさなければ操作全体を巻き戻す
  • modifier = 名前をつけた使い回せる門番。_; が本体の差し込み位置

次回は、自動販売機に「売れたら音を鳴らす」——イベントを付けます。

:::tip Lab でやってみる 上の require 入りコードをデプロイし、①setPrice に 150 → 成功、price() が 150 に ②setPrice に 0 → ❌ で巻き戻り、price() は 150 のまま、を確かめましょう。エラーもまた正しい動作です。操作方法: コントラクトを動かす :::