「スマートコントラクトの仕組みと法律」の感想とメモ

スマートコントラクトの仕組みと法律」は2023年の発売日に購入したのですが、なんだかんだ読んでいなかったので読んでみました。技術部分は気になる論点をChatGPTにまとめてもらってメモとして残しています。

目次

第1章

ウォレットなど

ウォレットやニーモニック、秘密鍵、アドレスの理解って結構最初は難しいですよね。昔Accentureの戦略から採った人がLedgerを見つめながら「この中に10億トークンも入っているんですね!」って言っているのを横で冷たい目で見ていたことを思い出しました。

僕も当初は秘密鍵が生成されるプロセスを知らず、ニーモニックと秘密鍵が並列だと勘違いしていて、僕が持っている一番txを刻んでいるアドレスは秘密鍵しか持っていなかったりします。そしてそのままエアドロ獲得活動もあったりしてなかなか切り替えられておらず。よくないですね。また、アドレス=公開鍵だという誤った理解をしていたなあと思い出しました。

コード監査

スマートコントラクトの監査会社について、CertiKとSlowmistはよく使うので知っているのですが、他はあまり知らなかったのでこの機会にちょっと調べてみました。スマートコントラクト監査と言えばCMC(CoinMarketCap)の監査バッジがなじみ深いので、上位プロジェクトが利用している監査会社をいくつかリストアップしてみました。

CertiK(サーティック)
2018年設立、米国拠点(創業者はイェール大学やコロンビア大学の研究者)。形式手法(formal verification)を売りにした監査を行う。世界的に最も知名度が高い監査企業のひとつで、取引所や投資家からの信頼が厚い。

Fairyproof(フェアリープルーフ)
中国を拠点とするスマートコントラクト監査企業。DeFiやNFTプロジェクトの監査実績が多く、セキュリティコンサルティングやリスク評価レポートも提供している。特にアジア圏のプロジェクトに採用例が多い。

Quantstamp(クオントスタンプ)
サンフランシスコ拠点の老舗セキュリティ企業。Ethereum系プロジェクトの初期から活躍し、ICO時代から利用されてきた。大規模プロジェクトや規制対応を重視するプロジェクトに選ばれることが多い。

Hacken(ハッケン)
ウクライナ発、東欧を中心に活動するセキュリティ企業。スマートコントラクト監査だけでなく、ペネトレーションテストやバグ報奨金(Bug Bounty)プラットフォームも運営。コスト感はCertiKよりやや安価で、中堅〜小規模プロジェクトも利用しやすい。

Chainsulting(チェインサルティング)
ドイツ拠点のブロックチェーンコンサルティング&セキュリティ企業。スマートコントラクト監査、DApp開発、コンサルティングを提供しており、特にヨーロッパ圏のプロジェクトで実績がある。

SlowMist(スローミスト)
中国拠点のセキュリティ企業。ハッキングインシデントの調査レポート「SlowMist Hacked」で知られ、監査だけでなく取引所やウォレット、DeFiプロトコルのセキュリティ監視に強みを持つ。

ちなみに、CMCの監査バッジは「CMCの提携監査会社のAPIにデータが載っているかどうか」でしかないので、監査バッジがないから監査をしていないわけではありません。ここで「なぜEthereumなど一流L1チェーンは監査バッジがついていないのか、大丈夫なのか?」という疑問が生じますが、それらは監査バッジの枠組みを必要とせず、外部監査(例:Trail of Bits、OpenZeppelin)、コミュニティによる継続的なコードレビュー、長年の運用実績、強固なコンセンサスメカニズム(PoW/PoS)により信頼が確立されているからです。逆に「なぜXRPは一流L1チェーンなのに監査バッジがついているのか?」という疑問も生じますが、これは特定のツールやエコシステムの部分監査であって全面的なコードレビューの結果を主張するものではありません。

逆に言えば、ブロックチェーン、エコシステム、投資家・Devコミュニティが未熟な後発のL1であればCertiKなどを巻き込んで監査してゆくのが合理的なのではないかと思います。

DAOではCode4rena(コードアリーナ)が有名で、Arena(闘技場)をもじって4renaとなっているとおり、バグバウンティのプラットフォームです。ARBITRUMやEigenLayerなど大手プロジェクトも利用しています。

第2章

「gasがかかる取引=send関数を実行する場合」って、シンプルな説明でいいなと思いました。

共通規格の関数については、「transferFrom」はトークン保有者以外の者が、当該トークンを移転させるときに利用される関数で、「approve」はトークン保有者が、トークン保有者以外の者にtransferFrom関数を実行させることを承認する関数であるという定義もちゃんと覚えておこうと思いました。

ステーブルコイン

日本では黎明期に、日本円建てステーブルコインであるJPYCが「前払式支払手段」として発行されました。しかし、USDTやUSDCといった成熟したステーブルコインは既存の枠組みに当てはまらなかったため、資金決済法の改正によって新たに「電子決済手段」というカテゴリーが設けられました。電子決済手段は、銀行・信託会社・資金移動業者が1:1の裏付け資産を保有して発行でき、発行はできないものの売買や媒介・取次・代理を行うことができる「電子決済手段取扱業者」も存在します。さらに、USDTやUSDCのように海外で発行されたものは「外国電子決済手段」と位置づけられ、日本で扱うには「外国電子決済手段取扱業者」としての登録が必要になります。以下に特徴をまとめます。

移転制限

電子決済手段は、発行者や取扱業者が管理するネットワーク内でのみ移転できるよう制限されています。これは、不特定多数に自由に譲渡できる状態になると、事実上「通貨」として流通して無秩序な信用創造を招き、金融政策や金融システムの安定を損なう恐れがあるためです。その実効性を担保するために、発行者や取扱業者は、不正利用者や制裁対象者への送金を禁止するblocklist機能、残高を動かせなくするfreeze機能、さらには不正取得された残高を消去するwipe機能など、複数の技術的手段を組み合わせて移転を制御することが求められます(日本の資金決済法では具体的な機能名までは規定していませんが、実務上はこれらが典型的な実装例とされています)。

滞留制限

利用者資金を長期間預かることは認められず、送金目的の一時的な利用に限定されます。これは、長期に資金を預かると預金と同じ機能を持ってしまい、銀行法による監督や預金保険制度の保護なしに銀行と同じ役割を果たしてしまう危険があるためであり、預金業務との明確な峻別を図る趣旨があります。

裏付け資産100%保全

発行残高に対して、必ず1:1で法定通貨などを分別管理することが義務づけられています。前払式支払手段のように半額供託では発行体の破綻時に資金が戻らない可能性があるため、全額を裏付け資産として確保し、利用者資金を確実に保護する仕組みとされています。

発行主体の限定

電子決済手段を発行できるのは、銀行・信託会社・資金移動業者に限られます。誰でも発行できる仕組みにすると、財務基盤の弱い事業者が破綻した際に利用者資金が失われるリスクが高まるため、信頼性と監督が確保された主体に限定しているのです。

NFT

NFTに権利を定めてハードフォークが起きた場合に、発行者は二重に義務を負うことになるのか?という論点は面白いと思いました。まあ実際はチェーンの正統性の勝敗がついてそちらだけ有効となるのだろうと思いますが。

ERC721もERC1155も用途としてはNFTですが、ERC1155はFTの束ってイメージですね。ユーザからすると、ノンファンジブルであることよりもtokenURIの紐づけができる(画像やパラメータが出る)ことがNFTとしての認識につながっている気がします。

approve

approveトークン保有者が、トークン保有者以外の者にtransferFrom関数を実行させることを承認する関数。引数の(address spender, unit256 amount)について、spenderとして指定されたアカウントはamountの量のトークンを移転し得る状態となる。
allowanceどのアカウントにどのくらいの量のトークンをapproveしたかという情報を表す関数。引数の(address owner, address spender)について、ownerとして指定されたアカウントがspenderとして指定されたアカウントに対してどのくらいの数量をapproveしたのかについての値を返す。spenderがtransferFrom関数を利用してownerアカウントからトークンを移転させた場合、当該数量分のallowance数量が減少する。
setApprovalForAll同じコントラクトのERC721・ERC1155について一括でapproveを行う関数。

defiを触っているとたまにとんでもない量のトークンのapproveを求められることがあるけれど、あれは2256−1=115792089237316195423570985008687907853269984665640564039457584007913129639935(77桁)の256ビット最大値を求められているということだったんですね。なお、1を引くのはゼロを含むためです。これの意味は、ERC-20のトークン最大発行量=「上限なしのapprove」を求められているということです。

setApprovalForAll関数といえば、以前深夜にうとうとしながら偽リンクを踏んで当該関数を実行し、当時高値だったNFTを一括で盗まれそうになって全速力でrevokeした記憶があります。恐怖の関数のイメージです。

revokeの意味

「〇〇プロジェクトがhackされたのでrevoke推奨です!」というようなpostがしばしばXのタイムラインに流れてきますが、どういう仕組みなのか知りませんでした。revokeとは、すでに一定数量のamountについてapproveされた状態であるとき、amountを0にしてapproveしなおすことなんですね。

カストディ業

暗号資産であるトークンのapproveを前提としたプラットフォームを提供する場合はカストディ業該当性を検討する必要があるというのはなるほどと思いました。日本で交換業ライセンスを保有していないWeb3事業者がライセンス取得から取り組むのは馬鹿げているので、日本のCEXに委託するか弁護士に相談しながらカストディ業に該当しないように設計するかが現実路線だと思います。

transfer

transfer自己の保有するトークンを自分で第三者に移転するときに利用する。Blocklistなど様々な追加機能を拡張可能。
transferFrom第三者が自己のトークンを移転させるときに利用する(事前にapproveが必要となる)。

残高管理と移転

ERC20トークンの残高管理は基本的にsolidityのmappingを活用して実装され、各アドレスごとにトークン残高を保持します。mappingとは、キー(key)と値(value)のペアを対応付けて保存する仕組みであり、solidityにおける連想配列のようなデータ構造です。たとえばmapping(address => uint256) public balanceOf;と定義すると、各アドレスをキーとして、そのアドレスが保有するトークン残高を値として記録できます。これはブロックチェーン上におけるキー・バリュー型ストア(Key–Value Store)の一種です。ブロックチェーンのストレージは「データベース」ではなく、キー(key)と値(value)の組み合わせで情報を保持する仕組みです。各アドレスをキーとし、保有しているトークンを値としてブロックチェーン上のストレージ(当該トークンのコントラクトに割り当てられたストレージ領域の中)に直接保存しているのです。トークンの発行(mint)時には、このmappingに初期残高がストックとして記録され、その後は各ブロックに記録されるトランザクションのフローによってmappingの値が更新されていきます。

なお、mapping に保存された値はすべてそのコントラクトのストレージに永続化され、ブロックが進んでも保持され続けます。ブロックには「この残高をどう変えたか」という履歴(トランザクション)が記録され、ノードはそれを順に実行することで、各アドレスの最新残高(state)を再現します。

