1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JPYSC(日本円ステーブルコイン)スマートコントラクト技術分析

1
Last updated at Posted at 2026-06-30

本記事は Etherscan で公開されているソースコードを元に技術的な分析を行ったものであり、公式監査結果や開発者へのヒアリング結果ではありません。また、本記事に記載する考察はソースコードから推測した内容を含み、公式見解を示すものではありません。

TL;DR

  • JPYSCはFiatToken系の管理型ステーブルコイン
  • Mint先ホワイトリストとSeize機能が特徴
  • 脅威モデルは外部攻撃より内部統制

1. 概要

コードから読み取れる事実

  • 中核コントラクトは StablecoinV1 で、ERC-20 に加えて以下の機能を統合している。
  • 一時停止: Pausable
  • ブラックリスト: Blacklistable
  • ミント先ホワイトリスト(minter 単位): Whitelistable
  • 差押え(強制移転): Seizable
  • 誤送金トークン回収: AssetRecovery
  • ガスレス承認: EIP2612 (permit)
  • ガスレス送金: ERC3009Upgradeable (transferWithAuthorization, receiveWithAuthorization)
  • UUPS アップグレード: UUPSUpgradeable
  • Initializable + Ownable2StepUpgradeable を採用したプロキシ前提の設計。
  • ストレージは ERC-7201 namespaced storage で管理され、機能モジュールごとに専用スロットを持つ。
  • initialize 内でロール初期化時の分離制約を実施している(例: minterAdmin と whitelistManager の分離、blacklister と seizer の分離、owner と upgradeAuthority の分離)。

筆者の考察

  • 「法令対応・運用統制」を重視したステーブルコイン実装で、単なる ERC-20 より管理機能が強い。
  • ERC-7201 namespaced storage の採用は、アップグレード時のストレージ衝突を避けるうえで妥当。
  • 役割分離(SoD: Segregation of Duties)をコードレベルで強制している点は、運用手順依存を減らす実装として評価できる。

2. 主要機能

コードから読み取れる事実

主要関数一覧

関数シグネチャ 役割 呼び出し可能な主体 状態変更内容 発火イベント
initialize(...) 初期化(メタデータ、各ロール、EIP-712 設定) 初期化時に 1 回のみ 各モジュールのロール・メタデータを設定 UpgradeAuthorityChanged ほか各モジュール初期化イベント
mint(address to, uint256 amount) 新規発行 onlyMinter かつ onlyWhitelisted(to) totalSupply 増加、balances[to] 増加、minter allowance 減算 Mint, Transfer(address(0), to, amount)
burn(uint256 amount) 償却 onlyMinter balances[msg.sender] 減少、totalSupply 減少 Burn, Transfer(msg.sender, address(0), amount)
transfer(address to, uint256 amount) 通常送金 トークン保有者 残高移転 Transfer
transferFrom(address from, address to, uint256 amount) 承認済み送金 allowance を持つ spender allowance 減少(無限許可除く)、残高移転 Transfer
approve(address spender, uint256 amount) 利用許可設定 トークン保有者 allowance 設定 Approval
increaseAllowance(address spender, uint256 addedValue) allowance 増加 トークン保有者 allowance 加算 Approval
decreaseAllowance(address spender, uint256 subtractedValue) allowance 減少 トークン保有者 allowance 減算 Approval
permit(address owner_, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) 署名によるガスレス承認 誰でも提出可(署名検証前提) nonce 増加、allowance 設定 Approval
transferWithAuthorization(...) 署名によるガスレス送金 誰でも提出可(署名検証前提) authorization 状態を使用済みに更新、残高移転 AuthorizationUsed, Transfer
receiveWithAuthorization(...) 受取人限定のガスレス送金 msg.sender == to authorization 状態を使用済みに更新、残高移転 AuthorizationUsed, Transfer
cancelAuthorization(...) 署名認可の取消 誰でも提出可(署名検証前提) authorization 状態を使用済みに更新(取消) AuthorizationCanceled
configureMinter(address minter, uint256 allowance_) minter 登録/再設定 onlyMinterAdmin minter フラグ・allowance 設定 MinterConfigured
removeMinter(address minter) minter 削除 onlyMinterAdmin minter フラグ解除、allowance ゼロ化 MinterRemoved
whitelistMintDestination(address minter, address account) minter ごとのミント先追加 onlyWhitelistManager whitelist 更新 MintDestinationWhitelisted
unwhitelistMintDestination(address minter, address account) minter ごとのミント先削除 onlyWhitelistManager whitelist 更新 MintDestinationUnwhitelisted
blacklist(address account) / unBlacklist(address account) ブラックリスト制御 onlyBlacklister blacklist 状態更新 Blacklisted / UnBlacklisted
pause() / unpause() 停止/再開 onlyPauser pause 状態更新 OZ Paused / Unpaused
seize(address from, address to, uint256 amount, bytes32 trackId) 差押えによる強制移転 onlySeizer 残高移転(総供給不変) Seized, Transfer
recoverERC20(address tokenContract, address to, uint256 amount) 誤送金 ERC20 回収 onlyAssetRecoverer 外部 ERC20 へsafeTransfer呼び出し AssetRecovered
updatePauser(...) / updateBlacklister(...) / updateSeizer(...) / updateAssetRecoverer(...) / updateWhitelistManager(...) / updateMinterAdmin(...) 運用ロール更新 各現行ロールまたはowner(デュアルアクセス) ロールアドレス更新 *Changed
updateUpgradeAuthority(address newUpgradeAuthority) アップグレード権限更新 onlyUpgradeAuthority upgradeAuthority 更新 UpgradeAuthorityChanged
upgradeToAndCall(...)(UUPS 経由) 実装アップグレード _authorizeUpgrade により onlyUpgradeAuthority 実装アドレス更新 UUPS 標準イベント

