
巧妙なコントラクト設計:stETHはどのようにして毎日自動でリターンを分配しているのか?
TechFlow厳選深潮セレクト

巧妙なコントラクト設計:stETHはどのようにして毎日自動でリターンを分配しているのか?
アカウントは取引を一切行っていないにもかかわらず、stETHの数量が増加している。
執筆:ZAN Team
筆者がわずかなETHをstETHに交換したところ、stETHの保有量が日々自然に増加し、収益が継続的に得られていることに気づきました。しかし、アカウントの取引履歴を確認しても、そのような収益の振込に関するトランザクションは一切見当たりません。なぜでしょうか?本稿では、その巧妙な仕組みについて詳しく解説し、収益付与の秘密を明らかにしていきます。

数日後、1つのstETHにはすでに一定の収益が発生している
その前に、stETHが収益を得る背景にあるロジック、つまりイーサリアムのステーキング(Staking)について簡単に紹介します。この部分の概念をすでに理解されている読者は、後半まで飛ばしてお読みください。

初期のイーサリアムはビットコインと同様に、作業証明(Proof of Work、PoW)をコンセンサスメカニズムとしていました。しかし、電力消費やセキュリティ・パフォーマンス面での課題などを考慮し、イーサリアムは2022年9月からプルーフ・オブ・ステーク(Proof of Stake、PoS)へと移行しました。
もともとマイナーたちが計算能力で採掘を行い、コンセンサスを実現していたイーサリアムは、ステーキングによりETHを預けることで投票権を得る方式へと変わりました。ユーザーはこの投票によって報酬を得ることができ、結果としてPoSによるコンセンサス形成が促進されます。
32ETHをステーキングすることで、イーサリアムネットワークに参加し、検証者(バリデータ)になることができます。検証者はデータの保存、トランザクション処理、およびブロックチェーンへの新規ブロック追加を担います。正しくトランザクションを新しいブロックにパッケージングし、他の検証者の作業を検証するだけで、ETHの報酬を受け取ることができます。これにより、ETHをステーキングすることで比較的安定したリターンを得られるようになります。
しかし、このようなステーキングは一般のユーザーにとっては依然としてハードルが高いです。32ETHという高額な資金だけでなく、24時間365日イーサリアムネットワークに接続された専用のコンピュータも必要です。また、ステーキングされたETHは流動性を失ってしまいます。そこで登場したのが「流動性ステーキングデリバティブ(Liquid Staking Derivatives、LSD)」です。これは従来のステーキングにおける参入障壁と流動性の問題を解決するために設計されており、32ETH未満の単位でもステーキングが可能になります。また、自前でノードを持つ必要はなく、ETHを第三者に委託してステーキングを行い、その見返りにstETH(Lidoのもの)やrETH(Rocket Poolのもの)などの流動性トークンを受け取ります。これらのトークンは他のプラットフォーム上で売買・貸出・金融活動などに利用でき、ユーザーは手軽にステーキング報酬を得つつ、資産の柔軟性を維持できます。

つまり、stETHの本質的な仕組みは、ユーザーがETHをLidoに預け、LidoがそのETHを使ってイーサリアムのPoSに参加し報酬を得ること、そしてユーザーはその対価としてstETHという証明書を受け取ることです。次に、Lidoはこの報酬をstETHを保有する各アドレスに対して分配していく必要があります。
実際にstETHの収益は毎日自動的に更新されています。下図はテストで確認した収益の変化であり、暗号資産ウォレットで日々確認可能です。

ここで、スマートコントラクト開発に詳しい方であれば疑問に思うでしょう。「毎日ごくわずかな収益を配布する場合、そのGas代すら報酬を上回ってしまう可能性があるのではないか?」
確かに、Lidoが最もシンプルな方法で収益を配布しようとすれば、Gasコストをまかなうのは難しいでしょう。直感的には、膨大な数のアドレスに対してトークンを送金するためのGasは想像を絶する額になります。
しかし実際には、Lidoはウォレット内のstETH残高が自動的に増加する仕組みを実現しており、しかもそのアドレスに新たな取引が発生していないことも確認できます。一体どのように実現しているのでしょうか?
私たちはLidoのコントラクト https://etherscan.io/token/0xae7ab96520de3a18e5e111b5eaab095312d7fe84 を調査し、balanceOf メソッドに注目しました。