スクロールできます
残高取得uint256 fromBalance = balances[from];mapping(balances)から送信者の残高を読み取る。
送信者の残高を減らすbalances[from] = fromBalance – amount;残高が不足していないことを確認後、残高を減算する。
受信者の残高を増やすbalances[to] += amount;受信者の残高を加算する。
イベント発行emit Transfer(from, to, amount);ブロックにログを記録(外部に通知)。

NFTのtokenURI

tokenURI

NFTにおける tokenURI とは、それぞれのトークン(=NFT)に紐づくメタデータ(属性情報)を参照するためのURLのことです。NFTはブロックチェーン上に「トークンID」と「所有者情報」を記録しますが、画像・動画・名前・説明文などの詳細データをすべてオンチェーンに保存するのは現実的ではありません。そのため、NFTの本体となるメタデータはオフチェーン(外部サーバーやIPFSなど)に保存され、スマートコントラクトはその場所を tokenURI として記録します。

function tokenURI(uint256 tokenId) public view virtual override returns (string memory)

この関数を呼び出すと、たとえば次のようなURI(JSONファイルへのURL)が返されます。

https://example.com/metadata/1.json

tokenURI の「URI」は、URLよりも広い概念を示しています。URL(Uniform Resource Locator)が「リソースの場所(どこにあるか)」を指すのに対し、URI(Uniform Resource Identifier)は「リソースの識別子(何であるか)」を意味します。NFTのメタデータは、必ずしも特定のウェブサーバー上に存在するとは限らず、IPFSやArweaveなどの分散ストレージ、あるいはオンチェーンデータとして直接ブロックチェーン上に保存されることもあります。そのため、NFTの仕様ではHTTPのURLに限定せず、さまざまな形式の識別子を扱えるように「URI」という表現が採用されています。つまり、tokenURI は「NFTのメタデータがどこにあるか」ではなく、「そのNFTのメタデータをどのように識別するか」を示すための関数なのです。

メタデータの内容

tokenURI が返すURI先には、一般的に以下のような構造のJSONファイルが置かれています。

{
  "name": "xxx Genesis #1",
  "description": "The first NFT of the xxx collection.",
  "image": "https://example.com/images/1.png",
  "attributes": [
    { "trait_type": "Background", "value": "Blue" },
    { "trait_type": "Rarity", "value": "Legendary" }
  ]
}

この JSONフォーマットはOpenSeaが事実上の標準仕様(デファクトスタンダード) となっており、多くのNFTマーケットプレイス(LooksRare, Rarible, Magic Edenなど)も同じ形式を採用しています。

OpenSeaはNFT市場の黎明期からメタデータの標準化を進めており、ERC721・ERC1155トークンを自動で読み取るための共通JSONスキーマ(name, description, image, attributesなど)を定義しました。そのため現在では、「OpenSea形式に従ってJSONを構成すれば、どのマーケットプレイスでも自動的にNFTが正しく表示される」という互換性が生まれています。

データの保管

NFTのメタデータや画像データの保存方法には、主にサーバ保管・分散ストレージ(IPFSやArweave)・フルオンチェーンの3つがあります。サーバ保管は運営者が管理する中央集権的な方式で、安価ではありますが、削除や改ざんのリスクがあります。IPFSやArweaveといった分散ストレージは、データをネットワーク上で共有し、改ざん耐性を持たせる仕組みです。ただし、IPFSはノードのピン留めが必要で、維持費を払い続けなければデータが失われる可能性があります。一方、Arweaveは保存時に一度だけ料金を支払い、その後はネットワーク全体で恒久的に保持されるよう設計されています。フルオンチェーンは最も安全かつ永続的な方法ですが、コストが高いため限定的に利用されます。つまり、NFTのデータ保存は「中央管理の安さ」と「分散保存の持続性」とのトレードオフの上に成り立っているのです。

Blocklist/ Allowlist機能

blocklist(ブロックリスト)やallowlist(アローリスト)は、スマートコントラクトやWebアプリケーションなどで特定のアドレスやユーザーの操作を制御するための機能です。blocklistは「禁止リスト」として機能し、指定されたアドレスを取引やアクセスの対象から除外します。一方、allowlistは「許可リスト」として、特定のアドレスだけに特定の操作(例:NFTの先行ミント、限定トークン配布など)を認める仕組みです。つまり、blocklistは不正や制裁対象をブロックする“防御的な機能”、allowlistは信頼済みユーザーだけを選別して許可する“選択的な機能”といえます。

これらの機能はERC20やERC721などのEthereum標準仕様には含まれていませんが、実務上は多くのプロジェクトが必要とするため、後に開発者コミュニティが拡張機能として実装しました。代表的な実装は、世界的に利用されているSolidityライブラリであるOpenZeppelinが提供しています。OpenZeppelinは、スマートコントラクトの安全なテンプレートを提供するオープンソース組織で、ERC20・ERC721の標準実装やアクセス制御(OwnableAccessControl)機能なども開発しています。blocklistやallowlistも、これらの基盤機能を拡張する形で利用されることが多く、内部的には mapping(address => bool) によって各アドレスの許可・拒否を truefalse の値で判定する、シンプルかつ効率的な仕組みで動作しています。

なお、かつては「ブラックリスト(blacklist)」と「ホワイトリスト(whitelist)」という表現が一般的でしたが、近年では人種差別的な連想を避けるため、より中立的な表現であるblocklist/allowlistという言葉が国際的に推奨されるようになりました。そのため、現在のブロックチェーン業界や開発者コミュニティでは、これらの呼称が主流となっています。

ポリシーの開示

一方で、これらの機能を運用する際には、どのような基準でアドレスをブロックまたは許可しているのかというポリシーを開示することが重要です。とくに、取引所やNFTプロジェクトなど多くのユーザーが関与するサービスでは、ブロックリストやアローリストの運用が恣意的でないことを示す必要があります。基準の開示や透明性の確保は、法的なリスクを軽減するだけでなく、ユーザーからの信頼を得る上でも不可欠です。

permit

ERC20トークンでは、第三者にトークンの使用を許可するために approve 関数が使われます。ユーザーはまず approve を実行して使用を許可し、その後に相手が transferFrom を呼び出すことで送金が行われます。この仕組みはシンプルですが、2回のトランザクションと2回分のガス代が必要になるという課題がありました。

この不便を解消するために導入されたのが permit(EIP-2612) です。permit はユーザーが署名したデータを利用してトークン使用を許可する仕組みで、オンチェーンでのapproveを不要にするガスレス認可機能です。ユーザーは署名だけを行い、実際のトランザクション送信は相手(spender)が行うため、ユーザー自身はガス代を支払いません。

スクロールできます
項目approvepermit
認可方法オンチェーンで許可オフチェーン署名で許可
ガス代負担ユーザーが支払うspenderが支払う(ユーザーは不要)
トランザクション数2回(approve+transferFrom)1回(permit+transferFrom)
採用例古いERC20トークンDAI、USDC、Uniswap、Aaveなど

一方、メタトランザクション(Meta Transaction) は、さらに一歩進んだ仕組みです。ユーザーが署名した取引データをリレーサー(代行者)がブロックチェーンに送信し、代わりにガス代を支払います。これにより、ユーザーはトランザクション実行を含めて完全にガスレスで利用できます。

permit は「トークン使用の承認部分をガスレス化」する機能であり、メタトランザクションは「取引実行そのものを代行者がガス代込みで送信する」仕組みです。両者を組み合わせることで、ユーザーは署名するだけで、承認から送金までを完全にガスレスで完結できるようになります。

ERC2612

ERC-2612 は、従来の approve に代わるガスレスな認可方法を定義したERC(Ethereum標準仕様)です。従来のERC20では、第三者にトークンの使用を許可するためにユーザーが approve を送信し、ガス代を支払う必要がありました。ERC-2612ではこの制約をなくし、ユーザーがオフチェーン署名で許可を与えられるように設計されています。

この仕組みでは、ユーザーが署名したデータを相手(spender)がブロックチェーンに送信し、permit() 関数を呼び出すことで approve と同じ状態を作ります。ユーザー自身はガスを支払わないため、ガスレスなトークン承認が可能になります。

function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v, bytes32 r, bytes32 s
) external;

この規格は2020年に正式に承認され、Aave、Uniswap、DAI、USDC など多くの主要プロジェクトが採用しています。

一方で、permit がカバーするのは「承認」の部分のみであり、メタトランザクションのように「トランザクション全体の実行」を代行するものではありません。メタトランザクションでは、ユーザーの署名を受け取ったリレーサー(代行者)が代わりにガス代を支払って取引全体を送信します。

スクロールできます
比較項目ERC-20 (approve)ERC-2612 (permit)メタトランザクション
認可方式オンチェーンオフチェーン署名オフチェーン署名
ガス代負担ユーザーspender(相手側)relayer(代行者)
対象範囲トークン使用の許可トークン使用の許可トランザクション全体
主な用途基本的な送金・承認DeFiやDEXの承認効率化Web3アプリのガスレス化

Upgradable機能

通常のスマートコントラクトは、一度デプロイするとそのコード(バイトコード)を変更できません。ブロックチェーンの「不変性」は信頼の源泉でもありますが、同時に「バグを修正できない」「機能を追加できない」という制約にもつながります。この問題を解決するために考案されたのが、Upgradable(アップグレード可能)コントラクトです。これは、データを保持するコントラクト(Proxy)と、処理ロジックを持つコントラクト(Implementation)を分離し、後からImplementationだけを差し替えられるようにした仕組みです。

コンサルティング契約受嘱先の会社がこの機能を使って重大な金額のtokenを盗まれたことがあり、うんざりするくらい悩まされました。Pros&Consをよく考えて使う必要があるかと思います。

仕組み:fallback + delegatecall

Proxyコントラクトは、基本的に自分自身にはアプリケーションロジックを持ちません。ユーザーからの呼び出しを受け取ると、Solidityのfallback関数が動作します。fallbackは「呼び出された関数がこのコントラクト内に存在しない場合」に自動的に実行される特別な関数で、Proxyではこの中でdelegatecallを使って別のコントラクト(Implementation)の関数を呼び出します。

fallback() external payable {
    _delegate(implementation);
}

delegatecallは、呼び出し元(Proxy)のストレージを共有したまま、呼び出し先(Implementation)のロジックだけを実行する命令です。そのため、データ(残高や所有者情報など)はProxy側に保持されたまま、新しいImplementationのロジックに置き換えることができます。

アップグレードできる理由

Proxyは内部に「現在参照しているImplementationのアドレス」を変数として持っています。この値を新しいコントラクトアドレスに書き換えることで、実行されるロジックを差し替えることができます。コードは変わらず、参照先(implementation address)を更新するだけで挙動が変わるという仕組みです。

function upgradeTo(address newImplementation) external onlyAdmin {
    implementation = newImplementation;
}