主要イベント一覧

イベント 意味
Transfer トークン移転(mint/burn 含む)
Approval allowance 設定
Mint / Burn 発行・償却
MinterConfigured / MinterRemoved / MinterAdminChanged minter 関連の管理変更
MintDestinationWhitelisted / MintDestinationUnwhitelisted / WhitelistManagerChanged ミント先ホワイトリスト管理
Blacklisted / UnBlacklisted / BlacklisterChanged ブラックリスト管理
PauserChanged pauser 更新
Seized / SeizerChanged 差押え実行・seizer 更新
AssetRecovered / AssetRecovererChanged 誤送金回収関連
AuthorizationUsed / AuthorizationCanceled ERC-3009 認可の利用・取消
UpgradeAuthorityChanged アップグレード権限更新

筆者の考察

  • mint を「minter 権限 + 宛先ホワイトリスト + ブラックリスト + pause」で多層防御している点は、発行統制として強い。
  • configureMinter が allowance 再設定時に「現在 allowance が 0 であること」を要求する設計は、mempool 上の競合(再設定前の駆け込み mint)を意識した実装になっている。
  • receiveWithAuthorization を実装しているため、ERC-3009 の典型的な先回りリスクを受取人固定フローで回避できる。

3. 処理フロー

コードから読み取れる事実

Mint フロー

  1. minterAdminconfigureMinter で minter と allowance を設定。
  2. whitelistManagerwhitelistMintDestination(minter, to) を設定。
  3. minter が mint(to, amount) 実行。
  4. whenNotPausednotBlacklistedonlyWhitelisted(to)、allowance 超過チェックを通過した場合のみ発行。
  5. MintTransfer(address(0), to, amount) を発火。

Burn フロー

  1. minter が burn(amount) 実行。
  2. whenNotPausedonlyMinternotBlacklisted(msg.sender) を通過。
  3. 残高を減算し、totalSupply を減算。
  4. BurnTransfer(msg.sender, address(0), amount) を発火。

Transfer フロー

  • 標準送金: transfer / transferFrom
  • ガスレス送金: transferWithAuthorization / receiveWithAuthorization
  • いずれも残高移転は内部 _transfer に集約される。
  • 通常送金とtransferWithAuthorizationwhenNotPaused + blacklist チェックの対象。
  • receiveWithAuthorizationmsg.sender == to 制約を満たす必要がある。

