はじめに
初めまして。 『DApps開発入門』という本や色々記事を書いているかるでねです。
以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!
今回は「SolidityスマートコントラクトをOpenAPI/Swagger形式で仕様書化する方法」についてまとめていきます。
Solidityスマートコントラクトの開発において、ABI(Application Binary Interface)だけでは関数の目的やエラーの発生条件、イベントの意味を十分に伝えることが難しい場面があります。 特に、チーム開発やクライアントへの説明、フロントエンド開発者との連携において、より詳細で構造化されたドキュメントが求められます。
この記事では、SolidityスマートコントラクトをOpenAPI 3.0(YAML)形式で仕様書化する方法を提案しています。
OpenAPI/Swagger形式で仕様書化するメリット
OpenAPI/Swagger形式で仕様書化することで、以下のメリットがあります。
- 標準化されたフォーマット APIドキュメントの業界標準であるOpenAPI/Swagger形式を使用することで、多くの開発者にとって馴染みのある形式で仕様を共有できます。
- インタラクティブなドキュメント Swagger UI Reactコンポーネントを使って、視覚的で操作可能なドキュメントサイトを構築可能です。
- 型情報の明確化 Solidityの型(address、uint256、bytes32など)をパターン付きで表現し、バリデーションルールを明示できます。
- エラーハンドリングの可視化 カスタムエラーやrevertの条件を構造化して記述できます。
- イベント・構造体の文書化 コントラクトの全要素を網羅的にドキュメント化可能です。
設計方針
目的と制約
この仕様書はHTTP API設計ではなく、Solidityコントラクトのインターフェイス定義をOpenAPI/Swagger形式で記述するためのものです。 HTTPのベストプラクティスに合わせるのではなく、Solidityの挙動を正確かつコンパクトに表現することを最優先にしています。
実際にHTTPで呼び出すことを前提としていません。 Swagger/OpenAPIの制約上、便宜的にパスとHTTPメソッドを割り当てています。
基本ルール
| 項目 | ルール |
|---|---|
| 成功レスポンス | 常にHTTP 200を使用 |
| エラーレスポンス | 常にHTTP 500を使用(4xx系や他の5xx系は使わない) |
| 説明文 | すべて日本語で記述 |
| 識別子の表記 | 変数名、関数名、エラー名などはバッククォート(`)で囲む |
| extensionフィールド | x- で始まるフィールドは使用しない |
パス設計ルール
パスには関数名やイベント名をそのまま使用し、分かりやすい構造を維持します。
| 要素 | パス形式 | HTTPメソッド |
|---|---|---|
| view/pure関数 | /{functionName} |
GET |
| nonpayable/payable関数 | /{functionName} |
POST |
| 変数/定数/Mapping | /{variableName} |
GET |
| イベント | /events/{EventName} |
GET |
| エラー | /errors/{ErrorName} |
GET |
| 構造体 | /structs/{StructName} |
GET |
| Modifier | /modifiers/{ModifierName} |
GET |
パラメータの配置ルール
パラメータは常に query または path で定義し、requestBody は使用しません。
# 正しい例
parameters:
- name: owner
in: query
required: true
# 間違った例(requestBodyは使用しない)
requestBody:
content:
application/json:
schema:
properties:
owner:
type: string継承関係の表現
コントラクトの継承関係は info.description に記載します。
継承しているコントラクト名を箇条書きで列挙します。
info:
title: "MyToken Solidity Interface"
version: "1.0.0"
description: |
MyToken コントラクトの Solidity インターフェイスを OpenAPI 形式で表現した仕様です。
このコントラクトは以下のコントラクトを継承しています。
・ERC20
・Ownable
・Pausable継承元コントラクトの関数やイベント、エラーも仕様書に含めることで、コントラクトの全体像を把握できるようにします。
コントラクト仕様書の構造
スマートコントラクトをOpenAPI/Swagger形式で表現する際の基本構造を説明します。
全体構成
openapi: 3.0.3
info:
title: "コントラクト名 Solidity Interface"
version: "1.0.0"
description: |
コントラクトの説明。
継承関係やネットワーク情報などをここに記載。
tags:
- name: Read Functions
description: Functions that retrieve information from the contract without modifying state.
- name: Write Functions
description: Functions that modify state.
- name: Variables
- name: Constants
- name: Mapping
- name: Events
- name: Errors
- name: Structs
- name: Modifier
x-tagGroups:
- name: Functions
tags:
- Read Functions
- Write Functions
- name: Storage
tags:
- Variables
- Constants
- Mapping
- name: Others
tags:
- Events
- Errors
- Structs
- Modifier
paths:
# 関数、イベント、エラー、構造体のパス定義
components:
schemas:
# ErrorResponse、イベントスキーマ、構造体スキーマタグによるカテゴリ分類
仕様書では以下の9つのタグでコントラクトの要素を分類します。
| タグ | 説明 |
|---|---|
| Read Functions | view/pure関数。ステートを変更せず情報を取得 |
| Write Functions | nonpayable/payable関数。ステートを変更 |
| Variables | publicなstate variable |
| Constants | constant/immutableな値 |
| Mapping | publicなmapping |
| Events | コントラクトで定義されたevent |
| Errors | カスタムエラー |
| Structs | struct定義 |
| Modifier | modifier定義 |
タグ名は英語で統一されています。
Read Functions と Write Functions のみ description が設定され、その他のタグは名前のみです。
各要素の表現方法
スマートコントラクトには、関数、イベント、エラー、変数など、さまざまな要素が含まれています。 これらをOpenAPI/Swagger形式で正確に表現することで、開発者がコントラクトの仕様を理解しやすくなり、フロントエンドやバックエンドとの連携もスムーズになります。
このセクションでは、Solidityの主要な要素それぞれについて、なぜその表現方法を採用するのか、どのように記述するのかを具体例とともに解説していきます。
表現する要素一覧
- 関数(読み取り関数・書き込み関数)
- イベント
- エラー
- 変数・定数
- Mapping
- 構造体
- Modifier
- Solidity型のマッピング
各要素には、その性質に合ったHTTPメソッド(GET、POST)とパス構造を割り当てます。
例えば、ステートを変更しない読み取り関数は GET メソッドで、ステートを変更する書き込み関数は POST メソッドで表現します。
これは、HTTPの設計原則(RESTful API)に従った設計であり、OpenAPI/Swaggerを使い慣れたWeb開発者にとっても理解しやすい形式です。
関数の表現
関数はスマートコントラクトの中核となる要素です。
Solidityの関数には、ステートを変更しない読み取り専用関数(view/pure)と、ステートを変更する書き込み関数(nonpayable/payable)があります。
OpenAPI/Swagger形式では、これらをHTTPメソッドで区別して表現します。
読み取り関数
読み取り関数は、ブロックチェーンのステートを読み取るだけで変更を加えない関数です。
view 修飾子が付いた関数はステート変数の読み取りが可能で、pure 修飾子が付いた関数はステート変数にすらアクセスせず、引数のみから結果を計算します。
これらの関数は、HTTP GET メソッドで表現します。
なぜなら、GETメソッドはデータの取得のみを目的とし、サーバー(この場合はブロックチェーン)のステートを変更しないという性質が、読み取り関数の特性と一致するためです。
引数は parameters フィールドで定義し、in: query または in: path で指定します。
- 基本的な例(引数なし)
/totalSupply:
get:
summary: "totalSupply"
description: |
トークンの総供給量を返します。
この関数はERC20標準で定義されており、現在発行されているトークンの総量を確認できます。
ガス代は発生しません。
operationId: totalSupply
tags:
- Read Functions
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
description: "トークンの総供給量(wei単位)。"
example: "1000000000000000000000000"- 引数ありの例
/balanceOf:
get:
summary: "balanceOf"
description: |
指定されたアカウントのトークン残高を取得します。
ERC20標準関数です。この関数を呼び出すことで、任意のアドレスが保有しているトークンの量を確認できます。
ブロックチェーンのステートを変更しないため、ガス代は発生しません。
operationId: balanceOf
tags:
- Read Functions
parameters:
- name: owner
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "所有者のアドレスを指定します。40桁の16進数文字列である必要があります。"
example: "0x1234567890123456789012345678901234567890"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
description: "指定されたアドレスのトークン残高(wei単位)を返します。"
example: "1000000000000000000"- 複数の引数を持つ例
/allowance:
get:
summary: "allowance"
description: |
`spender` が `owner` から使用を許可されているトークン量を取得します。
ERC20標準関数です。この関数により、あるアドレス(`owner`)が別のアドレス(`spender`)に対して、
どれだけのトークンを使用することを許可しているかを確認できます。
`approve` 関数で設定された許可量が返されます。
operationId: allowance
tags:
- Read Functions
parameters:
- name: owner
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "トークンを所有しているアドレスを指定します。"
example: "0x1234567890123456789012345678901234567890"
- name: spender
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "トークンの使用を許可されたアドレスを指定します。"
example: "0x0987654321098765432109876543210987654321"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
description: "`spender` が使用できる残りのトークン量(wei単位)を返します。"
example: "500000000000000000"各フィールドの意味は以下です。
| フィールド | 説明 | 注意点 |
|---|---|---|
summary |
関数名を指定。Swagger UIのサイドバーに表示される | 冗長な表現(「を取得」など)は避け、関数名のみを記載 |
description |
関数の詳細な説明。マルチライン文字列(|)で複数行記述可能 |
関数の目的、使用場面、注意事項を記載。識別子は必ずバッククォートで囲む |
operationId |
一意の識別子。通常は関数名をそのまま使用 | 他の操作と重複しないように注意 |
tags |
関数の分類。Swagger UIでグループ化される | 読み取り関数は Read Functions タグを使用 |
parameters |
関数の引数。in: query でクエリパラメータとして表現 |
各引数に適切な型とバリデーションルールを設定 |
responses |
戻り値とエラー。成功時は 200、エラー時は 500 |
読み取り関数は通常200レスポンスのみ |
- 型の表現方法
| Solidity型 | OpenAPI表現 | 理由 |
|---|---|---|
address |
type: string, pattern: "^0x[0-9a-fA-F]{40}$" |
40桁の16進数文字列であることをバリデーション |
uint256 |
type: string |
JavaScriptの安全な整数範囲(2^53-1)を超える可能性があるため |
uint8 |
type: integer, minimum: 0, maximum: 255 |
安全な範囲内なので数値型として表現可能 |
bool |
type: boolean |
真偽値はそのまま表現 |
string |
type: string |
文字列型はそのまま表現 |
書き込み関数
書き込み関数は、ブロックチェーンのステートを変更する関数です。
nonpayable 修飾子が付いた関数はEtherを受け取らず、payable 修飾子が付いた関数はEtherを受け取ることができます。
これらの関数は、HTTP POST メソッドで表現します。
POSTメソッドはサーバーのステートを変更する操作を表すため、書き込み関数の特性と一致します。
書き込み関数では、エラーハンドリングが重要になります。 500レスポンスで発生しうるエラーを明示的に記載します。
- 基本的な例
/transfer:
post:
summary: "transfer"
description: |
指定されたアドレスにトークンを転送します。
ERC20標準関数です。この関数を呼び出すと、呼び出し元のアカウントから `to` で指定したアドレスに、
`amount` で指定した量のトークンが転送されます。
トランザクションが成功すると、`Transfer` イベントが発行されます。
残高が不足している場合や、送金先が無効なアドレスの場合はエラーが発生します。
operationId: transfer
tags:
- Write Functions
parameters:
- name: to
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "送金先のアドレスを指定します。ゼロアドレス(`0x0000000000000000000000000000000000000000`)は指定できません。"
example: "0x1234567890123456789012345678901234567890"
- name: amount
in: query
required: true
schema:
type: string
description: "トークン量を指定します(wei単位)。呼び出し元の残高以下である必要があります。"
example: "1000000000000000000"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: boolean
description: "送金が成功した場合 `true` を返します。"
example: true
"500":
description: "この関数で発生しうるエラーの一覧です。\n\n・InsufficientBalance\n\n・InvalidAddress"
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
InsufficientBalance:
summary: "残高不足"
value:
message: "InsufficientBalance"
data: {}
InvalidAddress:
summary: "無効なアドレス"
value:
message: "InvalidAddress"
data: {}- 複雑な例(複数のエラーパターンを持つ関数)
/transferFrom:
post:
summary: "transferFrom"
description: |
第三者が所有者の代わりにトークンを転送します。
ERC20標準関数です。この関数は、`approve` 関数で事前に許可された量の範囲内で、
`from` アドレスから `to` アドレスにトークンを転送します。
呼び出し元は、`from` アドレスから十分な許可量(allowance)を得ている必要があります。
転送が成功すると、`Transfer` イベントが発行され、許可量が減少します。
operationId: transferFrom
tags:
- Write Functions
parameters:
- name: from
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "トークンの転送元アドレスを指定します。このアドレスから `amount` 分のトークンが引き出されます。"
example: "0x1234567890123456789012345678901234567890"
- name: to
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "トークンの転送先アドレスを指定します。ゼロアドレスは指定できません。"
example: "0x0987654321098765432109876543210987654321"
- name: amount
in: query
required: true
schema:
type: string
description: "転送するトークン量を指定します(wei単位)。呼び出し元の許可量以下である必要があります。"
example: "1000000000000000000"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: boolean
description: "転送が成功した場合 `true` を返します。"
example: true
"500":
description: "この関数で発生しうるエラーの一覧です。\n\n・InsufficientBalance\n\n・InsufficientAllowance\n\n・InvalidSender\n\n・InvalidReceiver"
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
InsufficientBalance:
summary: "残高不足"
value:
message: "InsufficientBalance"
data:
account: "0x1234567890123456789012345678901234567890"
balance: "500000000000000000"
required: "1000000000000000000"
InsufficientAllowance:
summary: "許可量不足"
value:
message: "InsufficientAllowance"
data:
spender: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
allowance: "500000000000000000"
required: "1000000000000000000"
InvalidSender:
summary: "無効な送信者アドレス"
value:
message: "InvalidSender"
data:
sender: "0x0000000000000000000000000000000000000000"
InvalidReceiver:
summary: "無効な受信者アドレス"
value:
message: "InvalidReceiver"
data:
receiver: "0x0000000000000000000000000000000000000000"書き込み関数特有のフィールドは以下です。
| フィールド | 説明 | 注意点 |
|---|---|---|
responses["500"] |
エラーレスポンス。description にエラー一覧を箇条書きで記載 |
各エラーの間には \n\n で空行を入れる |
examples |
各エラーの具体例。エラー名をキーに summary と value を指定 |
エラーに引数がある場合は data フィールドに含める |
$ref |
共通スキーマの参照。#/components/schemas/ErrorResponse で形式を統一 |
すべてのエラーで同じスキーマを使用 |
エラーはすべてHTTP 500で表現し、200と500以外のステータスコードは使用しません。
これは、Solidityの revert やカスタムエラーを統一的に表現するための設計方針です。
HTTPの4xx系エラー(クライアントエラー)と5xx系エラー(サーバーエラー)の区別は、スマートコントラクトの文脈では意味を持たないため、500に統一しています。
エラーレスポンスの詳細
エラーレスポンスは、書き込み関数において特に重要な要素です。
Solidityでは、revert、require、カスタムエラーなど複数のエラーハンドリング方法があり、これらを統一的に表現する必要があります。
ErrorResponseスキーマ
すべてのエラーは共通の ErrorResponse スキーマを使用します。
このスキーマは、エラーの種類に関わらず一貫した形式でエラー情報を提供するために設計されています。
components:
schemas:
ErrorResponse:
type: object
description: "コントラクト呼び出し時のエラー情報を表現する共通スキーマです。"
properties:
message:
type: string
description: "カスタムエラー名またはrevert/requireのメッセージ文字列。"
data:
type: object
description: "追加情報(任意)。カスタムエラーが引数を持つ場合、その値をここに格納します。"- スキーマの構成要素
| フィールド | 型 | 説明 | 例 |
|---|---|---|---|
message |
string |
エラー名またはメッセージ | "InsufficientBalance", "Amount must be greater than zero" |
data |
object |
エラーの詳細情報(オプション) | {"balance": "100", "required": "1000"} |
message フィールドには、Solidityのカスタムエラー名(例: InsufficientBalance)または、revert()/require() で指定した文字列メッセージが入ります。
data フィールドには、カスタムエラーが引数を持つ場合、その引数の値を格納します。
例えば、以下のようなSolidityエラーの場合には、
error InsufficientBalance(address account, uint256 balance, uint256 required);data フィールドは以下のようになります:
{
"account": "0x1234567890123456789012345678901234567890",
"balance": "100",
"required": "1000"
}500レスポンスのdescription書き方
500レスポンスの description には、その関数で発生する可能性のあるすべてのエラーを箇条書きで記載します。
これにより、関数を呼び出す際に想定すべきエラーパターンを一目で把握できます。
- 基本的な書き方
"500":
description: "この関数で発生しうるエラーの一覧です。\n\n・InsufficientBalance\n\n・InvalidAddress\n\n・AmountZero"- 複数のエラーがある場合の例
"500":
description: |
この関数で発生しうるエラーの一覧です。
・InsufficientBalance
・InvalidAddress
・AmountZero
・Unauthorized
・ContractPausedexamplesの書き方
各エラーの具体例は examples フィールドで定義します。
examples を使うことで、Swagger UIでエラーごとの詳細な情報を確認できるようになります。
- 基本的な書き方
examples:
InsufficientBalance:
summary: "残高不足"
value:
message: "InsufficientBalance"
data: {}
InvalidAddress:
summary: "無効なアドレス"
value:
message: "InvalidAddress"
data:
address: "0x0000000000000000000000000000000000000000"- フィールドの説明
| フィールド | 説明 | 注意点 |
|---|---|---|
キー(例: InsufficientBalance) |
エラー名。Swagger UIのドロップダウンに表示される | Solidityのエラー名と一致させる |
summary |
エラーの簡潔な日本語説明 | ユーザーフレンドリーな表現を使う |
value.message |
エラー名またはメッセージ文字列 | Solidityのエラー名をそのまま記載 |
value.data |
エラーの詳細情報 | カスタムエラーが引数を持つ場合のみ記載 |
- 引数を持たないエラーの例
examples:
Unauthorized:
summary: "権限がありません"
value:
message: "Unauthorized"
data: {}- 引数を持つエラーの例
examples:
InsufficientBalance:
summary: "残高不足"
value:
message: "InsufficientBalance"
data:
account: "0x1234567890123456789012345678901234567890"
balance: "500000000000000000"
required: "1000000000000000000"
InsufficientAllowance:
summary: "許可量不足"
value:
message: "InsufficientAllowance"
data:
spender: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
allowance: "100000000000000000"
required: "500000000000000000"- require文のエラーの例
Solidityの require() や revert() を使ったエラーの場合、message にはエラーメッセージ文字列が入ります。
examples:
RequireError:
summary: "require文によるエラー"
value:
message: "Amount must be greater than zero"
data: {}エラーに引数がある場合は、必ず data フィールドにその値を含めます。
これにより、エラーが発生した際の具体的な状況を把握しやすくなります。
イベントの表現
イベント(Event)は、スマートコントラクトのステート変化を外部に通知するための重要な仕組みです。 トランザクションのログに記録され、フロントエンドアプリケーションやインデックスサービスがこれを監視してリアルタイムにステート変化を追跡できます。
イベントは /events/{EventName} パスで表現し、HTTP GET メソッドを使用します。
イベントは読み取り専用の情報であり、発行されたイベントを照会する操作として扱うため、GETメソッドが適切です。
基本的なイベントの例
/events/Transfer:
get:
summary: "Transfer"
description: |
トークンが転送された時に発行されるイベントです。
ERC20標準イベントです。このイベントは、`transfer` 関数や `transferFrom` 関数が実行されたときに発行されます。
トークンの移動を追跡するために使用されます。
**パラメータ:**
- `from` (address) - indexed
- `to` (address) - indexed
- `value` (uint256)
operationId: event_Transfer
tags:
- Events
responses:
"200":
description: "トークン転送イベント"
content:
application/json:
schema:
$ref: '#/components/schemas/TransferEvent'イベントスキーマの定義
イベントのスキーマは components/schemas に定義します。
各パラメータの型、説明、サンプル値を明確に記載します。
components:
schemas:
TransferEvent:
type: object
description: "Transfer イベント。トークンが転送されたときに発行されます。"
properties:
from:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "indexed: true。送金元のアドレス。トピックとして検索可能です。"
example: "0x1234567890123456789012345678901234567890"
to:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "indexed: true。送金先のアドレス。トピックとして検索可能です。"
example: "0x0987654321098765432109876543210987654321"
value:
type: string
description: "indexed: false。転送されたトークン量(wei単位)。"
example: "1000000000000000000"複雑なイベントの例(複数のindexedパラメータ)
/events/Approval:
get:
summary: "Approval"
description: |
トークンの使用許可が設定された時に発行されるイベントです。
ERC20標準イベントです。このイベントは、`approve` 関数が実行されたときに発行されます。
`owner` が `spender` に対してトークンの使用を許可した量を記録します。
**パラメータ:**
- `owner` (address) - indexed
- `spender` (address) - indexed
- `value` (uint256)
operationId: event_Approval
tags:
- Events
responses:
"200":
description: "承認イベント"
content:
application/json:
schema:
$ref: '#/components/schemas/ApprovalEvent'- スキーマ定義
components:
schemas:
ApprovalEvent:
type: object
description: "Approval イベント。トークンの使用許可が設定されたときに発行されます。"
properties:
owner:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "indexed: true。トークンの所有者アドレス。トピックとして検索可能です。"
example: "0x1234567890123456789012345678901234567890"
spender:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "indexed: true。トークンの使用を許可されたアドレス。トピックとして検索可能です。"
example: "0x0987654321098765432109876543210987654321"
value:
type: string
description: "indexed: false。許可されたトークン量(wei単位)。"
example: "1000000000000000000"カスタムイベントの例
/events/RoleGranted:
get:
summary: "RoleGranted"
description: |
ロールが付与された時に発行されるイベントです。
AccessControl で使用されるイベントです。管理者が特定のアカウントに新しいロールを付与したときに発行されます。
このイベントを監視することで、権限の変更履歴を追跡できます。
**パラメータ:**
- `role` (bytes32) - indexed
- `account` (address) - indexed
- `sender` (address) - indexed
operationId: event_RoleGranted
tags:
- Events
responses:
"200":
description: "ロール付与イベント"
content:
application/json:
schema:
$ref: '#/components/schemas/RoleGrantedEvent'- スキーマ定義
components:
schemas:
RoleGrantedEvent:
type: object
description: "RoleGranted イベント。ロールが付与されたときに発行されます。"
properties:
role:
type: string
pattern: "^0x[0-9a-fA-F]{64}$"
description: "indexed: true。付与されたロールのID(bytes32形式)。"
example: "0x0000000000000000000000000000000000000000000000000000000000000000"
account:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "indexed: true。ロールを付与されたアカウントのアドレス。"
example: "0x1234567890123456789012345678901234567890"
sender:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "indexed: true。ロールを付与した管理者のアドレス。"
example: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"イベントスキーマのフィールドは以下です。
| フィールド | 説明 | 注意点 |
|---|---|---|
type |
スキーマの型。イベントは object を使用 |
常に object |
description |
イベントの説明。どのような状況で発行されるかを記述 | 発行条件、用途、関連する関数を明記 |
properties |
イベントの各パラメータ。indexed はdescriptionに明記 |
各パラメータに indexed: true/false を明記 |
indexedパラメータの重要性
Solidityの indexed パラメータは、イベントログのトピック(topics)として記録されます。
トピックとして記録されたパラメータは、効率的に検索・フィルタリングが可能です。
- indexed パラメータ
descriptionに「indexed: true」と明記し、「トピックとして検索可能です」と追記。 - 非indexed パラメータ
descriptionに「indexed: false」と明記。
例えば、特定のアドレス(from)から送信されたすべての Transfer イベントを検索したい場合、from が indexed であれば効率的に検索できます。
description: "indexed: true。送金元のアドレス。トピックとして検索可能です。"一方、indexed でないパラメータは、イベントのデータ部分に記録され、検索には使用できませんが、より多くの情報を含めることができます。
description: "indexed: false。転送されたトークン量(wei単位)。"エラーの表現
カスタムエラーは、Solidity 0.8.4以降で導入された効率的なエラーハンドリング機能です。
従来の revert() や require() よりもガス代が安く、型安全性が高いという特徴があります。
カスタムエラーは /errors/{ErrorName} パスで表現し、HTTP GET メソッドを使用します。
エラーの定義を参照する操作として扱うため、GETメソッドが適切です。
基本的なカスタムエラーの例(引数なし)
/errors/Unauthorized:
get:
summary: "Unauthorized"
description: |
権限がないアカウントが操作を実行しようとした時に返されるエラーです。
このエラーは、アクセス制御で保護された関数を、権限を持たないアカウントが呼び出した場合に発生します。
適切な権限(ロール)を付与してから、再度実行してください。
operationId: error_Unauthorized
tags:
- Errors
responses:
"200":
description: "権限エラー"
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: "Unauthorized"引数を持つカスタムエラーの例
カスタムエラーに引数がある場合、エラーが発生した際の具体的な状況を伝えることができます。
/errors/InsufficientBalance:
get:
summary: "InsufficientBalance"
description: |
残高が不足している時に返されるエラーです。
このエラーは、トークン転送や支払いの際に、実行者の残高が必要な量に満たない場合に発生します。
`balance` フィールドで現在の残高を、`required` フィールドで必要な残高を確認できます。
**エラー引数:**
- `account` (address) - 残高が不足しているアカウントのアドレス
- `balance` (uint256) - 現在の残高
- `required` (uint256) - 必要な残高
operationId: error_InsufficientBalance
tags:
- Errors
responses:
"200":
description: "残高不足エラー"
content:
application/json:
schema:
$ref: '#/components/schemas/InsufficientBalanceError'- エラースキーマの定義
components:
schemas:
InsufficientBalanceError:
type: object
description: "InsufficientBalance エラー。残高が不足している場合に返されます。"
properties:
account:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "残高が不足しているアカウントのアドレス。"
example: "0x1234567890123456789012345678901234567890"
balance:
type: string
description: "現在の残高(wei単位)。"
example: "500000000000000000"
required:
type: string
description: "必要な残高(wei単位)。"
example: "1000000000000000000"複雑なカスタムエラーの例
/errors/InvalidAddress:
get:
summary: "InvalidAddress"
description: |
無効なアドレスが指定された時に返されるエラーです。
このエラーは、ゼロアドレス(`0x0000000000000000000000000000000000000000`)が指定された場合や、
コントラクトのロジック上許可されないアドレスが指定された場合に発生します。
**エラー引数:**
- `addr` (address) - 無効と判定されたアドレス
operationId: error_InvalidAddress
tags:
- Errors
responses:
"200":
description: "無効なアドレスエラー"
content:
application/json:
schema:
$ref: '#/components/schemas/InvalidAddressError'- エラースキーマの定義
components:
schemas:
InvalidAddressError:
type: object
description: "InvalidAddress エラー。無効なアドレスが指定された場合に返されます。"
properties:
addr:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "無効と判定されたアドレス。"
example: "0x0000000000000000000000000000000000000000"エラー定義のフィールドは以下です。
| フィールド | 説明 | 注意点 |
|---|---|---|
summary |
エラー名をそのまま記載 | Solidityのエラー名と一致させる |
description |
エラーの詳細な説明。発生条件、対処方法を記述 | 引数がある場合は「エラー引数:」として列挙 |
operationId |
error_{ErrorName} の形式 |
他の操作と重複しないよう接頭辞を付ける |
tags |
Errors タグを使用 |
エラーは単一のタグで分類 |
responses["200"] |
エラースキーマへの参照 | 引数がある場合は $ref でスキーマを参照 |
カスタムエラーを使うことで、従来の文字列ベースのエラーメッセージよりも構造化された詳細な情報を提供でき、デバッグやエラーハンドリングが容易になります。
変数・定数の表現
Solidityの public なステート変数や定数は、コンパイラによって自動的にgetter関数が生成されます。
これらの自動生成されたgetterをOpenAPI/Swagger形式で表現する際には、HTTP GET メソッドを使用します。
重要なポイントとして、description には必ず変数宣言そのものをコードブロックで含めます。
これにより、型、可視性、初期値などの重要な情報を一目で確認できます。
基本的な変数の例
/totalSupply:
get:
summary: "totalSupply"
description: |
```solidity
uint256 public totalSupply;
```
トークンの総供給量を取得します。
ERC20標準のステート変数です。この値は、トークンの発行(mint)や焼却(burn)によって変動します。
現在発行されているトークンの総量を確認できます。
operationId: totalSupply
tags:
- Variables
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
description: "トークンの総供給量(wei単位)を返します。"
example: "1000000000000000000000000"定数(constant)の例
定数は、コンパイル時に値が確定し、デプロイ後は変更できません。
constant キーワードを使って定義します。
/DECIMALS:
get:
summary: "DECIMALS"
description: |
```solidity
uint8 public constant DECIMALS = 18;
```
トークンの小数点以下の桁数を表す定数です。
この値は、トークンの表示や計算において重要な役割を果たします。
例えば、`DECIMALS` が18の場合、1トークンは `1 * 10^18` wei として扱われます。
ERC20標準では、通常18が使用されます(Etherと同じ)。
この値はコンパイル時に確定し、変更できません。
operationId: DECIMALS
tags:
- Constants
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: integer
minimum: 0
maximum: 255
description: "小数点以下の桁数を返します。"
example: 18イミュータブル変数(immutable)の例
イミュータブル変数は、コンストラクタ内で一度だけ値を設定でき、その後は変更できません。 デプロイ時に値が確定します。
/owner:
get:
summary: "owner"
description: |
```solidity
address public immutable owner;
```
コントラクトのオーナーアドレスを取得します。
この値は、コントラクトのデプロイ時にコンストラクタで設定されます。
デプロイ後は変更できません。
オーナーは、コントラクトの管理機能(ミント、バーン、権限設定など)にアクセスできます。
operationId: owner
tags:
- Variables
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "コントラクトのオーナーアドレスを返します。"
example: "0x1234567890123456789012345678901234567890"bytes32型の定数の例
ロールベースのアクセス制御でよく使われる bytes32 型の定数の例です。
/ADMIN_ROLE:
get:
summary: "ADMIN_ROLE"
description: |
```solidity
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
```
管理者ロールを表す定数です。
AccessControl で使用されるロール識別子です。
このロールを持つアカウントは、コントラクトの管理機能にアクセスできます。
`hasRole(ADMIN_ROLE, account)` で、特定のアカウントがこのロールを持っているかを確認できます。
operationId: ADMIN_ROLE
tags:
- Constants
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
pattern: "^0x[0-9a-fA-F]{64}$"
description: "ロールIDを表すbytes32値を返します。"
example: "0xdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42"変数・定数の表現において重要なポイントは以下です。
| ポイント | 説明 | 例 |
|---|---|---|
| 変数宣言の記載 | description の最初にSolidityの変数宣言をコードブロックで記載 |
solidity uint256 public totalSupply; |
| 型の明確化 | 変数宣言により、型、可視性、修飾子が一目で分かる | uint256 public, uint8 public constant, address public immutable |
| 変更可能性の説明 | constant や immutable の場合、変更できないことを明記 |
「この値はコンパイル時に確定し、変更できません」 |
| 使用目的の説明 | 変数が何のために使われるか、どのように使われるかを説明 | 「トークンの発行や焼却によって変動します」 |
変数宣言を含めることで、Swagger UIで仕様書を見る人が、実際のSolidityコードの構造を理解しやすくなります。
Mappingの表現
Mappingは、Solidityでキーと値の対応関係を管理するデータ構造です。
public な Mapping は、コンパイラによって自動的にgetter関数が生成されます。
Mappingも変数と同様に、description には型定義をコードブロックで含めます。
特に、ネストしたMapping(二重Mapping)の場合は、型定義を明記することで構造が理解しやすくなります。
単一Mappingの例
/balanceOf:
get:
summary: "balanceOf"
description: |
```solidity
mapping(address account => uint256) public balanceOf;
```
各アカウントのトークン残高を管理するMappingです。
ERC20標準のMappingです。アカウントアドレスをキーとして、そのアカウントが保有するトークン量を取得できます。
トークンの転送や発行、焼却によって残高が変動します。
operationId: balanceOf
tags:
- Mapping
parameters:
- name: account
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "残高を照会するアカウントのアドレスを指定します。"
example: "0x1234567890123456789012345678901234567890"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
description: "指定されたアカウントのトークン残高(wei単位)を返します。"
example: "1000000000000000000"ネストしたMapping(二重Mapping)の例
ERC20の allowance のような二重Mappingの例です。
/allowance:
get:
summary: "allowance"
description: |
```solidity
mapping(address owner => mapping(address spender => uint256)) public allowance;
```
`spender` が `owner` から使用を許可されているトークン量を管理するMappingです。
ERC20標準のMappingです。このMappingは、トークンの所有者(`owner`)が、
別のアカウント(`spender`)に対して使用を許可したトークン量を記録します。
`approve` 関数で許可量を設定し、`transferFrom` 関数で実際に使用されます。
`transferFrom` が実行されると、この許可量が減少します。
operationId: allowance
tags:
- Mapping
parameters:
- name: owner
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "トークンの所有者アドレスを指定します。"
example: "0x1234567890123456789012345678901234567890"
- name: spender
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "トークンの使用を許可されたアドレスを指定します。"
example: "0x0987654321098765432109876543210987654321"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: string
description: "`spender` が使用できる残りのトークン量(wei単位)を返します。"
example: "500000000000000000"アクセス制御に使われるMappingの例
/hasRole:
get:
summary: "hasRole"
description: |
```solidity
mapping(bytes32 role => mapping(address account => bool)) public hasRole;
```
特定のアカウントが特定のロールを持っているかを確認するMappingです。
AccessControl で使用されるMappingです。ロールID(`role`)とアカウントアドレス(`account`)の
組み合わせに対して、そのアカウントがそのロールを持っているかどうかをブール値で管理します。
`grantRole` 関数でロールが付与され、`revokeRole` 関数で剥奪されます。
operationId: hasRole
tags:
- Mapping
parameters:
- name: role
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{64}$"
description: "確認するロールのID(bytes32形式)を指定します。"
example: "0xdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42"
- name: account
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "確認するアカウントのアドレスを指定します。"
example: "0x1234567890123456789012345678901234567890"
responses:
"200":
description: "正常終了時のレスポンスです。"
content:
application/json:
schema:
type: object
properties:
result:
type: boolean
description: "アカウントがロールを持っている場合 `true`、持っていない場合 `false` を返します。"
example: trueMappingの表現において重要なポイントは以下です。
| ポイント | 説明 | 例 |
|---|---|---|
| 型定義の記載 | Mappingの完全な型定義をコードブロックで記載 | mapping(address => uint256) public balanceOf |
| ネスト構造の明示 | 二重Mappingの場合、キーの階層構造を明確に説明 | 「owner → spender → amount」 |
| parametersの順序 | Mappingのキーの順序に従ってparametersを定義 | 外側のキー(owner)を先に、内側のキー(spender)を後に |
| 使用場面の説明 | どの関数でこのMappingが使われるかを明記 | 「approve で設定、transferFrom で使用」 |
構造体の表現
構造体(struct)は、複数のデータをまとめて管理するための複合型です。 関連するデータをグループ化することで、コードの可読性と保守性を向上させます。
構造体は /structs/{StructName} パスで表現し、HTTP GET メソッドを使用します。
基本的な構造体の例
/structs/TokenInfo:
get:
summary: "TokenInfo"
description: |
トークンの基本情報を保持する構造体です。
この構造体は、トークンのメタデータ(名前、シンボル、decimals)を一つのデータ構造にまとめています。
コントラクトの初期化時や設定変更時に使用されます。
**フィールド:**
- `name` (string) - トークンの名前
- `symbol` (string) - トークンのシンボル
- `decimals` (uint8) - トークンの小数点以下の桁数
operationId: struct_TokenInfo
tags:
- Structs
responses:
"200":
description: "TokenInfo構造体"
content:
application/json:
schema:
$ref: '#/components/schemas/TokenInfoStruct'構造体のスキーマは components/schemas に定義します。
components:
schemas:
TokenInfoStruct:
type: object
description: "TokenInfo 構造体。トークンの基本情報を保持します。"
properties:
name:
type: string
description: "トークンの名前。例: 'MyToken'。"
example: "Example Token"
symbol:
type: string
description: "トークンのシンボル。例: 'MTK'。通常は3-5文字の大文字。"
example: "EXT"
decimals:
type: integer
minimum: 0
maximum: 255
description: "トークンの小数点以下の桁数。通常は18。"
example: 18複雑な構造体の例
/structs/VestingSchedule:
get:
summary: "VestingSchedule"
description: |
トークンのベスティング(段階的権利確定)スケジュールを管理する構造体です。
この構造体は、トークンの配布スケジュールを定義します。
ベスティング期間中、受益者は時間の経過とともに徐々にトークンを受け取る権利を獲得します。
**フィールド:**
- `beneficiary` (address) - 受益者のアドレス
- `start` (uint256) - ベスティング開始時刻(UNIXタイムスタンプ)
- `cliff` (uint256) - クリフ期間(秒)。この期間中はトークンを受け取れない
- `duration` (uint256) - ベスティング期間(秒)
- `totalAmount` (uint256) - ベスティング対象のトークン総量
- `releasedAmount` (uint256) - すでに引き出されたトークン量
operationId: struct_VestingSchedule
tags:
- Structs
responses:
"200":
description: "VestingSchedule構造体"
content:
application/json:
schema:
$ref: '#/components/schemas/VestingScheduleStruct'- スキーマ定義
components:
schemas:
VestingScheduleStruct:
type: object
description: "VestingSchedule 構造体。トークンのベスティングスケジュールを定義します。"
properties:
beneficiary:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "受益者のアドレス。このアドレスがベスティングされたトークンを受け取ります。"
example: "0x1234567890123456789012345678901234567890"
start:
type: string
description: "ベスティング開始時刻(UNIXタイムスタンプ、秒単位)。"
example: "1704067200"
cliff:
type: string
description: "クリフ期間(秒)。開始からこの期間中はトークンを引き出せません。"
example: "2592000"
duration:
type: string
description: "ベスティング期間(秒)。この期間をかけてトークンが徐々に権利確定します。"
example: "31536000"
totalAmount:
type: string
description: "ベスティング対象のトークン総量(wei単位)。"
example: "1000000000000000000000"
releasedAmount:
type: string
description: "すでに引き出されたトークン量(wei単位)。"
example: "500000000000000000000"ネストした構造体の例
/structs/Proposal:
get:
summary: "Proposal"
description: |
ガバナンス提案を管理する構造体です。
この構造体は、DAOの投票提案に関する情報を保持します。
提案の内容、投票状況、実行ステートなどを一元管理します。
**フィールド:**
- `id` (uint256) - 提案のID
- `proposer` (address) - 提案者のアドレス
- `targets` (address[]) - 実行対象のコントラクトアドレスのリスト
- `values` (uint256[]) - 各呼び出しで送信するEther量のリスト
- `signatures` (string[]) - 各呼び出しの関数シグネチャのリスト
- `calldatas` (bytes[]) - 各呼び出しのコールデータのリスト
- `startBlock` (uint256) - 投票開始ブロック番号
- `endBlock` (uint256) - 投票終了ブロック番号
- `forVotes` (uint256) - 賛成票の総数
- `againstVotes` (uint256) - 反対票の総数
- `abstainVotes` (uint256) - 棄権票の総数
- `executed` (bool) - 提案が実行済みかどうか
- `canceled` (bool) - 提案がキャンセル済みかどうか
operationId: struct_Proposal
tags:
- Structs
responses:
"200":
description: "Proposal構造体"
content:
application/json:
schema:
$ref: '#/components/schemas/ProposalStruct'構造体スキーマのフィールドは以下です。
| フィールド | 説明 | 注意点 |
|---|---|---|
type |
スキーマの型。構造体は object を使用 |
常に object |
description |
構造体の用途や役割の説明 | どのような場面で使われるかを明記 |
properties |
構造体の各フィールド。Solidityの変数名をキー名として使用 | フィールドごとに詳細な説明を記載 |
構造体を使うことで、関連するデータをまとめて扱えるため、関数の引数や戻り値をシンプルに保つことができます。
Modifierの表現
Modifier(修飾子)は、関数の実行前後に特定の条件をチェックしたり、処理を追加したりする仕組みです。 アクセス制御、ステートチェック、再入攻撃対策などに広く使われます。
Modifierは /modifiers/{ModifierName} パスで定義し、HTTP GET メソッドを使用します。
基本的なModifierの例
/modifiers/onlyOwner:
get:
summary: "onlyOwner"
description: |
```solidity
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
```
このmodifierは、関数の実行者がコントラクトのオーナーであることを確認します。
関数の実行前に `msg.sender` がオーナーアドレスと一致するかをチェックします。
オーナー以外が実行した場合は、「Not owner」というメッセージとともにrevertします。
**使用例:**
- `mint` 関数: トークンの発行
- `burn` 関数: トークンの焼却
- `transferOwnership` 関数: オーナー権限の移譲
operationId: modifier_onlyOwner
tags:
- Modifier
responses:
"200":
description: "onlyOwner modifier"
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: "onlyOwner"ロールベースのModifierの例
/modifiers/onlyRole:
get:
summary: "onlyRole"
description: |
```solidity
modifier onlyRole(bytes32 role) {
require(hasRole(role, msg.sender), "AccessControl: account is missing role");
_;
}
```
このmodifierは、関数の実行者が指定されたロールを持っているかを確認します。
AccessControl で使用されるmodifierです。関数の実行前に、呼び出し元のアカウントが
指定されたロール(`role`)を持っているかをチェックします。
ロールを持っていない場合は、エラーメッセージとともにrevertします。
**引数:**
- `role` (bytes32) - 必要なロールのID
**使用例:**
- `grantRole` 関数: ロールの付与(`ADMIN_ROLE` が必要)
- `revokeRole` 関数: ロールの剥奪(`ADMIN_ROLE` が必要)
operationId: modifier_onlyRole
tags:
- Modifier
responses:
"200":
description: "onlyRole modifier"
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: "onlyRole"ステートチェックのModifierの例
/modifiers/whenNotPaused:
get:
summary: "whenNotPaused"
description: |
```solidity
modifier whenNotPaused() {
require(!paused, "Pausable: paused");
_;
}
```
このmodifierは、コントラクトが一時停止ステートでないことを確認します。
Pausable パターンで使用されるmodifierです。関数の実行前に、コントラクトの `paused` フラグを
チェックします。コントラクトが一時停止中(`paused == true`)の場合は、関数の実行を拒否します。
**使用例:**
- `transfer` 関数: 一時停止中は転送を禁止
- `mint` 関数: 一時停止中は発行を禁止
- `burn` 関数: 一時停止中は焼却を禁止
**関連するModifier:**
- `whenPaused`: 一時停止中のみ実行可能(一時停止解除のため)
operationId: modifier_whenNotPaused
tags:
- Modifier
responses:
"200":
description: "whenNotPaused modifier"
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: "whenNotPaused"再入攻撃対策のModifierの例
/modifiers/nonReentrant:
get:
summary: "nonReentrant"
description: |
```solidity
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
```
このmodifierは、再入攻撃を防ぐためのガードです。
ReentrancyGuard パターンで使用されるmodifierです。関数の実行中に、同じ関数が再度呼び出されることを防ぎます。
外部コントラクトを呼び出す関数や、Etherを送信する関数に適用することで、再入攻撃のリスクを軽減できます。
**仕組み:**
1. 関数の実行前に、`_status` が `_NOT_ENTERED` であることを確認
2. `_status` を `_ENTERED` に設定
3. 関数本体を実行
4. 関数の実行後、`_status` を `_NOT_ENTERED` に戻す
**使用例:**
- `withdraw` 関数: Etherの引き出し
- `claim` 関数: 報酬の受け取り
operationId: modifier_nonReentrant
tags:
- Modifier
responses:
"200":
description: "nonReentrant modifier"
content:
application/json:
schema:
type: object
properties:
name:
type: string
example: "nonReentrant"Modifierが付与された関数のdescription
関数にmodifierが付与されている場合、その効果を関数の description に追記します。
これにより、関数を呼び出す際に必要な権限や条件を明確にできます。
- 単一のModifierの場合
/mint:
post:
summary: "mint"
description: |
新しいトークンを発行します。
指定されたアドレス(`to`)に、指定された量(`amount`)のトークンを新規に発行します。
総供給量(`totalSupply`)が増加し、`Transfer` イベントが発行されます。
:::message
**Modifier**: この関数は `onlyOwner` modifierにより保護されています。
コントラクトのオーナーのみが実行可能です。
:::
operationId: mint
tags:
- Write Functions- 複数のModifierの場合
/withdraw:
post:
summary: "withdraw"
description: |
コントラクトからEtherを引き出します。
呼び出し元のアカウントが預けているEtherの全額を引き出します。
残高が不足している場合はエラーが発生します。
:::message
**Modifiers**:
- `whenNotPaused`: コントラクトが一時停止中でないことを確認
- `nonReentrant`: 再入攻撃を防止
:::
operationId: withdraw
tags:
- Write Functions複数のmodifierが付与されている場合は、すべてのmodifierの効果を箇条書きで記載します。 これにより、関数を安全に呼び出すために必要な条件を包括的に理解できます。
Solidityの型マッピング
Solidityの型をOpenAPI/Swagger形式に正確にマッピングすることは、仕様書の品質を左右する重要なポイントです。 以下では、よく使われるSolidity型とそのOpenAPI表現を詳しく説明します。
基本型のマッピング表
| Solidity型 | OpenAPI表現 | 理由・注意点 |
|---|---|---|
address |
type: string, pattern: "^0x[0-9a-fA-F]{40}$" |
40桁の16進数文字列。パターンでバリデーション |
uint256 / int256 |
type: string |
JavaScriptの安全な整数範囲(2^53-1)を超えるため文字列化 |
uint8 / uint16 / uint32 |
type: integer, minimum: 0, maximum: {max} |
安全な範囲内なので数値型で表現可能 |
int8 / int16 / int32 |
type: integer, minimum: {min}, maximum: {max} |
符号付き整数。範囲を明示 |
bytes32 |
type: string, pattern: "^0x[0-9a-fA-F]{64}$" |
64桁の16進数文字列(32バイト) |
bytes4 |
type: string, pattern: "^0x[0-9a-fA-F]{8}$" |
8桁の16進数文字列(4バイト、関数セレクタなど) |
bytes |
type: string |
可変長バイト列。16進数文字列として表現 |
bool |
type: boolean |
真偽値。そのまま表現 |
string |
type: string |
文字列。そのまま表現 |
address[] |
type: array, items: {type: string, pattern: ...} |
アドレスの配列 |
uint256[] |
type: array, items: {type: string} |
uint256の配列 |
各型の詳細な説明と例
address型
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "Ethereumアドレス(40桁の16進数文字列)"
example: "0x1234567890123456789012345678901234567890"- 常に
0xプレフィックスを含む - 40桁の16進数(20バイト)
- 大文字・小文字を区別しない(チェックサムアドレスには大文字小文字の区別あり)
uint256型
schema:
type: string
description: "符号なし256ビット整数(wei単位)。JavaScriptの安全な整数範囲を超えるため文字列として扱います。"
example: "1000000000000000000"- JavaScriptの
Number.MAX_SAFE_INTEGERは2^53-1(約9京) uint256は2^256-1(約10の77乗)まで扱える- 文字列化しないと精度が失われる
uint8型(小さい整数)
schema:
type: integer
minimum: 0
maximum: 255
description: "符号なし8ビット整数(0-255の範囲)"
example: 18- 使用例
decimals(小数点以下の桁数)。
bytes32型
schema:
type: string
pattern: "^0x[0-9a-fA-F]{64}$"
description: "32バイトの固定長バイト列(64桁の16進数文字列)"
example: "0xdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42"- 使用例
ロールID、ハッシュ値、一意識別子。
bool型
schema:
type: boolean
description: "真偽値"
example: trueー 使用例
フラグ、権限の有無。
string型
schema:
type: string
description: "文字列"
example: "Example Token"- 使用例
トークン名、シンボル、メッセージ。
配列型(address[])
schema:
type: array
items:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "アドレスの配列"
example:
- "0x1234567890123456789012345678901234567890"
- "0x0987654321098765432109876543210987654321"配列型(uint256[])
schema:
type: array
items:
type: string
description: "uint256の配列(各要素は文字列として表現)"
example:
- "1000000000000000000"
- "2000000000000000000"型マッピングの実例
- 複数の型を持つ関数の例
/complexFunction:
post:
summary: "complexFunction"
description: "複数の型を扱う関数の例です。"
parameters:
- name: account
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{40}$"
description: "アドレス型のパラメータ"
- name: amount
in: query
required: true
schema:
type: string
description: "uint256型のパラメータ(文字列として扱う)"
- name: decimals
in: query
required: true
schema:
type: integer
minimum: 0
maximum: 255
description: "uint8型のパラメータ(数値として扱える)"
- name: isActive
in: query
required: true
schema:
type: boolean
description: "bool型のパラメータ"
- name: roleId
in: query
required: true
schema:
type: string
pattern: "^0x[0-9a-fA-F]{64}$"
description: "bytes32型のパラメータ"このように、各型の特性を理解し、適切なOpenAPI表現を選択することで、正確で使いやすい仕様書を作成できます。
サンプル仕様書(ERC20)
以下は、ERC20トークンコントラクトの完全なOpenAPI仕様書サンプルです。
最後に
今回は「SolidityスマートコントラクトをOpenAPI/Swagger形式で仕様書化する方法」についてまとめてきました。