このように、「コードは不変だが、ストレージに保持された変数(state)は変更可能」というブロックチェーンの性質を利用することで、データを保持したままロジックだけをアップデートできるようになっています。

スマートコントラクトは一度デプロイすると、そのコード(バイトコード)自体はブロックチェーン上に固定され、変更することはできません。しかし、コントラクトが保持する変数(state)は更新可能です。たとえば、残高を管理する balances、オーナー権限を記録する owner、アップグレード可能コントラクトで参照する implementation アドレスなどは、ブロックチェーン上のストレージ領域に保存されており、これらの値はトランザクションを通じて書き換えることができます。つまり、スマートコントラクトはコードは不変だが、データ(状態)は可変という設計になっています。

標準仕様(ERC)としての位置づけ

このProxy+delegatecallによる構造は、EVMレベルの基本的な命令を使って実現されています。そのため、fallbackとdelegatecall自体はEthereumの標準機能です。一方で、アップグレード方式としては複数のERCが存在します。現在は以下の2つが広く採用されています。

スクロールできます
規格名称主な特徴採用例
EIP-1967Proxy Storage SlotsProxyとImplementationのアドレスを安全に管理する方式OpenZeppelin Transparent Proxy
EIP-1822UUPS (Universal Upgradeable Proxy Standard)Implementation自身がアップグレードロジックを持つ軽量方式OpenZeppelin UUPS Proxy

どちらの方式でも、根底にある動作原理は同じであり、fallbackが呼び出しを受け、delegatecallが別コントラクトのロジックを実行するという流れで成り立っています。

利点(Pros)と課題(Cons)

  • バグ修正や機能追加が可能
    デプロイ後に発見された不具合を修正したり、新機能を追加できる。
  • アドレスを変えずに更新可能
    Proxyのアドレスを維持できるため、ユーザーや取引所との接続を切らずに済む。
  • セキュリティ対応が容易
    新しい脆弱性に対して、Implementationを差し替えることで即時対応できる。
  • ストレージの永続性
    データはProxy側に残るため、ユーザー資産や設定情報を保持したままアップデートできる。
  • 管理者権限の集中リスク
    adminが悪用すれば任意のコードを挿し替え可能。マルチシグによる運用が推奨される。
  • 構造の複雑化
    ProxyとImplementationの2層構造により、監査やデバッグが難しくなる。
  • ストレージ破壊リスク
    Implementationを更新する際に変数定義の順序を誤ると、Proxyの既存データが上書きされる可能性がある。
  • ガスコストの増加
    delegatecallによる間接呼び出しのため、通常より若干ガスコストが高くなる。

実務

コントラクトを再デプロイするとコントラクトアドレスが変わり、ユーザー資産、トークン残高、既存のDApp接続などがすべてリセットされます。これは運用上・UX上の致命的な問題です。そのため、プロダクションレベルのDeFi・NFT・DAOなどの主要プロジェクトでは、Upgradable構造がほぼ標準になっています。

スクロールできます
プロジェクト名採用技術概要
AaveTransparent Proxy (EIP-1967)各種レンディングプールをProxy化し、ロジックを差し替え可能にしている。
Uniswap V3Proxy構造 + delegatecallコア部分をUpgradable化し、新しいAMMロジックへの切り替えに対応。
Compound FinanceTransparent Proxyガバナンスで投票によりImplementationを更新できる。
USDC / CircleTransparent ProxyステーブルコインのコントラクトもProxy構造。セキュリティ監査後に安全にアップグレード可能。
OpenSea(Seaport)Proxy Factory構造NFTマーケットプレイスで個別ロジックをデプロイせず、Proxy経由で一括管理。
ENS(Ethereum Name Service)UUPS Proxyレジストリ機能を保持しつつ、仕様変更に柔軟対応できる設計。

アップグレード可能なコントラクトは非常に便利な仕組みですが、同時に大きなリスクも抱えています。なぜなら、アップグレードの権限を持つ管理者(admin)が、もし意図的に悪意あるコードに差し替えた場合、ユーザー資産の引き出しや凍結といった操作を行うことが技術的に可能だからです。つまり、プロジェクトがユーザーを裏切れば、それだけでシステム全体が破綻します。こうした「開発者への過剰な信頼」に依存する構造を緩和するため、実務ではいくつかの対策が取られています。

  1. マルチシグ運用
    アップグレードを複数人の署名でのみ承認できるようにすることで、
    一人の管理者が独断で悪意ある変更を行うことを防ぎます。
  2. タイムロック(TimeLock)
    アップグレードの実行に一定の待機期間を設け、
    ユーザーや監査者が変更内容を確認できる時間を確保します。
  3. ガバナンスによる承認
    アップグレードをDAOやトークン保有者の投票で決定する仕組みにすることで、
    コントラクトの制御権をコミュニティに分散させます。
  4. 権限の放棄
    運用が安定した段階で、アップグレード権限を破棄(address(0)に設定)し、
    コントラクトを完全に固定化してしまう方法も取られます。

このように、アップグレード可能な設計は「信頼を再導入する構造」であるため、その信頼をどう分散・制御・透明化するかが極めて重要です。利便性と安全性のバランスを取るために、プロジェクトは権限設計を慎重に行う必要があります。

Upgradable機能の確認

Etherscan上でUpgradableかどうかを見分けるポイントは次の通りです。

  • Implementation / Proxy / Admin の項目が表示されている
  • ソースコードに delegatecall・fallback が含まれている
  • 「Proxy Contract for implementation: 0x…」という注記がある
  • Read Contract に implementation()admin() が存在する

これらのいずれかが確認できれば、そのコントラクトはアップグレード可能(Proxy構造)であると判断できます。反対に、Implementation欄がなく単一のロジックだけが書かれている場合は、固定型(Non-upgradable)のコントラクトです。

第3章

NFTと賭博

2021年ごろのNFT全盛期に、「日本ではリビール型NFTは賭博に該当するのではないか?」というような議論が起きていました。それに気づかなかったのか無視したのか、海外の売り方を真似て、「えいや」で売ってしまったいくつかのPJは、FTのPJに比べれば小粒なものの、個人サークルレベルにしては巨額の売上をあげることができました。一方で、当時すでに大手企業もNFTマーケットに参入していたものの、リーガル面で腰が引けていました。

ようやく2022 年10 月 にNFTに関連する複数の団体が「NFTのランダム型販売サービスに関するガイドライン」を策定し、いよいよ大手を振るって販売できるぞとなった頃には残念なことにNFTは下火になっていました。また、そもそも論なのですが日本の事業者は何故かみな人気IPを利用できればNFTが売れると錯覚しており、NFTがなんたるかを理解しておらず、全く魅力のないプロダクトを作っていたので、全滅と言えるレベルでNFT事業者は消えました。

なお、リビール型NFTが賭博に該当しないという整理は販売者と購入者の間で販売価格相当額のNFTと対価が支払われているだけで「得喪を争う」関係が認められないからという整理のようです。

ガバナンストークン

僕は現行のDeFiプロジェクトにおけるガバナンストークンには価値がないと思っています。本来はプロトコル収益の配当とガバナンスがセットで存在しているはずなのですが、政府からセキュリティトークン(証券)に認定されてしまうとWeb3事業として立ち振る舞うことができなくなる規制を受けるので、彼らは収益の分配は行っていません。トークンホルダーはいったい何のために意思決定に参加しているのかよくわからないまま走っているという状態なのです。しいて言えば将来法令が整備されてプロトコル収益が得られるようになることを見越して持つというのであれば将来CFが期待できると言えるのかもしれません。

なお、ガバナンス参加がエアドロ条件の一つになることがあるため、一般ユーザーは脳死でsnapshotに接続して何も読まないで得票数の多いほうや上に表示されたほうに投票するという作業を行っていたりします。これをガバナンスと呼ぶのかというと疑問でしかありません。

第4章

OpenSea

取引フロー

スクロールできます
フェーズ実行者行動種類ブロックチェーン上の動き内容
① NFTをSeaportに承認販売者approve() 実行トランザクションオンチェーンNFTコントラクトに対して、SeaportがNFTを転送できる許可を与える。ガス代が発生。
② 出品情報(Order)の作成販売者Orderデータを署名署名オフチェーン「どのNFTをいくらで売るか」を含むデータを自分の秘密鍵で署名。ガス代は不要。NFTもまだ動かない。
③ 出品データの掲載OpenSea署名済みOrderを登録オフチェーンデータベース or IPFSOpenSeaが署名データを受け取り、サイト上に出品として表示。
④ 購入者が購入実行購入者fulfillOrder() 実行トランザクションオンチェーン購入者がガス代を支払って注文を実行。SeaportコントラクトがNFTとETHを交換。
⑤ 取引完了Seaport内部処理自動オンチェーンNFTが販売者→購入者、ETHが購入者→販売者へ自動転送される。

LazyMint

OpenSeaの Shared Storefront Contract(0x495f…) を代表例とする Lazy Mint では、「NFTを出品時には発行せず、購入時に初めてオンチェーンでミント」される仕組みになっています。

  • クリエイターが署名データ生成(オフチェーン)
  • プラットフォームが署名データを保存(DB/IPFS)
  • 購入者が注文実行(オンチェーン)
  • スマートコントラクトがNFTをミント+購入者に送付

ちなみに、このような共有コントラクトでミントされたNFTは、メタデータやURIがプラットフォーム依存となるため、提供元の事業継続リスクに晒されやすく、資産的価値(経済価値)の面ではマイナスに評価されます。

NFTのロイヤリティ問題

NFTの二次流通ロイヤリティは、当初「クリエイターが継続的に収益を得られる仕組み」として注目されていました。しかし実際には、技術的な制約によりその理想は実現しませんでした。

まず、NFTの基本規格であるERC-721やERC-1155には、ロイヤリティ機能がそもそも実装されていません。そのため、OpenSeaなどのマーケットプレイスは独自ルールで分配処理を行っていましたが、これはあくまで“任意の運用”であり、スマートコントラクト上で強制することはできませんでした。

2021年には EIP-2981(NFT Royalty Standard)が提案され、NFTが返す関数によって「この作品には○%のロイヤリティを支払うべき」と通知できるようになりました。しかし、これはあくまで「支払うべき」と示すだけで、実際の支払いを強制する仕様ではありません。

そこで次に登場したのが EIP-2571(NFT Royalty Enforcement Standard)です。この提案は、NFTの転送や販売を行う際に、必ずロイヤリティを同時に支払うよう制御する“強制徴収型NFT”を実現しようとするものでした。しかし、既存マーケットとの互換性が崩れることや、ユーザー体験(UX)の悪化、さらに「自由市場の理念」との衝突もあり、ほとんど採用されませんでした。