管理者操作

  • Pause/Unpause、Blacklist/UnBlacklist、Seize、Minter 設定、Whitelist 設定、各ロール更新、UpgradeAuthority 更新が分離ロールで実行される。
  • ロール更新の多くは「現行ロールまたは Owner」が実行可能(デュアルアクセス)。
  • アップグレードは Owner ではなく upgradeAuthority が実行主体。

状態遷移

  • paused 状態: 多くのトークン操作を停止。
  • blacklist 状態: 対象アカウントを各操作から排除。
  • minter 状態: configureMinter / removeMinter で有効/無効。
  • authorization 状態(ERC-3009): nonce 単位で未使用 → 使用済み/取消済みに遷移。

権限の流れ

ミント時のシーケンス

筆者の考察

  • フロー全体は「発行前提条件を多段化」しており、単一権限の誤操作が直ちに大きな被害へ繋がりにくい。
  • 一方で、運用者はロール間の連携(minterAdmin と whitelistManager、blacklister と seizer、owner と upgradeAuthority)を手順化しないと実務で詰まりやすい。

4. セキュリティ診断

コードから読み取れる事実

観点別評価

観点 事実ベース評価
アクセス制御 onlyMinter / onlyMinterAdmin / onlyWhitelistManager / onlyBlacklister / onlySeizer / onlyPauser / onlyAssetRecoverer / onlyUpgradeAuthority を実装。
Mint/Burn 権限 mintburnonlyMintermint は宛先ホワイトリストと allowance 制約あり。
Pause 機能 transfer / approve / transferFrom / allowance 増減 / permit / transferWithAuthorization / receiveWithAuthorization / mint / burnwhenNotPausedseizecancelAuthorization は pause 非依存。
ブラックリスト機能 主要操作に notBlacklisted を適用。seizefrom がブラックリスト済みであることを要求。
Upgrade 権限 UUPS の _authorizeUpgradeonlyUpgradeAuthority。owner と upgradeAuthority の同一化を防ぐチェックあり。
Reentrancy トークン本体の主要状態更新は外部呼び出しなし。recoverERC20 は外部 ERC20 呼び出しあり(safeTransfer)。
Front Running receiveWithAuthorization で受取人固定。configureMinter の allowance 再設定制約で競合を緩和。
DOS リスク bulk blacklist/unblacklist は配列長に応じてガス増。極端に大きい配列は実行困難化の可能性。
権限集中リスク 役割分離制約は存在。ただし個々のロール鍵が単独管理なら運用面の集中リスクは残る。
外部コントラクト依存 OpenZeppelin(upgradeable 含む)と EIP 署名検証(ECDSA)に依存。recoverERC20 は任意 ERC20 実装の挙動に影響を受ける。
その他 renounceOwnership を明示的に無効化し、オーナー喪失による機能停止を防止。

良い実装

  • 役割分離を初期化時・更新時の両方でチェックしている。
  • UUPS 権限を owner から分離している。
  • ERC-3009 のreceiveWithAuthorizationを実装し、提出者制約を設けている。
  • mint の 0 値ミントを禁止してスプリアスイベントを防いでいる。
  • removeMinter で allowance を 0 化し、再設定時に 0 残高条件を要求している。

気になる点

  • recoverERC20 は外部トークン呼び出しを行うため、対象トークンが悪意ある実装の場合の副作用に注意が必要。
  • seize は pause 状態でも実行可能であり、設計意図が強制執行優先である反面、運用ポリシー次第で誤解を招く可能性がある。
  • removeMinter 後も minter 向けホワイトリストエントリは残るため、再有効化時に古い宛先が復活する。

改善案

  • 運用レイヤで upgradeAuthority を Timelock + マルチシグに固定し、変更手順を監査ログ付きで標準化する。
  • recoverERC20 実行時に許可対象トークンのポリシー(allow-list)や追加イベントメタデータを運用で補強する。
  • minter 再有効化時にホワイトリスト再レビューを必須化し、必要ならコントラクト側に一括削除補助機能を追加する。

筆者の考察

  • 全体として「攻撃技術」より「内部統制の破綻」を主たる脅威モデルに置いた設計に見える。
  • よってセキュリティ品質は、コードの堅牢性に加えて、鍵管理・権限委任・緊急時手順の成熟度で大きく変わる。

