読了時間:5分
概要
スマートコントラクトとやり取りする際、ABIは不可欠な要素の一つです。このガイドでは、スマートコントラクトのABIとは何かについて理解していきましょう。
動画による解説をご希望ですか?ラデクと一緒に、11分でABIについて学びましょう。
ABIとは何ですか?
コンピュータサイエンスにおけるABI(アプリケーション・バイナリ・インターフェース)とは、2つのプログラムモジュール間のインターフェースであり、多くの場合、オペレーティングシステムとユーザープログラムの間で用いられる。
EVM(イーサリアム仮想マシン)はイーサリアムネットワークの中核をなすコンポーネントであり、スマートコントラクトとは、イーサリアムブロックチェーン上に保存され、EVM上で実行されるコードの断片のことです。SolidityやVyperといった高水準言語で記述されたスマートコントラクトは、EVMで実行可能なバイトコードにコンパイルされる必要があります。スマートコントラクトがデプロイされると、このバイトコードはブロックチェーン上に保存され、あるアドレスに関連付けられます。 イーサリアムおよびEVMにとって、スマートコントラクトとはまさにこのバイトコードのシーケンスに他なりません。高水準言語で定義された関数にアクセスするには、ユーザーは名前や引数をバイト表現に変換し、バイトコードがそれを処理できるようにする必要があります。 応答として送信されたバイト列を解釈するには、ユーザーはそれらを、高水準言語で定義された戻り値のタプルに逆変換する必要があります。EVM向けにコンパイルされる言語は、これらの変換に関して厳格な規約を定めていますが、変換を行うためには、各操作に関連付けられた正確な名前と型を知っている必要があります。ABIは、これらの名前と型を正確かつ解析しやすい形式で文書化しており、人間が意図したメソッド呼び出しとスマートコントラクトの操作との間の変換を、発見しやすく信頼性の高いものにしています。
これは、コードのインターフェースを人間が読み取れる形で表現したAPI(アプリケーション・プログラミング・インターフェース)と非常によく似ています。ABIは、APIと同様に、バイナリ契約とやり取りするために使用されるメソッドや構造体を定義しますが、APIよりも低レベルで定義されます。 ABIは、関数の呼び出し側に対し、関数シグネチャや変数宣言などの必要な情報を、EVMが理解できる形式でエンコードし、バイトコードとしてその関数を呼び出すよう指示します。これをABIエンコーディングと呼びます。ABIエンコーディングは主に自動化されており、REMIXのようなコンパイラや、ブロックチェーンとやり取りするウォレットによって処理されます。コントラクトのABIはJSON形式で表現されます。コントラクトのABIをエンコードおよびデコードする方法については、明確な仕様が定められています。
ABIの構成要素について
契約のABIのJSON形式は、さまざまな関数やイベントの説明によって定義されます。
関数のABI記述には、以下の要素が含まれます:
- type: 関数の型を定義します。以下のいずれかになります。「function」、「constructor」、「receive」(receive 関数用)、または「fallback」(デフォルト関数用)。
- name: 関数の名前を指定します。
- 入力: これはパラメータを定義するオブジェクトの配列であり、各オブジェクトには以下の要素が含まれます:
- name: パラメータの名前を指定します。
- type: パラメータの正規型を定義します。例:uint256。
- components: タプル型を定義するために使用されます。タプル型に到達した場合、それは type = tuple [タプル要素のその他のプロパティ(名前や型など)をここに記述] の形式で表されます。
- outputs:inputsと同様に、出力オブジェクトの配列です。
- stateMutability: 関数の可変性を定義します。以下のいずれかの値をとることができます:「pure」(ブロックチェーンの状態を読み書きしないことを指定)、「view」(ブロックチェーンの状態を読み取ることはできるが、変更はできない場合に指定)、 「nonpayable」(これはデフォルトの可変性であり、コード内で関数を記述する際に明示する必要はありません。これは、関数がイーサを受け付けないことを意味し、これを使用するとブロックチェーンの状態を読み書きできます)、 「payable」(これを指定すると、関数がイーサを受け付け、ブロックチェーンの状態を読み書きできることを意味します)。
注:コンストラクタおよびフォールバック関数のABIでは、名前フィールドと出力フィールドが空白になっています。また、フォールバック関数については、入力フィールドも空になっています。
イベントのABI記述には、以下の要素が含まれます:
- type:ここでは、常に「event」となります。
- name: イベントの名前を指定します。
- 入力: これはパラメータを定義するオブジェクトの配列であり、各オブジェクトには以下の要素が含まれます:
- name: パラメータの名前を指定します。
- type: パラメータの正規型を定義します。例:uint256。
- components: タプル型を定義するために使用されます。タプル型に到達した場合、それは type = tuple [タプル要素のその他のプロパティ(名前や型など)をここに記述] の形式で表されます。
- indexed: フィールドがログのトピックの一部である場合は「true」、ログのデータセグメントの一つである場合は「false」となります。
- anonymous:このフィールドは、イベントが契約コード内で「匿名」として宣言されている場合にtrueとなります。
ABIの取得・生成方法は?
最も一般的な方法の一つは、スマートコントラクトのコンパイルが完了した後、Ethereum REMIX IDEの「コンパイル」タブにある「ABI」ボタンを使用してABIをコピーすることです。

もう一つの方法は、Solidityコンパイラ用のJavaScriptバインディング を提供するsolcを使用して、コンパイルを行いABIを生成することです。solcをインストールするには、node.jsに付属するnpmが必要です。お使いのシステムにnode.jsがインストールされているかどうかを確認してください。
$ node -v
インストールされていない場合は、Node.jsのLTS版を公式サイトからダウンロードできます。
それでは、solc をインストールしましょう
$ npm install solc
変数の値を1増やす契約である以下の契約「test.sol」について、ABIをコンパイルして生成します:
上記のコードの説明
1行目:SPDXライセンスタイプの指定。これはSolidity ^0.6.8以降で追加された機能です。スマートコントラクトのソースコードが一般に公開される場合、これらのライセンスは著作権上の問題を解決・回避するのに役立ちます。ライセンスタイプを指定したくない場合は、特別な値「UNLICENSED」を使用するか、コメント全体を省略することもできます(エラーにはならず、警告が表示されるだけです)。
2行目:Solidityのバージョンを宣言しています。
4行目:契約名のテストを開始します。
6行目:count という名前の unsigned integer 型のプライベート変数を宣言し、値 0 を代入しています。
8~10行目:public関数「increment」を宣言しています。この関数は、呼び出されるとcountの値を1増やします。
12~14行目:count の値を符号なし整数として返す public 関数 getCount を宣言しています。
それでは、上記のコントラクトのABIを取得してみましょう。
$ solcjs test.sol --abi
同じディレクトリに「test_sol_test.abi」という名前のファイルが作成されます。このファイルには、次のようなJSON形式のABIが含まれます:
[
{
"inputs": [],
"name": "getCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "increment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
結論
ABIとは何かがわかったところで、次はSolidity やVyperのスマートコントラクトについてさらに学び、独自のスマートコントラクトを作成してみましょう。ABI仕様については、Solidityのドキュメントで詳しく確認してください。
イーサリアムに関する記事やガイドをもっと読みたい方は、ぜひニュースレターにご登録ください。ご意見やご感想がございましたら、Twitterからお気軽にお寄せください。また、Discordコミュニティサーバーでは、これまで出会った中で最もクールな開発者たちが集まっていますので、いつでもお気軽にチャットをお楽しみください :)