そして2022年、AMM形式でNFTを取引できる sudoswap が登場し、状況は決定的に変わりました。sudoswapはロイヤリティを一切徴収しない仕組みを採用し、「支払わなくても成立する市場」を作り上げたのです。この流れはBlurなどの他のプラットフォームにも波及し、最終的にOpenSeaも2023年にロイヤリティの任意化を発表しました。

このようにして、NFTのロイヤリティは制度として事実上崩壊しました。結局のところ、ロイヤリティはブロックチェーンが保証する権利ではなく、プラットフォームが信義的に運用していたルールにすぎなかったのです。

現在では、NFTの価値設計は「転売報酬」から「一次販売+コミュニティ参加価値」へとシフトしています。EIP-2981は理念を示し、EIP-2571は理想を追いましたが、市場が選んだのは、よりシンプルで自由なノーロイヤリティの形でした。

第5章

DEX

AMM DEXの価格決定

Uniswapなどの分散型取引所(DEX)は、自動マーケットメイカー(AMM)と呼ばれる仕組みで動いています。このAMMでは、常に次の関係が成り立っています。

ETH × DAI = k(一定)

ここで「k」はプール全体のバランスを保つための定数です。この関係により、ETHとDAIの価格が自動的に決定されます。

流動性供給とは

流動性供給(Liquidity Providing)とは、ユーザーがETHとDAIなどのペアでプールに預けること。その代わりに「LPトークン」が発行され、プール内の持ち分(シェア)を表します。LPトークンを保有している限り、取引手数料の一部を受け取ったり、いつでも出資額を引き出すことが可能です。

Uniswap V2では、最初のLPがプールを作るとき、次の式でLPトークンが発行されます。

LP発行数 = √(ETH量 × DAI量) − 1000

このうち「√(ETH量 × DAI量)」の部分が幾何平均にあたります。幾何平均とは、二つの数のバランスの取れた平均値を表すもので、一方が大きくても、もう一方が小さければ全体の値は中央付近に引き寄せられます。算術平均((A + B)/2)が「足して割る平均」であるのに対し、幾何平均は「掛けて平方根を取る平均」であり、対称性とバランスを保つ性質があるのが特徴です。

UniswapのAMMは「ETH量 × DAI量 = k」という不変式の上で動いており、この k(プールの規模)に対して平方根を取ることで、プール全体を一辺の長さに換算した“スケール”を求めています。この「√(ETH量 × DAI量)」こそが、プールの流動性を表す幾何平均です。LPトークンはこのスケールに基づいて発行されるため、LPの総量はプール内資産の幾何平均そのものに対応します。

また、この「−1000」には重要な意味があります。

スクロールできます
理由内容
① 小さすぎるプールを禁止√(x×y)が1000未満だとマイナスになり、初期化が失敗する。
② バグ防止整数演算の誤差や0除算を防ぐ安全弁。
③ 価格の基準を固定最初のLPが全て引き出しても価格の軸が残るよう、1000枚を永久ロック。

この1000枚はバーン(誰も触れないアドレスへ送信)され、「プールの芯」として永遠に残ります。

この1000LPは「プールを壊れにくくするための固定分」です。もし全員が引き出せると価格の基準が消え、プール自体が消滅してしまうため、最初の人の資産の一部を永久にロックして安定性を保つ仕組みになっています。なお、このルールは Uniswap v2 の仕様 に基づくものであり、最近の派生DEX(SushiSwapやPancakeSwapなど)ではこの1000LPロックを設けていない場合もあります。つまり、現在は必ずしも“損をして固定分を残す”必要はない設計になっているのです。

たとえば、ETHが1ETH=4000DAIのときにAさんが「250 ETH + 1,000,000 DAI」を入れてプールを作ると、

項目
x = 250 ETHy = 1,000,000 DAI
k = 250 × 1,000,000 = 250,000,000
√k = 15,811.38
LP総発行 = √k − 1000 = 14,811.38枚
  • 1000枚は永久ロック(バーン)
  • 残り14,811枚をAさんが受け取る
  • これがAさんの「出資証明」となる

この状態で、Bさんが同じ比率で同額を入れると、AさんとBさんの持分はほぼ50%ずつになります。

流動性を追加するたび、プールの規模(面積k)が広がります。でもLPトークンは面積(k)ではなく、その平方根(√k) に比例して増えます

スクロールできます
直感的なイメージ数値例
プールが4倍に広がる(k×4)√kは2倍になる
プールが9倍に広がる(k×9)√kは3倍になる

kの平方根によれば、「もし誰かが「既存プールの10%」の資金を追加したなら、その人にも「全LPトークンの10%」が発行される」という比例してLPトークンが発行される状態を実現できます。

Uniswap v2 では、LPトークンの発行量は次のように計算されます。

LP_new = LP_total × (Δx / x_reserve)

(※Δx と Δy の比が同じとき)これは √k に基づく設計と一致します。

つまり、

  • プールに 100 ETH あるときに 10 ETH 追加したら
     → 10%増加なので LP も 10%増発行
  • プールに 100 万 DAI あるときに 10 万 DAI 追加したら
     → 10%増加なので LP も 10%増発行

こうして 流動性の追加=LP発行量の増加 が 線形(比例) になります。

一方、もし「LPを k に比例」して発行した場合、k は x×y なので、両方のトークンを 10% ずつ増やすと

k = (1.1 × 1.1) = 1.21 倍

つまり、LP も 21% 増えてしまいます。結果として、後から入った人のほうが得をする という不公平が生まれます。これが、Uniswap が「面積(k)」ではなく「√k(スケール)」を採用している理由です。

利用者がトレード(ETHとDAIの交換)をすると、

  • ETH量とDAI量のバランスが変わる
  • 価格が動く
  • でも「k(=ETH×DAI)」は一定のまま

その間、LPの持分(シェア)は変わりません。ただし価格が変動した分、引き出すときの価値が上下します。これが「インパーマネントロス(評価差損)」です。

インパーマネントロス

インパーマネントロス(Impermanent Loss)とは、流動性を提供している間に発生する未確定の損失のことです。
AMMでは「ETH量 × DAI量 = k」という一定の関係が保たれるように、価格が動くたびにプール内の資産比率が自動的に調整されます。この自動リバランスが、単純に資産を持っていた場合よりも価値が下がる要因となります。インパーマネントロスは、わざと損を出すように設計されているわけではありません。AMMが価格を自動で調整する仕組みの副作用として、結果的に評価額が下がることがあります。そのリスクを補うために、取引手数料(例:0.3%)が流動性提供者に分配されるようになっています。

「Impermanent(インパーマネント)」は直訳すると「一時的」という意味ですが、DeFi文脈では「引き出すまで確定していない損失」を指します。つまり、まだプールから資産を取り出していない間は、評価上は損をしていても、確定していない=未実現損の状態です。市場価格が元に戻れば、この損失は消えるため “impermanent(非永久)” と呼ばれています。逆に、価格が戻らないまま引き出してしまえば、損失は確定して “permanent(永久的)” になります。

AMMでは、価格が変動するとトークンの量が自動で調整されます。たとえば、1ETH=4000DAIのときに「1ETH + 4000DAI」をプールに預けると、総額は8,000DAI相当になります。その後、ETH価格が倍の8,000DAIになったとします。プールは「ETH量 × DAI量 = k」を維持するため、ETHが売られDAIが増え、おおよそ次のようなバランスに変化します。このとき、プール内部では 2つの条件 が同時に成り立っています。

① x × y = k         ← プール内の積(流動性)は一定
② y ÷ x = 8,000     ← 外部市場の新しい価格に一致

ここで

  • x:ETHの残高
  • y:DAIの残高
  • k:初期状態での定数(1 × 4000 = 4000)

この2式を連立して解くと次のようになります。

y = 8,000x
x × 8,000x = 4,000
x² = 0.5
x = √0.5 = 0.7071
y = 8,000 × 0.7071 = 5,656.85

つまり、価格が2倍になった時点で、プール内のETH残高は0.7071ETH、DAI残高は5,656.85DAIに自動調整されます。これは「k=4000(面積)は変わらず、傾き(価格比率)だけが変わる」というAMMの仕組みによって決まる数値です。

スクロールできます
項目
ETH残高0.7071 ETH
DAI残高5,656.85 DAI
合計価値0.7071 × 8,000 + 5,656.85 = 11,313.65 DAI

一方、もし単純に1ETHと4000DAIを持っていた場合は1ETH × 8,000 + 4,000 = 12,000 DAI です。差額(約−686 DAI = −5.7%)がインパーマネントロスです。この「連立で求める」という考え方こそ、AMMを理解するうえでの核心です。掛け算(x×y)は“面積(流動性)”を保ち、割り算(y÷x)は“価格(比率)”を決める。その両方を同時に満たす点を探すことで、プール内の新しいバランスが自動的に定まります。

そして重要なのは、どちらか一方の価格が大きく動けば動くほど、もう一方の量が急激に減り、損失幅が指数的に拡大していくということです。これはAMMが線形(比例)ではなく非線形(曲線)で動いているためで、「x×y=k」という構造が、価格変動に対してどんどん傾きが急になる(価格感応度が増す)性質を持っているからです。

スクロールできます
価格比ETH価格変動プール内ETHプール内DAIプール総額 (DAI換算)単純保有時価損失率
0.5ETH価格 ½1.4142 ETH2828.4 DAI5656.8 DAI6000 DAI−5.7%
1.0変化なし1.0000 ETH4000.0 DAI8000.0 DAI8000 DAI0.0%
2.0ETH価格 2倍0.7071 ETH5656.9 DAI11,313.6 DAI12,000 DAI−5.7%
3.0ETH価格 3倍0.5774 ETH6928.2 DAI12,659.4 DAI14,000 DAI−13.4%
5.0ETH価格 5倍0.4472 ETH8944.3 DAI13,180.3 DAI16,000 DAI−25.5%

インパーマネントロスは数式上、IL(r) = IL(1/r) が常に成り立つため、本来は左右対称です。しかし線形スケールで描くと、rが1未満の領域が圧縮されて表示されるため、非対称に見えてしまいます(価格が半分になる(0.5倍)と、線形軸ではわずか0.5の距離しか動きません。一方、2倍になると1の距離動くため、右側が2倍広く見えるのです。実際には「2倍」と「1/2倍」は対称な変化なのに、線形軸では左側が押し潰されたように表示されてしまいます。)。対数スケールを使うことで、価格の倍率変化(0.5倍・2倍など)が等間隔に配置され、理論どおりの対称性が正しく可視化されます。

Uniswapの仕組み(概要)

Uniswapのスマートコントラクトは、Core(コア)・Periphery(ペリフェリー)・Pair(ペア)という三層構造で設計されています。この分離こそが、Uniswapを安全かつ柔軟に進化させる仕組みの核です。

