DeFiにおけるスマートコントラクトリスク

Nervos日本コミュニティ
13 min readJan 8, 2020

--

Jason Pofahl(Unsplash)

金融はリスク管理の技術です。リスクは、資産とその運用の双方に存在します。資産には価格があり、価格は資産固有の価値と総合リスクを反映しています。資産を評価するには、そのリスクを検討する必要があります。運用におけるリスクは、ミスが発生しやすい人為的なものが主です。資産とその運用リスクの評価は、伝統的な資産に基づく伝統的な金融であると、近時注目を浴びている分散型金融(いわゆるDeFi)であるとを問わず、金融の中核となるものです。

「ダメージコントロール」こそカギ

暗号資産のリスクは、規制の変更などの外部リスクと、設計上の欠陥や実装のバグなどの内部リスクから構成されています。Ethereumでは、ネイティブアセットとしてのETH、非ネイティブアセットとしてのERCトークンがあり、後者は、ERC20規格のいずれか1つおよびERC721やERC777などのトークンを指します。非ネイティブアセットは、Ethereumクライアントのバグとスマートコントラクトのバグの両方の影響を受ける可能性があるため、ネイティブアセットのリスクの方が非ネイティブアセットのリスクよりも低いです。

ERCトークンとDeFiの場合、システムとしてのDeFiは、さまざまな場所のさまざまな開発者によって作成された無限のスマートコントラクトによって織り込まれた複雑なネットワークであるため、スマートコントラクトのバグが最も懸念されます。スマートコントラクトのバグによって引き起こされるリスクを「スマートコントラクトリスク」と呼びます。

多くの研究努力がスマートコントラクトの脆弱性に焦点を当てており、多くの対策が発見されています。興味のある方は、こちらのアンケートをご覧ください。もっとも、重要なスマートコントラクト又はプログラムのバグを排除することは不可能であることが一般的に知られています。私たちは通信エラーとランダム性に満ちた世界に生きており、各ステップで「歪み」を引き起こします。頭の中のアイデアを正確な仕様に変えることはできません。同様に、仕様を完璧な実装に変換することはできません。

残酷にもこれが現実であるとするならば、私たちは、暗号資産の実装における予防的・事後的な防御だけでなく、悪い出来事が起こった場合の損失を最小限に抑えるダメージコントロールの手法も考える必要があります。

スマートコントラクトがダメージコントロールのために採用できる仕様パターンはたくさんありますが、最も重要なものは、アプリケーションの状態の分散化だと考えます。アプリケーションの状態が中央集権化すると、スマートコントラクトのバグによって引き起こされるダメージが増幅されるからです。以下で詳細を説明させてください。

ERCトークンのリスク

ERCトークン規格はインターフェースが異なりますが、いくつかの共通の機能を共有しています。ERCトークンの基本的な仕様は、トークンコントラクトを使用してトークン台帳を管理し、ユーザーがトークンコントラクトと対話してトークンを発行、転送、または書き込むことです。トークン台帳のすべての記録はトークンコントラクトに保存され、コントラクト自体は単にイーサリアムのアカウントです。

たとえば、ERCトークン「CUP」があり、アリスが100CUP、ボブが50CUP保有しており、トークン台帳は、アドレス/アカウント0x1234にあるイーサリアムスマートコントラクトだとします。このトークンコントラクト0x1234は、「Aliceが100CUP保有していること」や「Bobが50CUP保有していること」といった記録を格納する内部データベースを保持しています。アリスが30CUPをボブに転送したい場合、彼女は「30CUPをボブに転送してください」という署名済みメッセージをコントラウト0x1234に送信し、コントラクト0x1234はメッセージが実際にアリスからのものであることを確認し、その内部データベースを変更し、 「アリスは70CUP」と「ボブは80CUP」と記録します。

ここでの問題は、すべてのロジックと状態が単一のコントラクト0x1234に保持されることです。アリスとボブは、レコードがコントラクト0x1234の管理下に置かれているため、自分の記録に直接アクセスできません。このトークンのすべてのユーザーがこのコントラクトと対話しトークンを管理する唯一の方法は、コントラクト0x1234にメッセージを送信することです。

