問題1:カウンターを作る
誰でも呼べるincrement、所有者だけが0へ戻せるreset、現在値を返すcurrentを持つCounterを作ってください。
確認ポイント
- ownerをconstructorで保存する
- resetにアクセス制御を付ける
- reset後の値が0であることを確認する
解答例SOLIDITY
contract Counter {
address public owner;
uint256 public count;
constructor() { owner = msg.sender; }
modifier onlyOwner() {
require(msg.sender == owner, "owner only");
_;
}
function increment() external { count += 1; }
function reset() external onlyOwner { count = 0; }
function current() external view returns (uint256) {
return count;
}
}実行結果OUTPUT
increment() → count: 1
ownerでreset() → count: 0
owner以外でreset() → revert "owner only"問題2:一人一票の投票
候補者名を配列に追加し、アドレスごとに投票済みかをmappingで記録してください。投票時には候補者番号を受け取り、範囲外ならrevertし、Votedイベントを発行します。
解答の中心部分SOLIDITY
mapping(address => bool) public voted;
uint256[] public votes;
event Voted(address indexed voter, uint256 indexed candidate);
function vote(uint256 candidate) external {
require(!voted[msg.sender], "already voted");
require(candidate < votes.length, "invalid candidate");
voted[msg.sender] = true;
votes[candidate] += 1;
emit Voted(msg.sender, candidate);
}実行結果OUTPUT
Account 0でvote(0) → votes[0]: 1
Account 0で再度vote(0) → revert "already voted"
Account 1でvote(1) → Votedイベント、votes[1]: 1候補者の追加を誰でもできるのか、投票期間を設けるのかは別の要件です。仕様にない権限を勝手に追加せず、必要なら設計として明記します。
問題3:入金箱を設計する
Etherを受け取り、入金者の累計額を記録し、所有者だけが全額を引き出せるTipJarを作ってください。入金時にはイベントを出し、送金失敗時はrevertし、送金前に状態を更新します。
解答例は学習用
Etherを扱う本番コントラクトには、再入可能性、ガス制限、権限管理、緊急停止、監査など追加の検討が必要です。
最小の骨格SOLIDITY
mapping(address => uint256) public deposited;
event Deposited(address indexed from, uint256 amount);
function deposit() external payable {
require(msg.value > 0, "zero value");
deposited[msg.sender] += msg.value;
emit Deposited(msg.sender, msg.value);
}実行結果OUTPUT
Account 0でdeposit(0.1 ether) → deposited[Account 0]: 0.1 ether
Depositedイベント → from: Account 0, amount: 0.1 ether振り返り
各問題を解くときは、コードを書く前に「状態」「権限」「成功条件」「失敗条件」「外部へ知らせるイベント」を表にします。次の発展テーマは、OpenZeppelinの既存実装、ERC-20/ERC-721、フロントエンドとのABI連携、HardhatやFoundryの自動テストです。