CoreはUniswapの中核をなす層で、実際のトークン残高と価格ロジックを保持しています。ここで最も重要な役割を果たすのがPairコントラクトです。Pairは1つのトークンペア(例:WETH/USDC)ごとに存在し、プール内の残高を使って「x × y = k」という不変の関係式を保ちます。トレーダーがETHをDAIに交換するたび、Pairコントラクトは自動的に残高を再計算し、価格を調整します。流動性提供者(LP)はここに資産を預け、そのシェアに応じたLPトークンを受け取ります。LPトークンを返却すれば、ペア内の比率に基づいてトークンが払い戻されます。つまりCoreは、資産を安全に保管し、取引の数学的整合性を維持する金庫のような存在です。

Peripheryは、ユーザーやDAppがCoreを直接操作せずに安全に取引できるよう設計された“外側の層”です。代表的なのがRouterコントラクトで、複数ペアをまたぐスワップや流動性追加の手続きを一括で処理します。Routerはトークンを一時的に扱うだけで、最終的な資産の移動や保管はCore(Pair)側で行われます。そのため、仮にRouterに不具合があっても、Core内の資金が失われることはありません。

Swapの仕組み

DEXでは、ユーザーがトークンを交換(スワップ)するときに、実際の資産移動は Routerコントラクト → Pairコントラクト(Core) の順で行われます。Uniswapの場合、この一連の流れを担っているのswapExactTokensForTokens() という関数です。これは「ある数量のトークンAを入れて、できるだけ多くのトークンBを受け取る」という最も基本的なスワップ関数です。

関数の引数には次のような情報を渡します:

スクロールできます
引数名内容
amountInスワップする元トークンの数量
amountOutMin最低限受け取りたいトークンの数量(スリッページ防止)
path交換経路(例: [WETH, USDC, DAI] )
to受け取り先アドレス
deadlineトランザクションの有効期限(タイムアウト防止)

ユーザーがトークンAをRouterに送ると、Routerが順番にA→B、B→Cといった複数のペア(Pairコントラクト)を経由して交換を実行します。このとき、実際のスワップ処理はRouterではなく、Pairコントラクト(Core)側のswap()関数で行われます。Routerはあくまで「流れを制御する司令塔」です。

function swapExactTokensForTokens(
    uint amountIn,
    uint amountOutMin,
    address[] calldata path,
    address to,
    uint deadline
) external returns (uint[] memory amounts) {
    // ① 各ステップでの受取量を計算
    amounts = UniswapV2Library.getAmountsOut(factory, amountIn, path);

    // ② 最低受取量を満たさなければ revert
    require(amounts[amounts.length - 1] >= amountOutMin, 'INSUFFICIENT_OUTPUT_AMOUNT');

    // ③ 入力トークンを最初のペアに送金
    TransferHelper.safeTransferFrom(
        path[0], msg.sender, UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0]
    );

    // ④ 各ペアでスワップ実行
    _swap(amounts, path, to);
}

内部で呼ばれる _swap() 関数が、実際にトークンの送受信をCore(Pair)に対して行います。

function _swap(uint[] memory amounts, address[] memory path, address _to) private {
    for (uint i; i < path.length - 1; i++) {
        (address input, address output) = (path[i], path[i + 1]);
        address to = (i < path.length - 2)
            ? UniswapV2Library.pairFor(factory, output, path[i + 2])
            : _to;
        uint amountOut = amounts[i + 1];
        IUniswapV2Pair(UniswapV2Library.pairFor(factory, input, output))
            .swap(0, amountOut, to, new bytes(0));
    }
}

つまり、各ペアで swap() を呼び出して次のペア(または受取先)にトークンを送るというループを行っているだけです。amountOutMin の指定があるため、実際の受取額が期待値よりも下回るとトランザクションは失敗(revert)します。これにより、価格変動やフロントランニングによる損失を防止しています。

スワップ処理の実体は、Core層の Pair コントラクトで行われます。Router はあくまで「どのペアをどの順番で呼び出すか」を制御するだけで、実際のトークン移動や価格計算は Pair コントラクト側の swap() 関数で完結します。Pair コントラクトでは、受け取ったトークン量と送出するトークン量をもとに次の関係が常に成り立つようにチェックしています。

(取引後のトークンA残高)×(取引後のトークンB残高) ≧ (取引前のトークンA残高)×(取引前のトークンB残高)

この「A残高 × B残高 = k」という定数積の法則(constant product formula)を守ることで、価格操作や不正な利益取得を防いでいます。また、取引手数料(通常0.3%)はプールの内部に自動的に残り、流動性提供者(LP)全体の持分に反映されます。つまり、手数料が積み上がることでk の値は増加方向にしか動かないよう設計されています。

このようにして Router から Pair へと複数のスワップが連続実行され、最終的にユーザーが指定した受取先アドレスにトークンが送られます。すべての処理は1つのトランザクションとしてまとめて実行されるため、途中でエラーが起きた場合は全体が取り消され(revert)、ユーザー資産が失われることはありません。

LPの仕組み

Uniswapでは、スワップだけでなく「プールに資産を預ける」ことで流動性を提供し、LPトークンを受け取ることができます。ユーザーがETHとDAIのような2種類のトークンを同時に預けると、Pairコントラクト内で次の処理が行われます。

  1. 預け入れ前後の残高を比較し、増えた分を amount0amount1 として計算
  2. 既存のリザーブ比率に応じて、発行すべきLPトークン数を算出
  3. 初回だけは「√(x×y) − 1000(永久ロック)」という特殊な計算で発行
  4. ユーザーにLPトークンを送付

このLPトークンは「あなたの出資比率」を示すもので、後から他の人がプールを利用したときに得られる手数料の一部をあなたの持分として受け取る権利を意味します。

流動性を引き上げたいときは、LPトークンをPairコントラクトに返却します。すると、返却された比率に応じてプール内の2種類のトークンが戻されます。このとき、LPトークンは burn() 関数で破棄され、対応する資産がユーザーに送られます。取引のたびにプール内に手数料が蓄積しているため、後から出金すると最初に入れた額よりわずかに多く戻る場合があります。

LPトークンとペアコントラクトの関係

Uniswapでは、各トークンペア(例:WETH/USDC)ごとに「ペアコントラクト(Pair)」と呼ばれるスマートコントラクトが1つ作られます。このコントラクトは、プールに預けられた2種類のトークンを保管し、x×y=k の定数積を維持するAMMの中核です。そしてこのペアコントラクトは、同時に LPトークンの発行元 でもあります。別のコントラクトがLPを発行しているわけではなく、各ペアコントラクト自身が ERC20トークンとして振る舞うように設計 されています。

これは、ペアコントラクトが Solidity の継承機能を利用してUniswapV2ERC20 コントラクトを継承しているためです。UniswapV2ERC20 は、トークン名・シンボル・残高管理・_mint_burn といったERC20トークンの基本機能を実装しており、ペアコントラクトはその上にスワップやリザーブ更新といったAMMロジックを追加しています。つまり、ペアコントラクトは「AMMロジック」と「ERC20トークン(LP)機能」を一体化した構造を持ち、この単一のコントラクトの中で流動性提供・LP発行・引き出しまでを完結させています。

たとえば、WETH/DAIのペアが存在する場合、UniswapV2Pair(WETH/DAI) という1つのコントラクトがあり、そこにプール資産のリザーブが保存され、同時にLPトークン(UNI-V2 WETH/DAI)もそのコントラクト自身によって発行されます。LPトークンを持つことは、そのペアコントラクトに預けられた資産の持分を所有することを意味します。

このように、UniswapのCoreは継承を使って「資産保管(Vault)」と「LP発行(ERC20)」を1つのペアに統合しており、コードの重複を避けつつ、非常にシンプルで安全な構造を実現しています。

ETHとERC20の交換の仕組み

Uniswapでは、基本的にすべての取引がERC20トークン同士で行われています。ところが、EthereumのネイティブトークンであるETHはERC20規格に対応していないため、スマートコントラクトはETHを直接扱うことができません。この問題を解決するために使われているのが「WETH(Wrapped ETH)」です。WETHは、ETHをスマートコントラクトに預けることで同額のERC20トークンを発行する仕組みで、1WETH=1ETHの比率で常に連動しています。

ユーザーがUniswapで「ETH→DAI」のスワップを実行すると、まずRouterコントラクトがETHを受け取り、WETH.deposit() を呼び出してWETHに変換します。次に、そのWETHを使って「WETH⇄DAI」の交換が行われ、最終的にDAIがユーザーのウォレットへ送られます。逆に「DAI→ETH」の場合は、スワップの最後でRouterが WETH.withdraw() を呼び出してWETHをETHに戻し、ユーザーへ送金します。

つまり、見た目はETHとERC20トークンを直接交換しているように見えても、内部的には「ETH → WETH → ERC20(またはその逆)」という処理が行われています。ETHは一度WETHコントラクト内に預けられ、スワップ後に再びETHとして戻される仕組みです。この設計によって、Uniswapはすべての取引をERC20標準のコードで統一し、例外のない安全でシンプルなアーキテクチャを実現しています。

Burn時の手数料の仕組み

Uniswapでは、すべてのスワップ取引で0.3%の手数料が発生し、その手数料は即時に誰かへ配分されるわけではなく、プール内に残ったままリザーブ(x, y)に上乗せされます。そのため、時間の経過とともにペアコントラクトの保有資産は少しずつ増えていき、プールの総価値がLP総供給量に対してわずかに大きくなります。

つまり、流動性提供者が後で burn() を行うと、自分のLP比率に応じてこの増えた分(取引手数料の累積分)を間接的に受け取ることになります。数式で表すと、「手数料=プール資産の増分」であり、LPの価値が時間とともに上がる構造です。

レンディングプロトコル

レンディングプロトコルとは、ブロックチェーン上でトークンの貸借を自動的に行う仕組みです。代表的なプロトコルにはAAVEやCompoundがあります。利用者は、自身の保有資産をプールに預け入れることで貸し手(Lender)となり、その資産を担保として別のトークンを借りることができます。したがって、借り手は同時に貸し手でもあるという構造になっています。誰かが資産を預けていなければ、誰も借りることはできません。すべての貸借はプール内に実在するトークンの範囲で完結します。

aTokenの仕組み

AAVEに資産を預けると、対応するaToken(例:aUSDC)が1:1で発行されます。このトークンは、元本に利息を反映した残高を表しており、ユーザーが何も操作しなくても時間の経過とともに残高が増加していくように見えます。ただし、実際にトークンが追加でミントされているわけではありません。AAVEではliquidityIndex(流動性インデックス) と呼ばれる内部の係数を用いており、ユーザーの残高は次の式で動的に計算されています。

aToken残高 = 預入元本 × liquidityIndex

この liquidityIndex はプールの利用状況(借入量や金利)に応じてブロックごとに更新されます。そのため、aTokenの balanceOf() を呼び出すたびに、利息を含めた最新の残高が返される仕組みになっています。利息の原資は、借り手が支払う金利です。プール全体としては、貸し手と借り手の間で収支が均衡するように設計されています。

借入と担保