5. 総合レビュー

コードから読み取れる事実

  • 保守性: 機能はモジュール分割され、責務が比較的明確。
  • 可読性: コメント・カスタムエラーが充実し、失敗理由の追跡がしやすい。
  • 拡張性: UUPS + namespaced storage で将来拡張を想定。
  • セキュリティ: 多層ガード(pause/blacklist/whitelist/role separation)を実装。

筆者の考察

  • 保守性: 良好。業務ロジックと共通機能の分離が効いている。
  • 可読性: 高め。エラー名とイベント名が運用文脈に沿っている。
  • 拡張性: 高いが、アップグレード運用の品質が前提。
  • セキュリティ: 設計は堅いが、実運用では「誰が鍵を持ち、どう承認するか」が最重要。

6. FiatToken 比較表(USDC/JPYC/JPYSC)

コードから読み取れる事実

  • JPYSC は本記事で解析した StablecoinV1 実装に基づき、FiatToken 系で見られる管理機能(Pause、Blacklist、Minter 管理、Asset Recovery、ガスレス署名系、Upgradeable)を備える。
  • さらに JPYSC には、minter 単位のミント先ホワイトリストと、ブラックリスト済み口座を前提にした差押え機能(Seize)が実装されている。
  • USDC / JPYC については本リポジトリ内に当該コントラクト実装がないため、以下比較の USDC/JPYC 列は一般公開されている情報・公開コードで広く知られた構成を要約した参考情報である。
観点 USDC(FiatToken 系) JPYC(FiatToken 系) JPYSC(本記事解析対象)
基本モデル 管理型 ERC-20(法令・運用対応を重視) 管理型 ERC-20(運用統制機能を持つ) 管理型 ERC-20(運用統制機能を持つ)
Pause あり あり あり(pause / unpause
Blacklist あり あり あり(blacklist / unBlacklist
Mint 管理 Minter と上位管理ロールで制御 Minter と管理ロールで制御 MinterAdmin + MinterAllowance
Mint 先制御 実装差分あり(版によって異なる) 実装差分あり(版によって異なる) minter ごとの宛先ホワイトリストを実装
Burn あり(ミンター系権限で実施) あり(ミンター系権限で実施) あり(onlyMinter
署名系 EIP-2612、ERC-3009 系を採用する版がある EIP-2612/3009 系を採用する版がある EIP-2612 + ERC-3009 を実装
Asset Recovery あり(誤送金回収) あり(誤送金回収) あり(recoverERC20
強制移転(Seize) 実装方針は版・運用方針に依存 実装方針は版・運用方針に依存 あり(seizefromはブラックリスト済み要件)
Upgrade Upgradeable(運用管理前提) Upgradeable(運用管理前提) UUPS + upgradeAuthority 分離
役割分離の強制 高い(管理型ステーブルコインの典型) 高い(管理型ステーブルコインの典型) 高い(owner/upgradeAuthority、blacklister/seizer 等を分離)

筆者の考察

  • JPYSC は FiatToken 系の設計思想を踏襲しつつ、国内運用を強く意識した統制機能を追加した実装に見える。
  • 特に「minter ごとの宛先ホワイトリスト」と「blacklist を前提にした seize」は、発行・強制執行の運用ルールをコードに落とし込む方向性が明確。
  • 比較時に重要なのは機能名の有無だけでなく、ロール分離の強制度合い、アップグレード権限のガバナンス、緊急時手順の設計である。

7. まとめ

コードから読み取れる事実

  • JPYSC コントラクトは、ERC-20 をベースに法令対応・統制機能を重ねた設計。
  • 発行・償却・送金・差押え・停止・ブラックリスト・アップグレードを明確なロールで分担。
  • 署名ベース機能(EIP-2612 / ERC-3009)と運用統制機能が同居している。

筆者の考察

  • 「実務で使うステーブルコイン」の観点で、かなり現実的な設計。
  • 今後の品質差は、スマートコントラクトそのものより、ガバナンス実装(timelock/multisig)と運用監査体制で決まると考える。

8. 参考資料

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?