アーキテクチャ
プロトコルは2つのチェーン上に存在します。Ethereumにはローンチパッド、プール、ボールトが、Robinhood Chainにはトークン化株式があります。
コントラクト
この表は、プロトコルを決定された姿のまま記述しています。ローンチの部分は2026-09-28以降、エアドロップの分配は2026-10-04以降コードに実装されていますが、デプロイはされていません。株式のLayerZeroアダプターはリポジトリにありません。公式のスワップルーター以外のルーターとアダプターは、表に含めていません。Ethereum上のUniswapV4StockRouter、Robinhood Chain上のRobinhoodStockRouter、そしてUsdgOftAdapterです。進捗状況を参照してください。2026-10-02以降、この表のすべてのコントラクトは、トークン、流動性のロック、デプロイヤーを除いてアップグレード可能です。以下を参照してください。図中のパーセンテージは、タックスのデフォルトの設定です。
| コントラクト | 役割 | 個数 |
|---|---|---|
StockFunFactory |
マーケットを作成し、作成手数料を徴収し、レジストリと、新しいマーケットおよびボールトに関するオーナーの設定を保持する。Ethereumのすべてのモジュールのアップグレード権限の管理元 | 1つ |
MarketDeployer · VaultDeployer |
トークンの作成コードとボールトのプロキシの作成コードを保持することでEIP-170の制限を回避する。状態を持たず、アップグレードではなくファクトリーを通じて置き換えられる | 各1つ |
StockFunToken |
アップグレードできない単純なERC-20。ミントもバーンもない。プロトコルオーナー用の1つのsetterであるsetRecorderとレスキューを除いて、独自のロジックを持たない。すべての残高の変化を保有量レコーダーに報告する |
マーケットごとに1つ |
HoldingRecorder |
すべてのトークンについて、各アドレスの保有量と、UniswapのPoolManagerの外にある供給量を、時系列で記録する。記録が失敗すればその転送も失敗し、これは後述の分離のルールに対する唯一の意図的な例外である |
1つ |
TreasuryVault |
ETH、USDC、次いで株式を保有する。変換(購入のレッグは個別に実行)、ローカルのレールでの株式のエアドロップへの引き渡し(sendToAirdrop。株式ごとに個別)、即時の緊急リカバリー |
マーケットごとに1つのプロキシ |
LiquidityLock |
プールを作成し、両方のポジションを預け入れてロックし、各プールのLP手数料とティック間隔を保持する。手数料の回収のうち拒否された取り分を、その受取人のために保持する。アップグレードできない。唯一の出口は、告知から30日後の終了モード | 1つ |
StockFunHook |
すべてのスワップで手数料を徴収し、アンチスナイプを適用し、タックスの設定と各プールのホワイトリストを管理し、ロック以外からの流動性を拒否し、クリエイター、チーム、バイバックの残高を請求されるまで保持し、自身の取り分を拒否したボールトへの未払い分も保持する | 1つ |
StockFunSwapRouter |
取引用の公式ルーター。ホワイトリスト登録アドレスがアンチスナイプを免除される唯一のルーター | 1つ。オーナーが置き換え可能 |
StockFunLens |
読み取り専用。各ボールトを個別に読み取り、dapp向けにマーケットの状態を集約する。2026-10-06以降、そのページには、ボールトのレール、一時停止状態、ブリッジで送ったUSDC、プールのロック状態、トークンの保有量レコーダー、そしてフックとロックがボールトに対して負っている額も含まれる | 1つ |
TreasuryOracle |
Chainlinkフィード。一度だけ書き込まれ、設定であるのはそのハートビートと、2026-10-06以降はRobinhood Chain上の2つのガード:Chainlinkがそのチェーンのアップタイムフィードを公開するまではオフのシーケンサーのチェックと、コーポレートアクションの間その株式の価格を差し止める、各株式のオラクル一時停止チェック | チェーンごとに1つ |
BuybackBurner |
$STOCKFUNを購入してバーンアドレスへ送る。$STOCKFUNのプールがロックされている間は、他の経路は存在しない |
1つ |
BridgeHub · RemoteHub · RemoteTreasuryVault |
クロスチェーンのレール。リモートハブはRobinhood Chain上のアップグレード権限の管理元であり、エアドロップの経路と各株式のアダプターを指定する。ミラーボールトは自身の株式をエアドロップへ送る(sendToAirdrop) |
1つ、1つ、マーケットごとに1つのプロキシ |
StockFunProtocolToken |
マーケットのトークンと同じくアップグレードできない$STOCKFUN。その供給量の全量はロックされたポジションに入る |
1つ |
AirdropDistributor |
各トレジャリーが購入した株式を、Ethereum上で、日次サイクルごとにそのトークンのホルダーに分配する。計上するのはマーケット自身のボールトからの送付だけ。各ホルダーが請求し、請求は支払えるすべての株式を支払う。ファクトリーに結び付けられ、ファクトリーがこれを指定する | 1つ |
プロキシとアップグレード
2026-10-02以降、すべてのモジュールは、実装の前に置かれたERC-1967のプロキシであり、UUPSによってアップグレードされます。プロキシはアドレスと状態を保持し、実装はコードを保持します。アップグレードは実装を置き換えます。実装が初期化されることは決してありません。各プロキシは、自身のコンストラクタの中で初期化されます。
各モジュールは、誰が自分をアップグレードできるかを、単一のコントラクト、つまりアップグレード権限の管理元に問い合わせます。管理元は実装の中に固定されています。Ethereumではファクトリーで、ファクトリーは自身のオーナーを返します。Robinhood Chainではリモートハブで、リモートハブは自身の緊急管理者、つまり直近のブリッジバッチが運んできたEthereumのオーナーを返します。したがって、ファクトリーの所有権を移転すると、Ethereumのすべてのモジュールのアップグレード権限が一度に移り、Robinhood Chainのモジュールのアップグレード権限も次のバッチとともに移ります。新しい実装が別の管理元を指定している場合、アップグレードは拒否されます。フックと保有量レコーダーの新しい実装は、同じPoolManagerも維持しなければなりません。
アップグレードできないもの:トークン、流動性のロック、そしてRobinhood Chain上のミラーボールトのデプロイヤーです。すべてのミラーボールトのアドレスは、このデプロイヤーのアドレスから導出されます。MarketDeployerとVaultDeployerは状態を持ちません。ファクトリーは、これらをアップグレードするのではなく、置き換えます(setDeployers)。
ストレージは追加されるだけで、並べ替えられることはありません。各モジュールのレイアウトはcontracts/storage-layouts/に記録されており、アップグレードの前には毎回、contracts/script/check-storage-layouts.shがそれを比較します。2026-10-05以降、このスクリプトは、すべての構造体をサイズも含めてあらゆる深さで比較し、ストレージ配列の要素である構造体への変更はすべて拒否します。拡張できるのは、マッピングの値である構造体か最後の状態変数だけで、それもその末尾に限られます。
実装コントラクトが直接使われることは決してありませんが、誤ってそのアドレスに送られたものにも、レバーがあります。ほとんどの実装は自身の権限の管理元をイミュータブルから読み取るため、プロトコルオーナーがそれを取り出します。ファクトリーとリモートハブの実装は管理者をプロキシのストレージに保持するため、それらの実装でのレバーは、それらをデプロイしたアドレスです。
誰がアップグレードでき、それがどれだけ速く発効するのかについては、信頼モデルを参照してください。
エアドロップのコントラクト
2026-10-04以降、AirdropDistributorが各トレジャリーの株式をEthereum上で分配します。これは他と同様にアップグレード可能なモジュールであり、アップグレード権限の管理元がファクトリーであるプロキシです。ファクトリーがこれを指定し(setAirdropDistributor)、ボールトはそれをその都度読み取ります。置き換えられた分配コントラクトでも、すべてのサイクルはそのコントラクト上で請求可能なままです。保有量は保有量レコーダーから読み取り、そのルールはエアドロップに記載されています。
そこへ届く経路は2つで、それ以外にサイクルに計上されるものはありません。
- ブリッジのレール。ミラーボールトの
sendToAirdropは、リストに載った各株式を、リモートハブが指定するその株式のLayerZeroアダプター(setStockAdapter)を通じて、リモートハブが指定する分配コントラクト(setAirdrop)へ、マーケットのIDをペイロードとして送ります。Ethereum上では、その株式のOFTがラップされた株式を分配コントラクトにミントし、LayerZeroのエンドポイントが分配コントラクトを呼び出します。分配コントラクトがその配信を計上するのは、オーナーが登録した株式のOFTから、Robinhood Chainから来たもので、ブリッジハブがそのマーケットについて導出するミラーボールトによって送られた場合だけです。 - ローカルのレール。Ethereumのボールトの
sendToAirdropは正確な金額を承認し、分配コントラクトがマーケット自身のボールトからのみそれを引き取って、受け取った分を計上します。承認は再び閉じられます。ブリッジハブに接続されたボールトは、この呼び出しを拒否します。
キーパーは両方をトリガーし、決めるのはタイミングだけです。ブリッジのレールでは、2026-10-06以降、各配信がEthereum上で受け取るガスも決めます。リモートハブは、そのガスを、StockFunのオーナーがそこで設定する範囲内に保ちます。
構造上の特性
フックはシングルトンです。1つのコントラクトがすべてのプールに対応するため、マーケットごとにアドレスをマイニングする必要がありません。v4のフックのアドレスは下位ビットに権限をエンコードしており、それを見つけるには計算コストがかかるからです。2026-10-02以降、フックは、そのアドレスがv4の14の権限すべてを備えたプロキシです。アップグレードしてもそのアドレスは変わらず、今後の実装はどのコールバックでも使用できます。
流動性はNFTではありません。流動性はPoolManager内に直接保持され、ロックのアドレスをキーとして管理されます。移転できるポジションも、取り消すべきapproveも、失う可能性のあるtokenIdもありません。コントラクトが実行できる流動性操作は、手数料を回収するための、デルタがちょうどゼロのmodifyLiquidityと、終了モードを通じて、終了の告知から30日後にプールのすべてのポジションを取り除くことだけです。
流動性を追加するのはロックだけです。2026-10-01以降、フックはStockFunのプール上のそれ以外のポジションをすべて拒否するため、すべての取引はロックされたポジションを相手とするスワップとなり、タックスを支払います。
ボールトには引き出し機能がありません。ボールトの資産を、誰かが自分の選んだアドレスへ送れるような関数は存在しません。出口は2つです。唯一の行き先がプロトコルの指定するエアドロップのコントラクトであり、そのコントラクトが誰も選ぶことのないルールのもとでトークンのホルダーへ比例配分で支払うエアドロップと、StockFunのオーナーが資産を任意のアドレスへただちに移動させる緊急モードです。これらは現在の実装のルールです。StockFunのオーナーは、ボールトを即時発効でアップグレードできます。
許容幅は設定であり、フィードは設定ではありません。ボールトの価格許容幅(デフォルトで50と200ベーシスポイント)はStockFunのオーナーの設定で、すべてのボールトがその都度読み取ります。キーパーにできるのは、それを狭めることだけです。フィードのレジストリは各フィードを一度だけ書き込みます。フィードのハートビートは設定であり、2026-10-06以降は、価格を差し止めることしかできず、決して変更することのない、レジストリの2つのガードも設定です。シーケンサーのチェック(Chainlinkがアップタイムフィードを公開するまで、Robinhood Chain上ではオフ)と、各株式のオラクル一時停止チェック(Robinhood Chainのすべての株式でオン。Robinhoodレールを参照してください)です。緊急モードはどちらにも触れません。緊急モードは資産を移動させるものであり、約定のルールを変更するものではありません。レジストリは、ボールトと同様に、StockFunのオーナーがアップグレードできます。
分離とレバー
2026-10-05、ファウンダーは1つの設計ルールを定めました。何かが1つの機能を失敗させても、他の機能がその代償を払ってはならない。すべてが動き続けられなければならず、すべてが、失われた資金を取り戻し、修正を受け入れるためのレバーを持たなければならない、というものです。同日の4回目の監査ループがこれをコードに組み込み、それ以降、監査ループは、その2つの部分のいずれかへの違反を欠陥として数えます。
分離。1つの機能、マーケット、株式、サイクル、記録、受取人での失敗が、他をブロックすることは決してありません。その項目は、イベントとともに、スキップされるか、未払い分として保持されるか、繰り延べられ、残りは先へ進みます。
- ブリッジバッチは、ボールトが資金を払い出せないマーケットを外し(
MarketSkipped)、他のマーケットはブリッジを渡ります。キャッシュレッグのトークンが1つのミラーボールトへの受け渡しを拒否した配信は、そのマーケットへの未払い分としてリモートハブにとどまり(DeliveryRefused)、他のマーケットには支払われます - 購入は各株式のレッグを個別に実行し(
LegFailed)、エアドロップへの送付は各株式を個別に送ります(AirdropSendFailed) - 請求は支払えるすべての株式を支払い、残りを繰り延べます(
ClaimDeferred) - ETHを拒否するボールトが、そのマーケットの取引を止めることはもうありません。フックは支払えなかった分をそのボールトへの未払い分として保持し(
treasuryOwed)、ロックは手数料の回収のうち拒否された取り分を、その受取人のために保持します(vaultOwed、creatorOwed)。受取人が再びETHを受け取るようになれば、誰でもそれらを支払うことができ(payTreasury、payOwed)、キーパーは毎サイクルそうします - Lensは各ボールトを個別の呼び出しで読み取るため、応答できないボールトがあっても、他のボールトは読み取れるままです(
vaultReadable)。2026-10-06以降、その呼び出しはボールトのレール、一時停止状態、ブリッジで送ったUSDCも返し、ページはフックとロックがボールトに対して負っている額も返します。アプリのデータサービスはマーケットごとにそれ以外の何も読み取らないため、ガスを使い果たすボールトがあっても、失敗するのはそのボールト自身の数値だけです。7回目の監査ループ以降、データサービスは、アップグレード可能な各モジュール(フック、オラクル、エアドロップのコントラクト、2つのハブ)とプロトコルトークンも、それぞれ独立したグループで読み取ります。そのため、欠陥のあるアップグレードの後でガスを使い果たすモジュールがあっても、失敗するのはそのモジュール自身の数値だけです
レバー。一時的にであれ誤ってであれ、ETHやトークンを保有しうるすべてのコントラクトには、滞留したものを取り出すためのレバーがあり、すべてのモジュールは修正を受け入れることができます。アップグレード、またはモジュールを差し替えるsetterです。
- トランザクションとトランザクションの間に誰のものも保持しないモジュール(ファクトリー、Lens、オラクル、保有量レコーダー、株式ルーター、公式のスワップルーター、ブリッジアダプター)には、プロトコルオーナーの
rescue(asset, amount, to)があります - 独自の帳簿を持つモジュール(ボールト、2つのハブ、エアドロップのコントラクト)には、緊急モードがあります
- フックの
rescueが取り出すのは、誤って送られたものだけで、フックが負っているものは決して取り出しません。ロックのレスキューは、ロックが保持している取り分も、終了モードしか届かないポジションも、決して取り出しません。BuybackBurnerのレスキューがそのETHを取り出すのは、もはやどのバーンもそれを使えなくなった後だけです。アップグレードできないトークンは、自身のアドレスに送られたものを取り出すことができます - 設計上、レバーを持たないもの:Ethereum上の2つのデプロイヤーとミラーボールトのデプロイヤーです。これらは状態を持たず、ETHを受け付けず、オーナーもいません
詳細は緊急モードにあります。
唯一の意図的な例外。トークンから保有量レコーダーへの報告は、ブロックするままです。報告が失敗すれば、転送も失敗します。失敗してもよい報告にすると、ホルダーは自分の転送でその報告のガスを枯渇させることができ、そうすると記録はその動きを飛ばし、そのホルダーのエアドロップの取り分が増えてしまいます。レバーは即時で、それぞれ1トランザクションで済みます。トークンの記録を止める、トークンでのsetRecorder(0)か、レコーダーのその場でのアップグレードです。エアドロップを参照してください。
オフチェーンのパッケージ
| パッケージ | 役割 |
|---|---|
shared/ |
生成されたABI、プロトコルの定数、フォーマット処理。他のすべてが共有する単一のソース |
backend/ |
価格サービス。dappの唯一の外部依存を切り離す |
keeper/ |
変換、ブリッジバッチ、リモート側のルーティング、配信の監視、そして2026-10-05以降は、エアドロップのステップ、フックとロックが受取人のために保持している分の支払い、LP手数料の回収 |
cairn-app/ |
アプリ。Next.jsのフロントエンドで、React + Viteのdappを置き換えた2026-10-02以降、projet/の隣にある。dappを参照 |
cairn-worker/ |
アプリのデータのエッジ。開いているすべてのページのためにプロトコルを一度だけ読み取り、変更をプッシュする |