ブロックチェーン技術の普及にともない、スマートコントラクトへの注目が高まっています。なかでもSolidityは、世界最大のスマートコントラクトプラットフォームであるイーサリアム(Ethereum)向けの開発言語として広く使われています。
スマートコントラクトとは、条件が満たされたときに自動的に実行されるプログラムのことです。仲介者を必要とせず、コードに書かれたルール通りに取引や処理が行われるため、金融・不動産・物流など多くの分野での活用が期待されています。
本記事では、Solidityをまったく触ったことがない方を対象に、言語の特徴から開発環境の構築、最初のコントラクト作成まで順を追って解説します。プログラミングの基礎知識があれば理解しやすい内容ですので、ぜひ最後まで読み進めてみてください。
Solidityとは何か
Solidityの概要と用途
Solidityは2014年にイーサリアムの開発チームによって設計された、静的型付けのオブジェクト指向プログラミング言語です。C++・JavaScript・Pythonの影響を受けており、既存のプログラミング経験者にとって比較的なじみやすい構文を持っています。
主な用途はイーサリアム仮想マシン(EVM:Ethereum Virtual Machine)上で動作するスマートコントラクトの記述です。ERC-20トークンやNFT(ERC-721)、分散型取引所(DEX)、レンディングプロトコルなど、DeFiエコシステムを構成するほとんどのプロトコルがSolidityで書かれています。
スマートコントラクトの仕組み
スマートコントラクトは、ブロックチェーン上にデプロイ(展開)されたコードです。一度デプロイすると基本的には変更できないため、コードの正確さが非常に重要になります。
実行の流れは次のとおりです。まずユーザーがコントラクトにトランザクションを送信します。EVMがコントラクトのバイトコードを実行し、ブロックチェーンの状態(残高・変数など)を更新します。実行にはガス(手数料)が必要で、計算量が多いほど高くなります。
開発環境のセットアップ
Remix IDEを使ったブラウザ開発
Solidityの学習に最も手軽なのがRemix IDE(https://remix.ethereum.org/)です。ブラウザ上で動作するため、インストール不要でコードを書いてコンパイル・デプロイまで試すことができます。
Remixの主な機能として、コードエディタ(シンタックスハイライト・自動補完)、Solidityコンパイラ(複数バージョン対応)、JavaScriptVM・テストネット・メインネットへのデプロイ、デバッガとトランザクション履歴の確認が挙げられます。初学者はまずRemixでコードを書き、動作を確認する習慣をつけるとよいでしょう。
ローカル開発環境(Hardhat・Foundry)
より本格的な開発にはローカル環境が必要です。代表的なフレームワークとしてHardhatとFoundryがあります。
Hardhatはnode.jsベースのイーサリアム開発環境です。テスト・デプロイ・スクリプト実行が一元管理でき、プラグインが豊富な点が特徴です。Foundryはrust製の高速ツールチェーンで、Solidityのみでテストを記述できるためガス最適化にも向いています。
Solidityの基本構文
コントラクトの基本構造
Solidityのファイルは拡張子 .sol で保存します。最もシンプルなコントラクトの構造は以下のようになります。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract SimpleStorage {
uint256 public storedNumber;
function store(uint256 _number) public {
storedNumber = _number;
}
function retrieve() public view returns (uint256) {
return storedNumber;
}
}
最初の行はライセンス識別子で、MITライセンスを指定しています。2行目の pragma solidity でコンパイラバージョンを指定します。^0.8.20 は0.8.20以上0.9.0未満を意味します。
データ型と変数
Solidityには以下のような主要データ型があります。
- uint / int: 符号なし・あり整数(uint256, int128など)
- address: イーサリアムアドレス(20バイト)
- bool: 真偽値(true / false)
- bytes / string: バイト列・文字列
- mapping: キーと値のハッシュマップ
- struct: 複合データ型
- array: 配列(固定長・動的)
変数のスコープには、ステート変数(ブロックチェーンに永続保存)・ローカル変数(関数内のみ)・グローバル変数(msg.sender, block.timestamp など)があります。
関数の書き方
関数の可視性修飾子
Solidityの関数には可視性(visibility)を明示する必要があります。
- public: 外部・内部のどちらからでも呼び出せる
- external: 外部からのみ呼び出せる(ガス効率が良い)
- internal: 同コントラクトおよび継承先から呼び出せる
- private: 同コントラクト内からのみ呼び出せる
関数の種類には、ブロックチェーンの状態を変更する通常の関数、状態を読み取るだけの view 関数、状態もブロックチェーンのデータも読まない pure 関数があります。view と pure はガスを消費しません(直接呼び出しの場合)。
モディファイアとイベント
モディファイア(modifier)は関数の実行前後に共通処理を挟む仕組みです。アクセス制御に多く使われます。
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function withdraw() public onlyOwner {
// オーナーのみ実行可能
}
イベント(event)はトランザクション実行時にログを残す仕組みです。フロントエンドからのリッスンや、オフチェーンでのデータ分析に利用されます。
はじめてのERC-20トークン作成
ERC-20の標準インターフェース
ERC-20はイーサリアム上のトークン規格で、以下の関数が必須です。
totalSupply(): 総発行量を返すbalanceOf(address): 指定アドレスの残高を返すtransfer(address, uint256): トークンを送るapprove(address, uint256): 第三者への送付を承認するtransferFrom(address, address, uint256): 承認された量を送るallowance(address, address): 承認済みの量を確認する
OpenZeppelinというセキュリティ監査済みのライブラリを使うと、安全なERC-20実装を簡単に継承できます。
OpenZeppelinを使ったトークン実装例
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor(address initialOwner)
ERC20("MyToken", "MTK")
Ownable(initialOwner)
{
_mint(msg.sender, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
このコードをRemixに貼り付け、コンパイルしてJavaScript VMにデプロイするだけで、ローカル環境でトークンの転送や残高確認を試すことができます。
セキュリティの基礎:よくある脆弱性
リエントランシー攻撃
リエントランシー(Reentrancy)攻撃は、外部コントラクトへの呼び出し中に再び関数が呼ばれることで残高を不正に引き出す攻撃です。2016年のDAOハック(360万ETH流出)で有名になりました。
対策としては、Checks-Effects-Interactionsパターン(状態変更を外部呼び出しより前に行う)や、OpenZeppelinの ReentrancyGuard モディファイアの使用が有効です。
整数オーバーフローとアクセス制御
Solidity 0.8.0以降はデフォルトでオーバーフロー・アンダーフローを検出してrevertするようになっています。旧バージョン(0.7以前)ではSafeMathライブラリが必要でした。
アクセス制御の不備も重大な脆弱性です。重要な関数には必ず onlyOwner などのモディファイアを付け、誰でも実行できる状態にしないよう注意が必要です。
テストとデプロイの流れ
HardhatでのJavaScriptテスト
Hardhatを使ったテストの基本的な書き方は以下のとおりです。
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("SimpleStorage", function () {
it("Should store and retrieve a value", async function () {
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
const storage = await SimpleStorage.deploy();
await storage.store(42);
expect(await storage.retrieve()).to.equal(42);
});
});
npx hardhat test コマンドでテストを実行できます。本番デプロイ前に必ず全テストをパスさせることが重要です。
テストネットへのデプロイ
本番(メインネット)へのデプロイ前に、テストネットでの動作確認が不可欠です。代表的なテストネットにはSepolia(イーサリアム公式推奨)とGoerli(非推奨、Sepoliaへ移行済み)があります。
Sepoliaへのデプロイにはテスト用のETH(SepoliaETH)が必要で、Infura・Alchemyなどのノードプロバイダを経由して接続します。デプロイスクリプトはHardhat Ignitionを使うと宣言的に管理できます。
まとめ
Solidityはイーサリアムのスマートコントラクト開発に欠かせない言語です。C++やJavaScriptに似た構文を持ち、既存のプログラミング経験があれば比較的スムーズに習得できます。Remix IDEを使えばブラウザだけで学習をスタートできるため、まずはシンプルなコントラクトを作成してデプロイを体験してみることをお勧めします。
セキュリティの観点から、OpenZeppelinなど監査済みライブラリの活用と、テスト駆動開発(TDD)の習慣は非常に重要です。スマートコントラクトは一度デプロイすると原則変更できないため、慎重な設計と十分なテストが求められます。
よくある質問
Q. SolidityはJavaScriptと同じですか?
構文は一部似ていますが、まったく別の言語です。JavaScriptはブラウザやnode.js上で動作しますが、SolidityはEVM(イーサリアム仮想マシン)上で動作するコントラクトを書くために設計されています。型システムや実行モデルが根本的に異なります。
Q. Solidityを学ぶのに必要な前提知識は何ですか?
プログラミングの基礎(変数・関数・条件分岐・ループ)があると理解が早まります。また、ブロックチェーン・イーサリアムの基本概念(トランザクション・ガス・アドレスなど)をある程度把握しておくと、コードの意味が分かりやすくなります。
Q. スマートコントラクトのバグは修正できますか?
一度デプロイしたコントラクトのコードは原則として変更できません。ただし、プロキシパターン(OpenZeppelin UUPSやTransparent Proxyなど)を使って実装コントラクトを差し替えられるよう設計することは可能です。本番デプロイ前のセキュリティ監査とテストが非常に重要な理由の一つです。
※本記事は情報提供を目的としており、投資を推奨するものではありません。暗号資産への投資は元本割れのリスクがあります。投資判断はご自身の責任で行ってください。