ユーザーは預け入れた資産を「担保として有効化(Collateral Enable)」することで、その担保価値に応じて別の資産を借りることができます。借入可能額は、担保資産ごとに設定された LTV(Loan to Value) によって決まります。LTVとは「担保価値に対してどの程度まで借入を許すか」を示す安全率で、資産ごとの特性に応じて異なります。

スクロールできます
判定基準内容LTVの傾向
価格変動(ボラティリティ)価格が大きく動く資産は担保価値が急落しやすいためリスクが高いです。📉 低く設定されます。
市場流動性清算時にすぐ売却できる資産はリスクが低いです。📈 高く設定されます。
相関性借入資産と価格が連動する資産は危険です。📉 低く設定されます。
ステーブル性価値が一定のステーブルコインなどは安定しています。📈 高く設定されます。

このように、ステーブルコイン(USDCやDAIなど)は LTV が 80〜90%、ETHやWBTCなどの主要な変動資産は 70〜80%、流動性の低いトークンは 50%以下に設定されるのが一般的です。AAVEでは、これらのLTVや清算閾値(Liquidation Threshold)などのリスクパラメータはRisk Parameters Contractで管理され、DAOガバナンスによって定期的に見直されています。

債務履行の仕組み

借り手は、借りた資産に対してブロックごとに利息が発生し、その残高はDebt Token(負債トークン)としてオンチェーン上で管理されています。AAVEでは、変動金利用の VariableDebtToken と固定金利用の StableDebtToken が発行されますが、これらは通常のERC-20トークンとは異なり、譲渡や承認が一切できない設計になっています。コントラクトの transfer() 関数は無効化されており、ユーザーは自分の債務トークンを他人に送ることができません。したがって、債務はウォレットアドレスに固定的に紐づく構造になっており、返済義務を回避したり、他人へ債務を移転することはできません。

返済を行うと、スマートコントラクトの repay() 関数が呼び出され、指定した資産が返済に充てられると同時に、対応するDebt Tokenがバーン(burn)されます。これにより、債務残高が減少し、全額返済が完了した時点でDebt Tokenは完全に消滅します。つまり、Debt Tokenの残高=未返済の債務であり、返済するたびにトークンがバーンされることで、債務がオンチェーン上から消える仕組みになっています。返済が行われない場合は、担保が自動的に清算され、Debt Tokenが強制的に消滅します。

このように、発行(借入)・保有(債務)・バーン(返済)が一貫してスマートコントラクト上で管理されており、AAVEでは債務の履行を完全に自動化しています。

清算(Liquidation)

担保の価値が下落し、清算閾値(Liquidation Threshold) を下回ると、スマートコントラクトが自動的に清算を許可する状態になります。このとき、外部のユーザー(清算者)が liquidationCall() を実行することで清算が進行します。清算者は、借り手の債務の一部を指定されたトークンで返済し、その代わりに担保資産を一定の割引率(Liquidation Bonus)で取得します。たとえば清算ボーナスが5%の場合、清算者は市場価格より5%安く担保を買い取ることができるため、清算行為に経済的なインセンティブが生まれます。

この処理はすべてスマートコントラクト上で即時に実行され、担保の一部が売却されることで債務残高が減少します。AAVEでは、1回の清算で借入全体の最大50%までしか償還できない制限があり、残りの債務が安全水準まで戻らない場合は、再び清算が行われます。これにより、担保不足のポジションが放置されることなく、プール全体の健全性が保たれます。清算プロセス全体は分散的に実行され、特定の運営者が介入することはありません。

オラクルの仕組み

AAVEでは、担保や借入資産の価格情報をオラクル(Oracle)を通じて取得しています。これは、ブロックチェーン外の現実のマーケット価格をスマートコントラクトに提供する仕組みです。AAVEのメインオラクルはChainlinkで、各トークンごとに「ETH/USD」「BTC/USD」「USDC/USD」などの価格フィードが常時参照されています。これらの価格データは分散されたノードネットワークによって提供され、一定のブロック間隔で自動的に更新されます。

清算やLTV判定はすべてこのオラクルデータに基づいて行われます。たとえば、ETHを担保にUSDCを借りている場合、Chainlinkが提供するETH/USD価格が清算閾値を下回った瞬間に、スマートコントラクトが自動的に清算を許可します。また、Chainlinkオラクルが一時的に異常値を返したり停止した場合に備えて、AAVEには Fallback Oracle(代替オラクル) が設定されています。これはDAOによって管理されており、Chainlinkが利用できない場合にのみ作動し、手動または別のデータソースを基に暫定価格を供給します。

この二重構造により、AAVEは単一のデータソースに依存せず、価格の改ざんや異常値による誤清算を防止しています。オラクルはAAVEの安全性を支える中核コンポーネントであり、正確な価格提供がシステム全体の信用を成立させています。

金利の自動調整と支払

レンディングプロトコルでは、金利は人為的に決められるものではなく、需要と供給の比率に基づいて自動的に調整されます。プールの利用率(借入総額 ÷ 預入総額)が高くなると借入金利が上昇し、それに連動して貸出金利(aTokenの利回り)も上昇します。これにより、過剰な借入や資金の偏りが発生しないように、市場全体のバランスが保たれています。

AAVEでは、借入金利は負債残高へ自動的に加算され、ブロックごとに複利で更新されます。返済時または清算時にまとめて支払われる仕組みであり、借り手は利息を都度送金するのではなく、Debt Tokenの残高が時間とともに増える形で金利を負担します。借入金利はプールの利用率によって常に変動し、需要が高まると金利が急上昇します。その結果、担保価格が変わらなくても債務額だけが増加し、ヘルスファクター(担保安全率)が低下して清算される場合があります。つまり、金利上昇自体が清算リスクを引き起こす要因となっており、AAVEの自動金利調整はシステムを守る仕組みである一方、借り手にとっては潜在的なリスクでもあります。

AAVE Arc(アーベ・アーク)

AAVEには、規制対応と機関投資家向け利用を目的とした特別バージョンであるAAVE Arcがあります。AAVE Arcでは、一般ユーザーが自由に参加できる通常のAAVEと異なり、KYC(本人確認)を通過した認定アドレスのみが参加を許可されています。このモデルは、銀行・証券会社・ファンドなど、法規制に準拠した主体がDeFiの仕組みを利用できるように設計されています。

スマートコントラクトの構造はAAVEと同一ですが、アクセス制御が追加されており、コンプライアンスを確保したままオンチェーンで資金運用が行える点が特徴です。AAVE Arcは、DeFiの「完全なオープン性」と、伝統的金融の「法的信頼性」の中間に位置するモデルであり、今後の規制対応型DeFi(RegFi)の方向性を示す先行事例となっています。

フラッシュローン(Flash Loan)

フラッシュローンとは、担保を必要としない一時的な融資の仕組みです。ブロックチェーン上では、すべての処理が同一トランザクション内で完結する必要があり、その性質を利用して「借入と返済が同時に行われるなら担保はいらない」という発想で設計されています。利用者はスマートコントラクトを通じて資産を借り入れ、その資金で任意の処理(アービトラージ、担保の入れ替え、清算の肩代わりなど)を行い、同一トランザクション内で元本と手数料を返済します。もし返済が完了しなければ、トランザクション全体がロールバック(取り消し)され、借入は最初から存在しなかったことになります。

この仕組みにより、プロトコルは無担保でもリスクを負わずに瞬間的な貸出を実現しています。手数料(例:0.05〜0.09%)はトランザクション成功時にのみ発生し、失敗時には何も実行されません。フラッシュローンは、通常のユーザーが手動で使うものではなく、スマートコントラクトを自動実行できる開発者やアービトラージャー向けの機能です。代表的な用途には以下のようなものがあります。

  • アービトラージ取引:複数のDEX間で価格差を利用して利益を得る。
  • 担保の入れ替え(Refinancing):借入ポジションを清算せずに別資産へ切り替える。
  • 清算代行:他人のポジションを清算して報酬(清算ボーナス)を得る。
  • ポジション再構成:複数のDeFiプロトコルを跨いだ資金移動やレバレッジ操作。

この機能はAAVEが最も早く実用化しましたが、現在では Balancer、Uniswap v3、DyDx、Cream Finance など多くのプロトコルにも実装されています。それぞれの仕組みはほぼ共通しており、「同一トランザクション内で完結しなければ成立しない」という原則の上に構築されています。

フラッシュローンは、DeFiの「資金の瞬間流動性」を支える重要な機構であり、市場の価格効率化や流動性均衡にも貢献しています。一方で、設計を誤ると脆弱なプロトコルがフラッシュローン攻撃(Flash Loan Attack)によって不正な価格操作や資金吸い上げを受けるリスクもあるため、近年では多くのプロジェクトがこの機能を制限的または安全に管理された形で提供しています。

第6章

コントラクトウォレット

コントラクトウォレットとは、従来のExternally Owned Account(EOA)のように1つの秘密鍵に依存するのではなく、ウォレットのルールをスマートコントラクトで定義するアカウント構造です。これにより、署名・送金・復旧・ガス支払いなどをコードで制御できるようになり、安全性と柔軟性を両立したウォレット運用が可能になります。

マルチシグ(Multi-Signature)

マルチシグは、複数のEOAが1つのコントラクトウォレットを共同で操作する仕組みです。ウォレットコントラクトは owners[] 配列として署名者のEOAを保持し、設定されたしきい値(threshold)以上の署名が集まらなければ取引を実行しません。

function execTransaction(...) public {
    require(getSignatureCount(txHash) >= threshold, "Not enough signatures");
}

署名は ecrecover() で検証され、登録オーナーでない署名は無効化されます。

  1. 各オーナー(EOA)が送金データに署名する。
  2. 署名をすべて集めてコントラクトへ送信。
  3. コントラクトが署名数を検証し、しきい値を満たせば実行。

本質的には「複数のEOAが1つのCA(スマートコントラクト)に命令を出している」構造であり、コントラクト自体は“資金を持つ器”ではなく“合意ルールを強制するロジック”です。

ソーシャルリカバリー(Social Recovery)

ソーシャルリカバリーは、秘密鍵を紛失しても信頼できる他者(ガーディアン)によって所有権を再登録できる仕組みです。コントラクトウォレットの内部には現在のオーナーEOAが記録されており、ガーディアン(複数EOA)が多数決で新しいEOAを承認すると、所有者が上書きされます。

function recoverAccount(address newOwner, bytes[] guardianSigs) external {
    require(validApprovals(guardianSigs) >= threshold, "Not enough guardians");
    owner = newOwner;
}
  1. 所有者が秘密鍵を失う。
  2. 事前登録済みのガーディアンEOAが新しいEOAを指定して署名。
  3. 規定数の署名が揃うと、コントラクトが owner を新EOAに置き換える。

ガーディアンには家族・別デバイス・法人用マルチシグなどを指定でき、「秘密鍵喪失=資産喪失」という従来構造を回避します。本質的には「所有者EOAを書き換える権限を他のEOAに一時的に委任する」設計です。