言い換えれば、トークンコントラクトは中心点です。そして、システムの中心点は最も効果的な攻撃対象でもあります。中心点の問題は、全てのユーザーに影響します。すべてのトークン/記録は中心点に保持されるため、誰もがそれと対話する必要があるからです。たとえば、整数オーバーフローに起因する「 transferFlaw / allowAnyone 」脆弱性、または慎重さのない許可に起因する「 ItchySwap」脆弱性を使用すると、攻撃者は所有者がコントラクトと対話していないときにトークンを盗むことができます。「ownerAnyone」の脆弱性により、攻撃者はトークンコントラクトを制御して、全員のトークンをロックできます。これらのすべての例で、トークンコントラクトが破られると、誰もが問題に直面します。

ERCトークンは、個々のユーザーではなく、トークンコントラクトによって保持されます。これは、EthereumのETHなどのネイティブトークンとは大きく異なります。ETH残高の記録は、スマートコントラクトによって保存されるのではなく、ユーザーが直接管理します。すべてのETH所有者には、自分の口座と残高の記録があります。たとえば、アリスが100 ETHを持ち、ボブがイーサリアムブロックチェーンで50 ETHを持っている場合、アリスは自分のアカウントにレコード「balance = 100」を持ち、ボブは自分のアカウントにレコード「balance = 50」を持っています。アリスの残高は、彼女の署名が存在する場合にのみ減少できます。これは、ボブの残高でも同様です。ETH所有権の記録は、単一のアカウントに集中するのではなく、複数のアカウントに分散されます。それらの秘密鍵が安全である限り、誰もETHを盗むことはできません。

これとは対照的に、ERCトークンの攻撃インターフェースはより大きくなります。これは、攻撃者が常にトークンコントラクトを破壊しようとすることができるためであり、プロトコル自体を破壊するよりもはるかに簡単です。

さまざまな固有のリスクがERCトークンとETHという2つの異なるクラスのアセットを生み出しました。分散ネットワークで実行されるスマートコントラクトは、分散ネットワークと同じではありません。集権化の問題がERCトークンによりアプリケーションレイヤーに再び持ち込まれました。これにより、スマートコントラクトバグの潜在的なダメージが増幅されます。また、残念ながら、人間はミスを犯す生き物であるため、バグの問題がつきまといます。ネットワーク/コンセンサスレイヤーの分散化によっては、アプリケーションレイヤーの集権化問題を解決することはできません。

リスクの増幅を回避する方法

ERCトークンに生じる中央集権化問題のポイントは、ERCトークンの状態がEthereumプログラミングモデルの”First-class Citizen”ではない点にあります。状態の一部はコードへの添付ファイルですが、直接参照して比較することはできません。同じ検証ルール(たとえば、同じトークンの記録)を持つ状態を同じコントラクトに置くことは自然ですが、このコントラクトは集権化のポイントになります。これは、イーサリアムのプログラミングモデルの結果です。

CKBでは、状態が”First-class Citizen”であるため、状況は一変します。状態は、ユーザーが直接操作するオブジェクトであり、コードは状態への添付ファイルです。これらの状態が異なるユーザーによって直接保持されている場合でも、状態を同じ検証ルールで自然に比較・グループ化できます。

CKBの非ネイティブトークンを「ユーザー定義トークン(User Defined Token, UDT)」と呼びます。特定のUDTについて、アセットの定義(コード)とアセットの記録(状態)が分離され、異なるユーザー(アドレス)の記録も分離されます。アセットの定義では、トークンのロジックが記述されます。たとえば、「発行上限は100万枚です」や「ボブは新しいトークンを発行できます」といった形で、アセットの記録では、「アリスは100トークンを保有しています」といった形です。アセットの定義は、トークン開発者が作成したコントラクトであり、開発者が所有するセル(アセット定義セル)に保存されますが、記録はユーザーのセルに保持され、すべて同じ「タイプ」スクリプトを使用します。各ユーザーは、自分のセルを使用して自分のトークン記録を保存します。これらのトークン記録は、アセット定義セルで定義された同じ検証ルールを共有します。この構造では、レコードは分散化された方法で保存されます。

