JPYCv2の一時停止機能(ポーズ)の紹介
こんにちは。 元JPYC現CodeFoxのretocroomanです。私事ですが今月からWeb3関連事業を展開する株式会社CodeFoxのエンジニアになりました。別会社ではあるものの、JPYCと業務提携してJPYCのエコシステムの拡大を目指すことは変わらず、技術ブログも引き続き書かせていただくことになりました。
それでは、早速、JPYCv2のポーズ機能を紹介していこうと思います。ポーズ機能は、スマコンにバグがあったり、ハッキングされたりして緊急にスマコンの利用を停止させたいとき、もしくはスマコンのアップグレードを安全に行いたいときに活躍します!ちなみに、JPYCv2のブロックリスト機能の紹介の記事と内容が共通する部分が多く、そちらを読んだ前提となっているので、まずはそちらを読むことをお薦めします。
前提知識
Solidity(前提知識集)
JPYCv2のブロックリスト機能
Pausable.solの目的と概要
コントラクトに不具合が見つかったときやコントラクトをアップデートするときに全ての利用者のコントラクトの利用を一時停止することができます。緊急時にとりあえず被害を抑えるために停止するという役割もあるので、停止中でも一般の利用者が通常呼び出せない関数(オーナーを変えるなど)は使えます。
実装方法は、ブロックリスト機能と同じで、PausableコントラクトでPauserと一時停止、解除、修飾子を管理します。そして、必要なところでその修飾子を使っていくやり方です。ポーズ中かどうかもストレージに保存しておいてそのストレージを読み出して確認するやり方です。ただポーズ機能はブロックリスト機能と違い一般の利用者全員が対象になるため、マッピングは必要ありません。
Pausable.solのコード解説
JPYCv2の全体像
解説するコードのリンク
Pausable.sol(JPYCv2)
継承しているコントラクトのコードのリンク
Ownable.sol(JPYCv2)
Pausableが継承しているコントラクトの解説
contract Pausable is Ownable {
JPYCv2のOwnableコントラクトはOpenZeppelinのOwanbleとほぼ同じコードですが少しだけ変更しています。変更点はバージョンが0.8.11であること、オーナー権を放棄する関数を削っていること、OpenZeppelinのContextライブラリを継承していないことです。このOwnableコントラクトで定義されているowner
がブラックリスターの変更をすることができます。
Pausableコントラクトは最終的にはトークンの基本ロジックが書かれているFiatTokenV1コントラクトへ継承されています。FiatTokenV1コントラクトではapprove
やtransfer
の関数が用意されており、そこでPausableの修飾子が使われています。
Pausableの状態変数と修飾子の解説
event Pause(); // ポーズした時
event Unpause(); // ポーズ解除した時
event PauserChanged(address indexed newAddress); // Pauserが変更された時
address public pauser;
bool public paused; // ポーズ中かどうか
// ポーズ中ならエラーになる修飾子
modifier whenNotPaused() {
require(!paused, "Pausable: paused");
_;
}
// msg.senderがPauser以外ならエラーになる修飾子
modifier onlyPauser() {
require(msg.sender == pauser, "Pausable: caller is not the pauser");
_;
}
それではFiatTokenV1コントラクトでwhenNotPaused修飾子が使われている箇所を見てみましょう。
関数名 | 説明 | 行数 |
---|---|---|
mint | トークン発行 | 154 |
approve | トークン移動の許可 | 254 |
transferFrom | トークンの移動 | 294 |
transfer | 送信者によるトークンの移動 | 318 |
configureMinter | トークン発行の許可 | 359 |
burn | トークン焼却 | 393 |
increaseAllowance | 移動を許可したトークンの増量 | 424 |
decreaseAllowance | 移動を許可したトークンの減量 | 441 |
transferWithAuthorization | トークン移動のメタトランザクション | 505 |
receiveWithAuthorization | トークン移動のメタトランザクション* | 543 |
permit | トークン移動の許可のメタトランザクション | 594 |
*トークンの移動先であるtoがメタトランザクションのリレイヤーであるmsg.senderと同じになるよう制限しているもの
どれも一般の利用者むけの関数ばかりになっています。
そしてコードの最後にはサイズ50のuint256型の配列が宣言されています。Blocklistableコントラクトにもありましたが、後から状態変数を追加できるようにするためです。
uint256[50] private __gap;
関数の解説
// Pauserのみが呼べてポーズする
function pause() external onlyPauser {
paused = true;
emit Pause();
}
// Pauserのみが呼べてポーズ解除する
function unpause() external onlyPauser {
paused = false;
emit Unpause();
}
// Ownerのみが呼べてPauserを変更する
function updatePauser(address _newPauser) external onlyOwner {
require(
_newPauser != address(0),
"Pausable: new pauser is the zero address"
);
pauser = _newPauser;
emit PauserChanged(pauser);
}
特に解説がいらないほど、簡単なロジックですね。最悪Pauserが乗っ取られてもPauserはOwner権限で変更できるので、Ownerの秘密鍵さえ守れなければ大丈夫です。Pauserはいざというときすぐに使えないと意味がないので、そこは厳重にしすぎてもという感じです。
まとめ
JPYCv2のポーズ機能をみてきました。コードはブロックリスト機能より、さらに簡単でしたので特に詰まるところはなかったのではと思います。ポーズ機能はいざという時に便利な機能です。ただ、それを乱用してしまえば、ポーズ中は利用者はコントラクトを利用できないわけですから、信用問題に発展します。あらかじめ運用ルール等を決めておくことをお薦めします。
またUSDCにもポーズ機能はありますがあまり知られてないのではないでしょうか。いざポーズした時にどうやって全ての利用者にポーズ状態であることを周知するかという問題もあると思います。運用方法を考えながらもコントラクトでサービスを展開する際はぜひ、ポーズ機能を入れてみてください!ご精読ありがとうございました!
日本初のブロックチェーン技術(ERC20)を活用した日本円ステーブルコインJPYCはこちらから購入できます!
JPYC社はブロックチェーンエンジニアを募集中です!こちらからご応募お願いします!(タイミングにより募集を行なっていない場合があります)
また、ラボ形式でブロックチェーンに関する講義をしているJPYC開発コミュニティにも是非ご参加ください!
Discussion