アカウントアブストラクション(Account Abstraction, AA)

AAは、EOAそのものを使わずに、アカウント機能をコントラクトで再構成する仕組みです。従来は「EOAが署名→ネットワークが検証→コントラクトを呼び出す」という固定ルールでしたが、AAではその署名検証・送信機能をコントラクト側に移します。

EIP-4337では、標準トランザクションの代わりに UserOperation という構造体を使います。

struct UserOperation {
    address sender;      // コントラクトウォレットのアドレス
    bytes callData;      // 実行する処理
    uint256 nonce;
    bytes signature;     // 任意形式の署名
}

このデータをバンドラー(Bundler)ノードが集約し、EntryPoint コントラクトの handleOps() に送信します。

EntryPoint.handleOps(UserOperation[] calldata ops)

EntryPointは各ウォレットの validateUserOp() を呼び出して署名を検証し、成功した場合に callData を実行します。このとき EntryPointがEOAの代理としてCAを呼び出すため、EOAが存在しなくてもコントラクトウォレットが自律的に動作できます。

  1. ユーザーがローカル署名でUserOperationを生成。
  2. BundlerノードがEntryPointへ送信。
  3. EntryPointがウォレットの validateUserOp() を呼び出し、署名を検証。
  4. 承認されたらウォレットが指定の処理(他CA呼び出しなど)を実行。
  5. ガス代はウォレットまたはPaymasterが支払い。

EOAの「署名+送信」という役割を、EntryPointとコントラクトウォレットのロジックが分担して再現しているのがAAの本質です。ウォレット自身が署名検証を行うため、認証方式を自由化できます(生体認証・マルチ署名・時間制限など)。

補足:AAにおける「EOAがないのにTXできる」仕組み

AAでは「EOAが消える」のではなく、EOAが担っていた署名と送信の役割を別の仕組みで再現しています。具体的には、ユーザーは「UserOperation」という署名付きデータを作成し、それをBundlerと呼ばれるノードに送信します。

Bundlerは複数のUserOperationをまとめ、自分のEOAで署名した1つの通常トランザクションとして、EntryPoint コントラクトに送ります。EntryPoint は各ウォレットの validateUserOp() を呼び出し、署名検証が通ったものだけを実行します。つまり、ブロック上ではBundlerのEOAが送信者(from)ですが、EVM内部では各コントラクトウォレットが“自分自身のTX”として動いている構造になります。

結果として、ユーザーはEOAを直接操作しなくても、ウォレットとEntryPointの組み合わせによってTXの署名・検証・実行が自動で完結します。これが「EOAなしでトランザクションを発行できる」仕組みの本質です。

まとめ

スクロールできます
モデル署名者構造目的
マルチシグ複数のEOAコントラクトが署名数を検証集団合意によるセキュリティ
ソーシャルリカバリー複数EOA(ガーディアン)コントラクトで所有者EOAを更新秘密鍵喪失からの復旧
AA(EIP-4337)コントラクト自身EntryPoint+UserOperationEOAを不要化し、認証と支払いを自由化

これらはすべて「EOAの機能をどこまでコントラクト側に移すか」の違いです。マルチシグは複数EOAが支配する形、ソーシャルリカバリーはEOAの権限を委譲・再登録する形、AAはEOAの存在自体をコードで置き換える形です。

ENS

ENS(Ethereum Name Service)は、Ethereum上で動作する分散型の名前解決システムです。
従来のインターネットにおけるDNSのように、人が読める名前(例:alice.eth)をウォレットアドレス(例:0x1234...abcd)に対応付ける仕組みを、スマートコントラクト上で実現しています。

ENSは主に次の3つのスマートコントラクトから構成されています。

  • Registry:各ドメイン名の所有者やResolver(変換先情報)のアドレスを記録します。
  • Resolver:実際に「名前→アドレス」の変換を行います。
  • Registrar.ethドメインの登録や更新を管理します。

この仕組みによって、ユーザーはブロックチェーン上で安全かつ分散的にアドレスを扱うことができます。

名前解決の仕組み

ウォレットがENS名を解決するときの流れは次のようになります。

  1. ENS Registryに問い合わせ、対象ドメインのResolverアドレスを取得します。
  2. Resolverコントラクトのaddr()関数を呼び出します。
  3. 戻り値として、対応するウォレットアドレスが返されます。

このように、ウォレットはEthereum上のスマートコントラクトを通じて、「名前」と「アドレス」の対応関係を取得しています。

ウォレットがENSを扱える理由

MetaMaskやRainbowなどの主要ウォレットは、Ethereum Mainnet上のENS Registryを標準で参照するように設計されています。ENS Registryのコントラクトアドレスは固定であり、ウォレットは常にそこへ問い合わせを行います。

  • Registryアドレス:0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e(Ethereum Mainnet)

そのため、.ethドメインはどのウォレットでも安定して利用できます。逆に言えば、このRegistryに登録されていないドメインは、ウォレットから見て「存在しない」扱いになります。

ENS以外にも、Unstoppable Domains、Space ID、Bonfidaなど、さまざまなネームサービスがあります。しかし、それぞれが異なる仕様やチェーンを採用しているため、ウォレットが個別に対応しなければ名前解決はできません。

たとえば次のような違いがあります。

スクロールできます
ウォレット対応しているネームサービス
MetaMaskENSのみ(Ethereum Mainnet固定)
Coinbase WalletENS、base.id
Trust WalletENS、Unstoppable Domains、Space ID
RainbowENS、CCIP-Read対応L2

このように、同じドメインであってもウォレットによって解決できたりできなかったりするのは、ウォレットがどのネームサービス仕様に対応しているかで決まります。

EthereumのL2やサイドチェーン上では、独自のネームサービスを提供するプロジェクトが数多く存在します。「.base」や「.bnb」など、各チェーン固有のドメインを発行するものもありますが、これらの多くはENS(Ethereum Name Service)を模倣した独自仕様のスマートコントラクトを利用しています。しかし、MetaMaskなどのウォレットはこれらの独自Registryを参照しません。ウォレットは、あくまでEthereum Mainnet上のENS Registryを固定的に参照しており、他のチェーンに存在するネームサービスは解決対象にならない仕組みになっています。そのため、L2やサイドチェーン上で独自に「ENSライクな」ドメインを提供していても、そのコントラクトがENSの標準仕様に準拠しておらず、MainnetのENS Registryと接続されていない場合、ウォレットからは認識されません。結果として、「.base」や「.bnb」などのドメインを登録しても、MetaMaskなどでは利用できないのです。

一方で、ENS公式チームはL2対応のためにCCIP-Readという仕組みを導入しています。これは、Ethereum Mainnet上のENS Resolverから他チェーン上のデータを参照できるようにするための標準仕様です。この仕組みを実装したL2側のサービスは、MainnetのENSと連携し、ウォレットからも認識されるようになります。つまり、L2やサイドチェーンで提供されるネームサービスがウォレットで利用できるかどうかは、単にそのチェーン上で動いているかではなく、ENS標準(EIP-137)やCCIP-Readを実装しているかどうかで決まります。ENSの設計思想に準拠し、Mainnetとの接続を正しく行っているプロジェクトだけが、既存のウォレット環境でもシームレスに動作するのです。

例えば、base.idは、ENSの仕組みをBaseチェーンに拡張したL2 ENSです。ただし、ENS Registry自体はEthereum Mainnetに残り、名前(ネームスペース)のルート管理はMainnet側が行います。

  • 所有権のNFTはBase上で発行
  • 名前データ(resolver情報)もBase上に保存
  • Ethereum側のResolverは CCIP-Read経由でBase上のデータを読み出す

という設計になっています。

スクロールできます
ENS (.eth)base.id (.base.id)
ルート管理Ethereum Mainnet (ENS Registry)Ethereum Mainnet(共通)
所有権NFTEthereum Mainnet(.eth NFT)Baseチェーン上のNFT
データ保存Ethereum Mainnet(Resolver)Base(L2 Resolver)
通信同一チェーン内で完結CCIP-Read経由でMainnetと接続

オラクル

ブロックチェーンは外部の現実世界の情報(例:価格、天気、為替、イベント結果)を自分では取得できません。これを「オラクル問題(Oracle Problem)」といいます。例えば、スマートコントラクトが「ETH/USD価格が3,000ドルを超えたら実行」という条件を持っていても、その価格情報をどこから持ってくるかを知らないのです。その「外部情報の取得とブロックチェーンへの安全な入力」を担うのがオラクル(Oracle)です。

Chainlinkの基本構造

Chainlinkは最も広く使われている分散型オラクルネットワークで、複数の独立したノードオペレーターが外部情報を取得・検証し、合意形成してからブロックチェーンに報告する仕組みをとっています。基本的な構成は以下の通りです。

スクロールできます
コンポーネント役割
スマートコントラクト(オンチェーン)リクエストと結果の格納先。Aggregator Contractなどがある。
Chainlinkノード(オフチェーン)外部APIからデータを取得し、オフチェーンで集約・合意を形成。
データプロバイダ(API提供者)現実世界の情報を提供する外部ソース。
Coordinator(報告者)オフチェーンでの合意結果をオンチェーンに投稿。

オフチェーン・レポーティング(OCR)

Chainlinkは初期のバージョン(V1)では、各ノードが個別にオンチェーンにトランザクションを送る方式でした。これだとガスコストが高く、冗長です。そこで現在の主流である OCR(Off-Chain Reporting) が導入されました。これは、ノード間でオフチェーン合意を行い、1回のオンチェーン書き込みで済ませる仕組みです。

フェーズ内容
データ収集(Off-chain Data Collection)Chainlinkノードが、外部データソース(例:CoinGecko、Binance、Kraken APIなど)から指定の指標(例:ETH/USD)をそれぞれ独立して取得します。
ローカル集計(Local Observation)各ノードは取得した価格データを「オブザベーション」として保持し、署名付きでネットワークに送信します。
オフチェーン合意形成(Off-chain Consensus)ノード間で暗号署名付きメッセージを交換し、中央値や加重平均値を算出します。BFT(Byzantine Fault Tolerance)を満たすノード数で合意が成立します。この工程はオフチェーンで実行されるため、ガスコストは発生しません。
レポート生成(Report Aggregation)合意済みの最終値を、選出されたAggregator(報告ノード)が1つのレポートにまとめます。全ノードの署名(署名集合)が付与されます。
オンチェーン報告(On-chain Transmission)Aggregatorが1回だけトランザクションを送信し、レポートをオンチェーンのAggregator Contractに書き込みます。これにより最新の価格(例:ETH/USD = 2999.85)がブロックチェーン上に確定します。
価格の更新トリガー(Price Update Trigger)価格の更新は「定期的な時間間隔(heartbeat)」または「価格変動が一定閾値を超えたとき(deviation threshold)」で発生します。たとえば、15分ごと、または前回の価格から0.5%以上変動した場合に新しい報告サイクルが開始されます。
データ利用(Contract Consumption)他のスマートコントラクト(例:Aave、Uniswap、Synthetixなど)がAggregator Contractから最新値を参照し、担保価値評価や清算判定などに利用します。