上の図が示すように、アリスのトークンはアリス自身のセルに保存され、デフォルトでSecp256k1である彼女自身のロックスクリプトによって保護されています。アセットの定義にバグがあっても、アリスの秘密鍵が必要なため、攻撃者はアリスのレコードを変更できません。トークンはアリスによって直接保持されるため、攻撃者がアリスのロックを回避する方法はありません。トークンの状態を分散化することで、アセット定義のバグによるダメージをコントロールできます。

すべての人に影響するバグの可能性は依然として存在します。たとえば、アセットの定義にバグがあり、だれでも予想よりも多くのトークンを発行できる可能性があります。UDTの利点は、まず、バグの大部分が排除されることです。第二に、資産定義セルは、トークン発行認証ロジックの一部となりうるロックによって保護されます。プロトコルによって提供される認証メカニズムに簡単に乗ることができます。この承認とビジネスロジックの分離は優れたエンジニアリング手法であり、CKBのデフォルトです。UDTはERCトークンよりも分散されているため、UDTのスマートコントラクトリスクはERCトークンよりも低いですが、ネイティブトークンよりは高いです。

UDTに興味がある方は、こちらの議論がも参照してみてください。

セキュアなNervos DAO

アプリケーション状態の分散化は、Defiアプリケーションの設計にも役立ちます。Nervos DAOは、CKBの最初のDeFiアプリケーションです。これは、ユーザーがCKBのスマートコントラクトと同じようにやり取りできるスマートコントラクトです。Nervos DAOの機能の1つとして、CKByteホルダーにDAOへのデポジットによる保有量の希釈への対策を提供することがあります。Nervos DAOにデポジットすることで、所有者はデポジット数量に比例した二次報酬を獲得します。これにより、デポジット者のCKB保有量がハードキャップされた一次発行(BTCの発行総数をイメージしてください)によってのみ影響を受けることが保証されます。

本記事の執筆時点では、DAOには10億を超えるCKBytesがデポジットされており、その数は増え続けているため、攻撃者にとっては非常に魅力的なコントラクトとなっています。

我々はこの点を懸念すべきでしょうか?

我々は懸念の必要性はさほど高くはないと考えます。

Nervos DAOでロックされたCKBytesは1つのスマートコントラクトにプールされず、別のユーザーによって保持されているからです。ユーザーがNervos DAOにデポジットする場合、セル(CKBytesのUTXO)を選択してデポジットトランザクションを作成し、Nervos DAOスクリプトを示すタイプスクリプトリファレンスを『0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e』に設定します。これらのセルのロックスクリプトは変更されません。Nervos DAOのタイプスクリプトは、ユーザーのロックスクリプトから切り離されているため、攻撃者はユーザーの許可なしにこれらのデポジットされたCKBytesを使用することはできません。

デポジットされたCKBytesを出金するには、対応するロックスクリプトのwitness(署名)を提供する必要があります。この検証は、スマートコントラクトではなくCKBネットワークによって保証されており、回避策はありません。Nervos DAOスクリプトは、資金を保持するためではなく、出金時に補償計算が正しいことを確認するためにあります。

DeFiへの影響

スマートコントラクトリスクがDeFiに与える影響を定量的に分析することは困難ですが、Nexus Mutualが提供する保険商品「decentralized alternative to insurance(分散型保険代替品)」であるからいくつかの手がかりを得ることができます。

その最初の製品であるSmartContractCoverを使用すると、ユーザーはスマートコントラクトにより保険を購入できるため、スマートコントラクトがハッキングされた場合に補償を受けることができます。SmartContractCoverのプレミアムは市場によって決定され、対応する期間と量に正の相関があります。この投稿によると、Nuoでの90日間の1000 DAIの保険の補償には6.41 DAIがかかり、365日間のUniswapの1 ETHの保険の補償には0.013 ETHの費用がかかります。これらの数値に基づいて、スマートコントラクトの年間リスクコストは約2%であると推定できます。

2%のコストは、スマートコントラクトリスクによって引き起こされる市場の非効率性です。そのため、スマートコントラクトプログラミングモデルの改善が重要です。異なるプログラミングモデルは、スマートコントラクトリスクを軽減し、より効率的なDeFi市場をもたらします。

この投稿の草案に関するフィードバックを頂いいたHaseeb QureshiCipher WangMatt Quinn、およびChristopher Heymannに感謝します。

--

--