balanceOf はERC20規格に準拠したメソッドであり、ウォレットアプリはこの関数を通じてユーザーの保有トークン数を取得しています。
stETHのコントラクトでは、この balanceOf 内で getPooledEthByShares メソッドを呼び出していることがわかります。このメソッドの引数は mapping (address => uint256) private shares; であり、ユーザーが保有するstETHの「株式数(シェア)」を示しています。しかし、これがそのままstETHの数量を表しているわけではありません。そうでなければ、毎日すべてのアドレスのデータを更新しなければならず、たとえ一度のトランザクションで全アドレスを更新できるとしても、Gasの消費は非常に大きくなってしまいます。
ここまでの説明で、もうお気づきの方も多いかもしれません。続いて getPooledEthByShares メソッドを見てみましょう。

最終的な戻り値は、「sharesAmount × _getTotalPooledEther() ÷ _getTotalShares」という計算式で求められています。
_getTotalPooledEther は総stETH数(stETHとETHの交換レートが1:1の場合、総ETH数とも一致)を、_getTotalShares は総シェア数を表します。つまり、各アドレスのstETH保有量は、この式によって動的に算出されるのです。
たとえば、現在の総シェア数が1000(_getTotalShares の戻り値)で、Aアドレスが100のシェア(sharesAmount)を持っているとします。この1000シェアは1000stETH(_getTotalPooledEther の戻り値)に相当すると仮定します。このとき、AアドレスのstETH保有量は 100 × 1000 / 1000 = 100 stETHとなります。その後、Lidoが1000ETHをステーキングして1ETHの報酬を得た場合、_getTotalPooledEther は1001に更新されます。つまり、合計stETH数が1001に増えたことになります。すると、Aアドレスの保有量は 100 × 1001 / 1000 = 100.1 stETH と計算されます。
つまり、各アドレスの「株式数(シェア)」は変わらず、その1株あたりの価値が上がる(= stETHの価値が上がる)ことで、結果として保有量が増えるという仕組みです。
コードをさらに追ってみましょう。_getTotalPooledEther の値は handleOracleReport メソッドの実行によって更新されます。このメソッドは定期的に外部から呼び出され、コントラクト内のデータを更新します。具体的には、https://etherscan.io/address/0x852deD011285fe67063a08005c71a85690503Cee のコントラクトが submitReportData を呼び出し、それが内部で Lido コントラクトの handleOracleReport を実行しています。

毎日のようにこの submitReportData が呼び出されていることが確認できます。これが、私たちのアドレスに取引履歴がなくても、stETHの残高が日々変化している理由です。
この仕組みは、イーサリアムのERC20スマートコントラクトの特徴をよく表しています。ERC20トークンの保有数はアドレスに直接書き込まれているわけではなく、コントラクトのメソッドが動的に計算して返す値であるため、取引履歴がなくても保有量が変化することがあります。これはERC20コントラクトの柔軟性を高める一方で、コントラクトの仕組みに不慣れなユーザーにとっては混乱のもとにもなります。本稿が、皆さんのスマートコントラクト理解の一助となり、より安全なインタラクションにつながれば幸いです。
なお、ETHをstETHにステーキングすることで一見安定した収益が得られるように見えますが、リスクも存在することに注意が必要です。本稿はあくまで技術的な研究の一環であり、投資勧誘を目的としたものではありません。
TechFlow公式コミュニティへようこそ
Telegram購読グループ:https://t.me/TechFlowDaily
Twitter公式アカウント:https://x.com/TechFlowPost
Twitter英語アカウント:https://x.com/BlockFlow_News