価格更新の仕組み

Chainlinkのデータフィードでは、価格が更新されるタイミングは次の2つの条件のどちらかを満たしたときです。

スクロールできます
条件説明
1. Heartbeat(ハートビート)一定時間ごとに必ず更新される周期的トリガー。価格変動がなくても、最低頻度で最新データをオンチェーンに反映します。例:1時間に1回必ず更新
2. Deviation Threshold(変動閾値)前回の価格からの変動率が一定以上になった場合に更新。大きな価格変動時のみ即時反映されます。例:±0.5%以上の変動で更新

「Aggregator Rounds」は、上記2条件のいずれかで価格更新が行われた結果として作成される1サイクル(更新単位)です。つまり、トリガーではなく「更新が起きた後に付与されるID」的な存在です。HeartbeatまたはDeviationにより新しい値が投稿される→ 新しい Round ID が割り当てられる→ Chainlink Aggregatorでその更新履歴が追跡できるという流れになります。

更新頻度

Chainlinkなどの分散型オラクルが提供する価格データは、一般的に数十秒から数分おきに更新されます。これは、取引所でのリアルタイム取引価格の参照を目的としていないためです。Chainlinkのようなオラクルは、AaveやMakerDAOなどのDeFiプロトコルにおいて担保評価や清算判定に使われる「信頼できる基準価格」を提供することを目的としています。頻繁に更新するとガスコストが増大し、取引所の一時的なスパイクを拾って誤清算が発生するリスクもあるため、あえて精度と安全性を優先してゆっくり更新する設計になっています。

一方、Pyth Network のような新しいオラクルは、取引所から直接リアルタイム価格データをブロードキャストする仕組みを採用しています。Pythでは、取引所やマーケットメイカーが自らの注文板データや約定データを暗号署名付きでPythネットワークに投稿し、オンチェーンではなくオフチェーン集約+高速配信によって数百ミリ秒単位の更新を実現しています。この仕組みにより、Pythはトレーディングやデリバティブ取引など、即時性が求められる用途でも価格指標として利用可能なのです。つまり、

  • Chainlink型:契約執行や担保評価に使うための「正確で安全な基準価格」
  • Pyth型:リアルタイム性を重視した「取引向けの市場価格」

というように、両者は同じ“価格オラクル”でも目的と設計思想が異なるのです。

LINK

LINKは、Chainlinkネットワークを動かすための報酬兼担保トークンです。Chainlinkのオラクルノードは、外部データ(例:価格情報)を取得・集約してブロックチェーン上のコントラクトに書き込み、その対価としてLINKで報酬を受け取ります。また、ノードは信頼性を担保するためにLINKをステーク(預け入れ)し、不正を行えば没収(スラッシュ)される仕組みになっています。

ユーザーが見る価格データは、オラクルが直接返しているものではありません。実際には、AaveやSynthetixなどのDeFiプロトコルがChainlinkオラクルを呼び出し、その結果を自分たちのスマートコントラクトに保持している値を見ています。これらのプロトコルが、オラクルにLINK(またはETH)で報酬を支払い、データ更新を依頼しているため、一般ユーザーはその結果を無料で参照できるのです。

ブリッジ

ブリッジ(Blockchain Bridge)は、異なるブロックチェーン間で資産やデータを移動させる仕組みです。
たとえばEthereum上のUSDCをArbitrumに送ったり、Solana上のトークンをPolygonで使ったりする際に使われます。
ブロックチェーンは原則として他チェーンの状態を直接参照できないため、
「Aチェーンで起きたことをBチェーンでも安全に再現する」ための仲介層としてブリッジが存在します。

言い換えれば、ブリッジとは**チェーンの独立性と互換性をつなぐ“翻訳機”**です。
その設計の本質は、「どこを信頼し、どうやって検証するか(Trust Model)」にあります。

主な方式

① ロック&ミント(Lock–Mint)

送信元チェーンで資産をブリッジコントラクトに「ロック」し、受信側チェーンで同量のWrapped Token(ラップトークン)を「ミント」する方式。例:Ethereumで10 USDCをロック → Arbitrum側で10 USDC.wを発行。戻すときは逆に「バーン → アンロック」。

  • 利点:実装が容易で、最も一般的。
  • 欠点:ロックコントラクトやマルチシグの侵害が致命的。

代表例:Polygon Bridge、Avalanche Bridge、WBTC

② バーン&ミント(Burn–Mint)

一方のチェーンでトークンを「バーン」し、他方で同量を「ミント」する方式。ロックを介さないため、裏付け資産の保管リスクがなく、供給総量が常に一定です。この構造はEthereumとArbitrumやOptimismなどの同系列チェーン(L1–L2間)でよく使われます。

  • 利点:ロック不要で安全、資産裏付けが自動的に保証される。
  • 欠点:双方向連携が必要なため、独立チェーン間では実現が難しい。

代表例:Arbitrum Bridge、Optimism Gateway、Cosmos IBC

③ アトミックスワップ(Atomic Swap)

仲介者を介さず、異なるチェーン上の資産を同時かつ条件付きで交換する方式。ハッシュタイムロックコントラクト(HTLC)を利用し、「全体が実行されるか、まったく実行されない(atomic)」という性質を保証します。

  • 利点:完全に信頼不要(trustless)。第三者に預けない。
  • 欠点:実装が複雑で、対応チェーン・流動性が限られる。

代表例:Bitcoin ↔ Litecoin スワップ、ThorChain

信頼モデル(Trust Model)

ブリッジを理解するうえで最も重要なのが「どこを信頼するのか」という設計思想です。同じ“資産転送”でも、裏で何を信じて動いているかで安全性も中央集権度もまったく異なります。

① Trusted(中央管理型)

最も単純なモデルで、管理者や運営者がブリッジを直接運営します。ユーザーはブリッジ契約に資産を預け、運営側が別チェーンで対応資産を発行・送金します。

  • 信頼の根拠:運営者の誠実性とセキュリティ管理
  • リスク:鍵の流出・内部不正・破産など人為リスク
  • 特徴:銀行や取引所に近い構造で、高速かつ低コストだが、完全に中央集権

代表例:Binance Bridge、CEXのクロスチェーン入出金

② Federated(マルチシグ/委員会型)

複数の署名者(validator set)が共同で資産移動を承認する方式。例えば「7人中5人の署名が揃えば転送を承認」といった仕組みです。

  • 信頼の根拠:少数の誠実な署名者が存在すること
  • 利点:単一管理者より安全で、速度と分散のバランスが良い
  • リスク:署名者間の共謀や鍵漏洩、ノードの停止

代表例:Ronin Bridge(Axie Infinity)、Polygon PoS Bridge

③ External Oracle / Relayer(外部検証型)

オラクルネットワークやリレーノードが、一方のチェーンのイベントを検知し、もう一方のチェーンでその情報を再現します。信頼は分散されますが、最終的には「オラクルネットワークの正直さ」を前提にします。

  • 信頼の根拠:多数のノード合意による確率的安全性
  • 利点:高速でスケーラブル、複数チェーン間に拡張しやすい
  • リスク:ネットワーク全体の妥協やデータ改ざんリスク

代表例:LayerZero、Axelar、Wormhole、Chainlink CCIP

④ Trustless(暗号的検証型)

各チェーンのスマートコントラクトが暗号証明(Merkle proof、ZK proofなど)を直接検証する仕組み。他のノードや運営者を信頼せず、チェーン間で相互に状態を認証できます。

  • 信頼の根拠:暗号学的証明そのもの
  • 利点:第三者不要で最も安全、理論的には完全な自律分散
  • リスク:設計と実装が非常に複雑、ガスコストが高い
  • 代表例:Arbitrum・Optimism(Rollup検証)、Cosmos IBC、zkBridge

このモデルはブリッジ技術の最終形態とも言われ、「人ではなく暗号が信用を担保する」世界を実現しています。

Tornado cash

Tornado Cashは、Ethereum上で入出金の関連を切断し、資金の出どころを誰にも特定できなくする匿名化プロトコルです。ブロックチェーンはすべての履歴が公開されるため、誰でも「誰がどこに送ったか」を追える構造になっています。Tornado Cashはこの透明性の裏返しであるプライバシー欠如を補う仕組みです。

基本構造

利用者は Tornado Cash コントラクトに資産(例:1 ETH)を入金(deposit)すると、Note(ノート)と呼ばれる暗号的チケットを受け取ります。このノートは、以下2つの秘密値から構成されます:

スクロールできます
要素役割
secretあなたの個人鍵のような乱数。入金を証明するために使う。
nullifier(ヌリファイア)同じノートを2回使えないようにする識別子。

これらをハッシュ化した commitment = hash(nullifier, secret) がブロックチェーン上のMerkle Tree に登録され、入金記録として保存されます。ブロックチェーン上には “commitment” しか残らず、誰が預けたか(アドレス) は完全に切り離されています。

引き出しの仕組み:ゼロ知識証明(zk-SNARKs)

出金時、ユーザーはノートを使って「自分のcommitmentがMerkle Tree内に存在する」ことを
ゼロ知識証明(zk-SNARKs) で証明します。この証明は次の2条件を満たします:

  1. 自分のdepositがツリーの中に確かに存在している
  2. nullifierがまだ使われていない(=二重出金ではない)

コントラクトはこの証明を検証し、正しければロックされていた資金を任意の受取アドレスに送金します。このとき、入金したアドレスはまったく関係なく、ノート(secret)を知っている人が“鍵”のように引き出せる仕組みになっています。

Anonymity Set(匿名性セット)

Tornado Cashの匿名性の強度は、同じ条件で混ざっている他のユーザー数=Anonymity set で決まります。

スクロールできます
プールDeposit件数匿名性
1 ETH プール100件匿名性 = 100
10 ETH プール3件匿名性 = 3
  • 金額を固定するのは「誰がどれを出したか」を均質化するため。
  • 時間をおいて他人と混ざるほど匿名性セットが拡大し、追跡が困難になる。
  • Deposit直後にWithdrawすると「1件だけ対応」になり、匿名性がほぼゼロになる。

つまり Tornado Cash の匿名化とは、「ゼロ知識証明で“自分のDepositが存在する”と証明し、
その証明を何百人もの他人のDepositの中に混ぜてしまう」という発想です。

リレイヤー(Relayer)の役割

匿名性をさらに強めるため、Tornado Cashではリレイヤーという中継者を利用できます。リレイヤーは利用者の代わりに出金トランザクションを送信し、ガス代を一時立て替えることで「どのアドレスが出金したか」という履歴を遮断します。

  • URLをコピーしました!

コメント

コメントする

目次