イーサリアムの誕生により、不変性の原則に基づいた新しいコンピューティング モデルが確立されました。このモデルでは、ソース コードは一度ブロックチェーンにデプロイされると永久に存在し、変更できません。しかし、実際のソフトウェア開発では、この不変性がバグ修正、機能更新、システム最適化に対する大きな障壁となります。ブロックチェーンの不変性とソフトウェアの柔軟性の必要性の間の矛盾を解決するために、代理契約モデルが標準ソリューションとして開発されました。 Tan Phat Digital チームがまとめたこのレポートは、代理契約の性質、基礎となる技術メカニズム、一般的な標準、特に現実のシナリオでエンド ユーザーを簡単にだまされる高度なセキュリティ リスクを深く分析しています。
1.コアコンセプトとステートとロジックの分離
イーサリアムの従来のスマート コントラクトはモノリシック エンティティであり、実行コード (ロジック) とストレージ スペース (ストレージ) が単一のアドレスに関連付けられています。プロキシ コントラクトは、システムを、プロキシ コントラクト (状態を保持する) とロジック コントラクト (実行可能コードを保持する) という 2 つの独立しているが密接に相互作用するコンポーネントに分離することで、この構造を打ち破ります。
このモデルでは、ユーザーとフロントエンド アプリケーションの固定アドレスを維持できる一方、プロキシのメモリ内の論理コントラクトを指すアドレスを変更することで、基礎となるビジネス ロジックを置き換えることができます。これにより、本質的に不変のインフラストラクチャに「変動性の幻想」が生じます。
1.1 プロキシ アーキテクチャにおけるコンポーネントの役割
このアーキテクチャでは、プロキシ コントラクトが単一の連絡先として機能します。すべての資産、イーサ残高、および所有権やユーザー残高などの重要な状態変数は、プロキシのアドレスに永続的に保存されます。対照的に、ロジック コントラクト (実装コントラクトとも呼ばれる) には、データの処理方法に関する指示のみが含まれています。
主なコンポーネントには次のものがあります。
プロキシ コントラクト: データ ストレージ、トークン残高、実装アドレス、および管理権限。不変のアドレス プロパティを持ちますが、内部データは変更できます。
ロジック (実装): ビジネス関数 (転送、ミント、スワップなど) のソース コードが含まれています。新しいバージョンに置き換えることができます。
ProxyAdmin: 管理契約またはウォレットにはアップグレードを実行する権利があり、システム全体を変更する機能の制御に役立ちます。
この分離により、システムのメンテナンスに大きなメリットがもたらされます。ビジネス ロジックでセキュリティの脆弱性が発見された場合、開発者は、何千人ものユーザーにアセットをまったく新しいアドレスに移動するよう依頼する代わりに、新しい固定ロジック コントラクトを展開してプロキシ内のアドレスを更新するだけです。
関連項目: スマート コントラクトとは何ですか?
2. DELEGATECALL メカニズム: アップグレードのエンジン
プロキシ コントラクトの動作を可能にする技術的基盤は、イーサリアム ネットワークの EIP-7 で導入されたオペコード delegatecall です。これは、コントラクトが別のアドレスから実行可能コードをフェッチしながら、独自の「コンテキスト」で実行できるようにする特別な呼び出しです。
2.1 EVM 実行でのコンテキストの保持
プロキシ コントラクトがロジック コントラクトに対して delegatecall を実行すると、トランザクションの環境変数はそのまま保持されます。これは、Logic コントラクト内では、プロキシを直接呼び出す場合と比較して、次の値が変更されないことを意味します。
msg.sender: プロキシのアドレスではなく、元のユーザーのアドレスのままです。msg.value: トランザクションに含まれる Ether の量が保持されます。 resource.storage: すべての読み取り (SLOAD) と書き込み (SSTORE) は、論理コントラクトではなく、プロキシのストレージ スペースに直接作用します。
通常の呼び出し (CALL) と DELEGATECALL の違いは、セキュリティと機能にとって非常に重要です。システム機能。 CALL コマンドでは、ターゲット コントラクトは独自のメモリ上で動作し、msg.sender を呼び出し側コントラクトとして認識します。 DELEGATECALL では、ターゲット コントラクトはプロキシ サーバーにロードされたロジック ライブラリとして機能します。
2.2 フォールバック関数による実行フローの分析
プロキシ コントラクトは通常、競合を回避するビジネス関数を定義しないため、fallback 関数を使用して不明な呼び出しを受信します。ユーザーがプロキシ上で transfer(address,uint256) 関数を呼び出すと、プロキシにはこの関数がないため、Ethereum 仮想マシン (EVM) は fallback 関数をトリガーします。ここで、低レベルのアセンブリ コードが実行されて呼び出しが承認されます。
技術的なプロセスは次のとおりです。
calldatacopyを使用して、トランザクションの入力データ全体をメモリにコピーします。指定された保存場所から現在の論理コントラクトのアドレスを取得します。
コマンドを実行します。
delegatecallは利用可能なすべてのガスを使用して、コピーされたデータを渡します。ロジック コントラクトの実行が完了すると、結果が返され、
returndatacopyを使用して出力データがコピーされます。プロキシは結果を元のユーザーに返し、委任サイクルを透過的に完了します。
3.メモリ アーキテクチャと EIP-1967 標準
プロキシ パターンの最大の課題の 1 つは、メモリ衝突 (ストレージ衝突) の管理です。プロキシと実装は両方とも同じプロキシのストレージ領域を共有するため、両方が同じメモリ「スロット」を異なる目的に使用しようとすると、惨事が発生します。
3.1 メモリ衝突のリスク
Solidity では、状態変数は宣言順に 32 バイトのスロットに配置されます。プロキシが論理アドレスを格納するためにスロット 0 で変数 address _implementation を宣言するとします。ロジック コントラクトが変数 uint256 _balance をスロット 0 でも宣言している場合、ロジック関数が残高を更新するたびに、プロキシ内の自身のアドレスを誤って上書きしてしまいます。これにより、攻撃者がそのスロットに書き込まれる値を操作できる場合、コントラクトが乗っ取られることになります。
3.2 非構造化ストレージと EIP-1967 ソリューション
衝突を防ぐために、EIP-1967 標準が確立されました。この標準では、識別子文字列をハッシュすることでプロキシ管理変数の特別な格納場所を定義します。

ハッシュ後に 1 を減算すると、このスロットは Solidity の動的配列またはマッピングの通常のハッシュでは作成できなくなり、衝突の可能性が突然低下することが最小限に抑えられます。
詳細はこちら: スマート コントラクト監査とは何ですか?
4.一般的なプロキシ モデルとトレードオフ分析
4.1 透過的プロキシ パターン (TPP)
このモデルは、「関数識別子の衝突」問題を解決することを目的としています。 TPP のメカニズムは呼び出し元の分散化に基づいています。呼び出し元が管理者の場合、プロキシは自身の管理機能のみを呼び出します。呼び出し元が管理者ではない場合、プロキシは常に呼び出しを実装に転送します。
4.2 Universal Upgradeable Proxy Standard (UUPS) - EIP-1822
UUPS は、アップグレード ロジックをプロキシから実装コントラクト自体に移動することにより、TPP よりも優れたパフォーマンスを発揮します。プロキシは非常に合理化され、プロキシで管理者を確認する必要がなくなるため、ガスの節約に役立ちます。ただし、アップグレード ロジックのない新しいバージョンにアップグレードすると、コントラクトは永久にロックされます。
4.3 ビーコン プロキシ
一連の同一のコントラクトをデプロイする必要があるプロジェクト向けに設計されています。プロキシは、共通の実装アドレスを保持する「ビーコン」と呼ばれる中間コントラクトを指します。 Beacon が更新されると、依存するすべてのプロキシが同時にアップグレードされます。
4.4 Diamond Standard (EIP-2535)
Diamond Standard では、1 つのプロキシ コントラクトを多くの異なる実装コントラクト (ファセット) に接続できます。これにより、ロジックを分割し、各部分を個別にアップグレードできるようにすることで、24 KB のコントラクト サイズ制限に対処します。
5.セキュリティ リスクとユーザーの欺瞞メカニズム
Tan Phat Digital の観察によると、ブロック エクスプローラーで変更されていない契約アドレスや検証済みのソース コードを見たときに、ユーザーは誤った安心感に騙されることがよくあります。
5.1 管理と集中化のリスク
最大のリスクは、管理者の絶対的な制御です。管理キーが侵害された場合、攻撃者は悪意のあるソース コードに対して「フラッシュ アップグレード」を実行して資金を引き出し、古いバージョンにアップグレードして痕跡を消去する可能性があります。
5.2 初期化エラー (初期化されていないプロキシの脆弱性)
プロキシは constructor を使用できないため、開発者は initialize 関数を使用します。管理者がこの関数を呼び出すのを忘れたり、保護しなかった場合、攻撃者が自分自身を呼び出して管理者権限を乗っ取る可能性があります。 500,000 ETH 以上を凍結した 2017 年のパリティ ウォレット ハッキングは、このバグの痛ましい歴史的な例です。
5.3 メモリの競合と Audius のクラッシュ
2022 年の Audius プロトコル ハッキングは、メモリ スロット エラーの例です。
アップグレード前: スロット 0 には初期状態が保存されます。 (
初期化 = true)。コントラクトは正常に動作します。アップグレード後: 開発者は変数
proxyAdminをプロキシに追加し、誤ってスロット 0 と重複します。エクスプロイト: 管理者のアドレス値により、システムは初期化されていないと誤解します。ハッカーは再び
initialize関数を呼び出し、所有権を取得します。被害: ハッカーはコミュニティ基金から 600 万米ドルのトークンを送金します。
5.4 隠蔽および偽装テクニック
詐欺師はよく safeWithdraw() などの危険な関数の名前を付けますが、実際には資金を排出する機能。また、悪意のある「バックドア」を含む実装のソース コードを隠しながら、プロキシのソース コード (非常に短く無害) のみを検証することもできます。
6.典型的なラグ プル プロキシ ケースの分析 (2024 ~ 2025 年)
6.1 LIBRA ケースとラグ プルの進化
2025 年の LIBRA プロジェクトでは、検出を回避するために「断片化されたラグ プル」戦術が使用されました。詐欺師は、1 回の大規模な引き出しの代わりに、プロキシを使用して引き出しを一連のサテライト ウォレットに分配し、監視システムの警告しきい値を下回る数千件の小規模な取引を実行します。その後、証拠を消去するための selfdestruct コマンドを含むコントラクトにプロキシをアップグレードしました。
6.2 Kinto Finance と低レベル プロキシの脆弱性
2025 年 7 月、Kinto Finance はプロキシ管理メカニズムのバグを通じて攻撃されました。攻撃者はアップグレード権を乗っ取り、すぐにさらに 110,000 個の未承認トークンを鋳造し、流動性プールから 155 万米ドルを引き出しました。
7.ユーザー向けのテストと検証プロセス
資産を保護するために、Tan Phat Digital はユーザーが次の手順を実行することをお勧めします。
プロキシの検証機能を確認する: Etherscan に「プロキシとして読み取り」タブが表示されるかどうかを確認します。
アップグレード履歴を監視する: 契約が予告なしに頻繁にアップグレードされる場合、危険信号です。危険です。
管理者権限を確認する: 管理者アドレスはマルチシグネチャ ウォレット (マルチシグ) であるか、重要な変更を遅らせるタイムロック メカニズムを備えている必要があります。
サポート ツールを使用する: GoPlus Security や TokenSniffer などのプラットフォームを利用して、ハニーポットや異常な Mint トークンの兆候をスキャンします。権利。
8.開発者のための防御戦略
開発者は OpenZeppelin 標準ライブラリを使用し、メモリ領域を確保するために常に「ストレージ ギャップ」テクニック (空の配列 uint256 private __gap; を作成する) を適用する必要があります。実装における変更は、展開前に Hardhat Upgrades Plugin などの自動ツールを使用してメモリ レイアウトの互換性をテストする必要があります。
9.よくある質問 (FAQ)
新しい契約を展開する代わりにプロキシ コントラクトを使用する理由は何ですか? プロキシを使用すると、ユーザーと統合アプリケーションに対して単一の固定契約アドレスを維持することができ、コストのかかるデータ移行 (移行) が回避され、更新またはバグ修正があるたびにユーザーが新しいアドレスに移動する必要が生じます。
CALL コマンドと DELEGATECALL コマンドの主な違いは何ですか?
CALLコマンドでは、ターゲット コントラクトが独自のメモリ上で実行されます。対照的に、DELEGATECALLはターゲット コントラクトのコードをロードしますが、呼び出し側コントラクトの「コンテキスト」で実行されます。つまり、メモリを使用し、バランスをとり、呼び出し側コントラクトのmsg.senderを保持します。透過的プロキシはなぜ UUPS より多くのガスを消費するのですか?透過的プロキシでは、呼び出しの方向 (管理者またはロジック) を決定するために、トランザクションごとに呼び出し元が管理者であるかどうかを確認する必要があります。アップグレード ロジックは実装契約に直接含まれるため、UUPS ではプロキシでのこのチェックが不要になります。
プロキシを使用してプロジェクトを識別するにはどうすればよいですか? Etherscan では、ユーザーは「これはプロキシですか?」ボタンを見つけることができます。または「プロキシとして読み取り」/「プロキシとして書き込み」タブ。そうであれば、それは間違いなく認可契約です。
ストレージ ギャップとは何ですか? これは、基本コントラクトに空の配列 (例:
uint256 private __gap;) を配置して、将来の新しい変数用のストレージ スペースを予約し、レガシー コントラクトのメモリ位置の押し合いを防ぐ手法です。プロキシを初期化しない場合のリスクは何ですか?
initialize関数が展開直後に呼び出されない場合、攻撃者は自分自身でこの関数を呼び出してコントラクトの所有者となり、完全な制御を取得する可能性があります。プロキシはなぜコンストラクタを使用できないのですか? 実際のユーザー状態はプロキシのアドレスにあるのに対し、
constructor内のコードはデプロイ時にロジック コントラクトのアドレスで 1 回しか実行されないからです。関数セレクターの衝突とは何ですか? これは、2 つの関数の名前は異なるものの、同じ 4 バイトの識別子を持つ現象です。ハッカーはこれを利用して、ユーザーを騙してビジネス機能を呼び出すように仕向けますが、実際には危険な管理機能をアクティブにする可能性があります。
プロキシのアップグレードが安全であることを確認するにはどうすればよいですか? プロジェクトでは、コミュニティが新しいソース コードを有効にする前にテストする時間を確保できるように、タイムロック メカニズム (実行時間の遅延) と組み合わせたマルチシグネチャ ウォレット (マルチシグ) を使用する必要があります。
プロキシのアップグレードは無効にできますか? はい。開発者は、アップグレード ロジックが含まれていない実装にアップグレードすることも、管理者の権利放棄を使用してプロキシを永続的に不変の契約にすることもできます。
ビーコン プロキシは通常のプロキシとどのように異なりますか? 各プロキシは論理アドレスを保存する代わりに、中間コントラクト (ビーコン) を指します。ビーコンを更新すると、単一のトランザクションで数千の依存プロキシが同時にアップグレードされます。
ProxyAdmin コントラクトの役割は何ですか? OpenZeppelin の透過的プロキシ モデルでは、
ProxyAdminはプロキシの所有権を取得する中間コントラクトであり、通常のユーザー操作とは別にアップグレードを安全に管理するのに役立ちます。プロキシのバックドアを検出するにはどうすればよいですか? ユーザーは、実装ソース コードが検証されているかどうかを確認し、Slither などのツールを使用して、資金を引き出したりトランザクションをブロックしたりできる
onlyOwner権限を持つ関数をスキャンする必要があります。フラッシュ アップグレード攻撃とは何ですか? これは、ハッカーがプロキシを悪意のあるコードにアップグレードして金銭を盗み、その後、たった 1 回のトランザクションですぐに古いバージョンにアップグレードしてオンチェーンの痕跡を消去する攻撃手法です。
最も安全な方法でプロキシを初期化するにはどうすればよいですか? 開発者はアトミック初期化プロセスを使用する必要があります。つまり、ハッカーによる「選択」を避けるために、プロキシのデプロイと
initialize関数の呼び出しが同じトランザクション内で行われます。
プロキシ コントラクトは、ブロックチェーン エコシステムの開発にとって避けられない技術的ソリューションです。ただし、この柔軟性は、透過的に管理しない場合にはリスクももたらします。 Tan Phat Digital は、ガバナンスの透明性とユーザーの慎重さが、不安定な Web3 の世界でコミュニティが目指すべき真の「不変性」であると信じています。
シェア








