Architettura

Il protocollo vive su due chain. Ethereum ospita il launchpad, i pool e i vault; Robinhood Chain ospita le azioni tokenizzate.

graph TD subgraph ETH[Ethereum] F[StockFunFactory] -->|fa il deploy di| TK[StockFunToken] F -->|fa il deploy di| V[TreasuryVault] F --> LL[LiquidityLock] TK -->|ogni trasferimento| HR[HoldingRecorder] LL -->|due posizioni bloccate| PM[Uniswap v4 PoolManager] PM --> H[StockFunHook] H -->|2 %| V H -->|2 %| CR[Creatore] H -->|0.5 %| TW[Wallet del team] H -->|0.5 %| BB[BuybackBurner] BB -->|acquisto + burn| SF[$STOCKFUN] V -->|ETH → USDC → USDG| BH[BridgeHub] V -->|sendToAirdrop, rail locale| AD[AirdropDistributor] AD -.legge.-> HR AD -->|riscossioni, pro rata| HO[Holder del token] L[StockFunLens] -.legge.-> F O[TreasuryOracle] -.limita.-> V end subgraph RH[Robinhood Chain] RH2[RemoteHub] --> MV[Vault speculare per mercato] MV -->|pool secondari| ST[Stock Tokens] end BH -->|LayerZero, OFT USDG| RH2 ST -->|sendToAirdrop, OFT delle azioni| AD K[Keeper offchain] -.attiva.-> V K -.attiva.-> BH

I contratti

Questa tabella descrive il protocollo come è stato deciso. La parte del lancio è nel codice dal 2026-09-28, e la distribuzione dell'airdrop dal 2026-10-04, non deployata; gli adapter LayerZero delle azioni non sono nel repository. Router e adapter diversi dallo swap router ufficiale non vi figurano: UniswapV4StockRouter su Ethereum, RobinhoodStockRouter su Robinhood Chain e l'UsdgOftAdapter. Vedi Stato di avanzamento. Dal 2026-10-02 ogni contratto della tabella è upgradabile, tranne i token, il lock della liquidità e i deployer: vedi sotto. Le percentuali del diagramma sono le impostazioni di default della tassa.

Contratto Ruolo Cardinalità
StockFunFactory Crea i mercati, preleva la commissione di creazione, tiene il registro e le impostazioni dell'owner per i nuovi mercati e per i vault; l'autorità di upgrade di ogni modulo Ethereum Uno
MarketDeployer · VaultDeployer Aggirano EIP-170 trasportando il creation code del token e quello del proxy del vault; non detengono alcuno stato, vengono sostituiti tramite la factory anziché ricevere un upgrade Uno ciascuno
StockFunToken ERC-20 semplice, non upgradabile, senza mint e senza burn; nessuna logica propria oltre a un solo setter, setRecorder, e ai suoi rescue, per l'owner del protocollo; notifica ogni variazione di saldo al registratore della detenzione Uno per mercato
HoldingRecorder Registra nel tempo, per ogni token, la detenzione di ogni indirizzo e la supply al di fuori del PoolManager di Uniswap; un trasferimento fallisce se la sua registrazione fallisce, l'unica eccezione voluta alla regola di isolamento descritta più avanti Uno
TreasuryVault Detiene ETH, USDC e poi azioni; conversione, ogni tratta d'acquisto a sé, consegna delle sue azioni all'airdrop sul rail locale (sendToAirdrop), ogni azione a sé, e recupero di emergenza immediato Un proxy per mercato
LiquidityLock Crea il pool e deposita entrambe le posizioni, bloccate, e conserva la commissione LP e il tick spacing di ogni pool; conserva per il suo destinatario la quota rifiutata di un incasso di commissioni; non upgradabile; la sua unica uscita è la modalità di chiusura, 30 giorni dopo il suo annuncio Uno
StockFunHook Preleva la commissione su ogni swap, applica l'anti-snipe, tiene le impostazioni della tassa e la whitelist di ogni pool, rifiuta la liquidità di chiunque non sia il lock, detiene i saldi dei creatori, del team e del buyback finché non vengono riscossi, e ciò che è dovuto a un vault che ha rifiutato la sua quota Uno
StockFunSwapRouter Il router ufficiale per i trade, l'unico attraverso cui un indirizzo in whitelist è esente dall'anti-snipe Uno, sostituibile dall'owner
StockFunLens Sola lettura; aggrega lo stato di un mercato per la dapp, leggendo ogni vault a sé; dal 2026-10-06 la sua pagina riporta anche il rail del vault, il suo stato di pausa e l'USDC che ha inviato attraverso il bridge, lo stato di blocco del pool, il registratore della detenzione del token, e ciò che l'hook e il lock devono al vault Uno
TreasuryOracle Feed Chainlink, scritti una sola volta; i loro heartbeat sono impostazioni e, dal 2026-10-06, le sue due protezioni su Robinhood Chain: il controllo del sequencer, disattivato finché Chainlink non pubblica un feed di uptime per quella chain, e la pausa dell'oracolo di ogni azione, che trattiene il prezzo di quell'azione durante un'operazione societaria Uno per chain
BuybackBurner Compra $STOCKFUN e lo invia al burn. Finché il pool di $STOCKFUN è bloccato, non esiste nessun altro percorso Uno
BridgeHub · RemoteHub · RemoteTreasuryVault Il rail cross-chain; l'hub remoto è l'autorità di upgrade su Robinhood Chain e indica la rotta dell'airdrop e l'adapter di ogni azione; il vault speculare invia le sue azioni all'airdrop (sendToAirdrop) Uno, uno, un proxy per mercato
StockFunProtocolToken $STOCKFUN, non upgradabile come un token di mercato; la sua intera supply va nella sua posizione bloccata Uno
AirdropDistributor Distribuisce, su Ethereum, le azioni comprate da ogni tesoreria agli holder del suo token, per ciclo giornaliero; accredita solo i vault del mercato stesso; ogni holder riscuote, e una riscossione paga ogni azione che può; legato alla factory, che lo indica Uno

Proxy e upgrade

Dal 2026-10-02 ogni modulo è un proxy ERC-1967 davanti a un'implementazione, con upgrade tramite UUPS. Il proxy detiene l'indirizzo e lo stato; l'implementazione detiene il codice, e un upgrade la sostituisce. Un'implementazione non può mai essere inizializzata: ogni proxy viene inizializzato all'interno del proprio costruttore.

Ogni modulo chiede a un unico contratto chi può farne l'upgrade, la sua autorità di upgrade, fissata nella sua implementazione: la factory su Ethereum, che risponde con il proprio owner, e l'hub remoto su Robinhood Chain, che risponde con il proprio admin di emergenza, l'owner di Ethereum così come l'ha trasportato l'ultimo batch del bridge. Un trasferimento della proprietà della factory sposta quindi in un colpo solo il potere di upgrade di ogni modulo Ethereum, e quello dei moduli di Robinhood Chain con il batch successivo. Un upgrade viene rifiutato se la nuova implementazione indica un'altra autorità; quelle dell'hook e del registratore della detenzione devono inoltre mantenere lo stesso PoolManager.

Non upgradabili: i token, il lock della liquidità e, su Robinhood Chain, il deployer dei vault speculari, dal cui indirizzo deriva l'indirizzo di ogni vault speculare. MarketDeployer e VaultDeployer non detengono alcuno stato: la factory li sostituisce (setDeployers) anziché farne l'upgrade.

Lo storage viene solo esteso in coda, mai riordinato: il layout di ogni modulo è registrato in contracts/storage-layouts/, e contracts/script/check-storage-layouts.sh lo confronta prima di ogni upgrade. Dal 2026-10-05 confronta ogni livello di ogni struct, dimensioni comprese, e rifiuta qualsiasi modifica a una struct che sia l'elemento di un array dello storage: solo una struct che sia il valore di un mapping, o l'ultima variabile di stato, può crescere, in coda.

Un contratto di implementazione non viene mai usato direttamente, ma anche ciò che viene inviato per errore al suo stesso indirizzo ha una leva. La maggior parte delle implementazioni legge la propria autorità da un immutable, quindi l'owner del protocollo lo porta fuori; quelle della factory e dell'hub remoto tengono il loro admin nello storage del proxy, per cui sulle loro implementazioni la leva è l'indirizzo che ne ha fatto il deploy.

Chi può fare l'upgrade, e con quale rapidità: vedi Modello di fiducia.

Il contratto dell'airdrop

Dal 2026-10-04, AirdropDistributor distribuisce su Ethereum le azioni di ogni tesoreria. È un modulo upgradabile come gli altri, un proxy la cui autorità di upgrade è la factory. La factory lo indica (setAirdropDistributor) e i vault lo leggono in tempo reale; un distributore sostituito mantiene ogni ciclo riscuotibile dove si trova. Legge la detenzione dal registratore della detenzione, e le sue regole sono in L'airdrop.

Due percorsi lo raggiungono, e nient'altro accredita un ciclo:

  • Il rail del bridge. sendToAirdrop del vault speculare invia ogni azione in lista attraverso l'adapter LayerZero di quell'azione, indicato dall'hub remoto (setStockAdapter), verso il distributore indicato dall'hub remoto (setAirdrop), con l'id del mercato come payload. Su Ethereum l'OFT dell'azione conia l'azione wrapped a favore del distributore, e l'endpoint di LayerZero lo chiama. Il distributore accredita la consegna solo da un OFT di azione registrato dall'owner, da Robinhood Chain, inviata dal vault speculare che il bridge hub deriva per quel mercato.
  • Il rail locale. sendToAirdrop del vault Ethereum approva gli importi esatti, il distributore li preleva, solo dal vault del mercato stesso, e accredita ciò che ha ricevuto; le approvazioni vengono poi chiuse. Un vault collegato al bridge hub rifiuta questa chiamata.

Il keeper attiva entrambi, e decide solo quando; sul rail del bridge, dal 2026-10-06, anche il gas che ogni consegna riceve su Ethereum, che l'hub remoto mantiene entro i limiti che l'owner di StockFun vi fissa.

Proprietà strutturali

L'hook è un singleton. Un solo contratto serve tutti i pool, il che evita di minare un indirizzo per mercato — l'indirizzo di un hook v4 codifica i suoi permessi nei bit meno significativi, e trovarne uno costa potenza di calcolo. Dal 2026-10-02 è un proxy il cui indirizzo porta tutti i 14 permessi v4: un upgrade mantiene quell'indirizzo, e un'implementazione successiva può usare qualsiasi callback.

La liquidità non è un NFT. È detenuta direttamente nel PoolManager, indicizzata dall'indirizzo del lock. Non c'è alcuna posizione da trasferire, nessun approve da revocare, nessun tokenId da perdere. Le uniche operazioni di liquidità che il contratto può eseguire sono un modifyLiquidity con un delta esattamente pari a zero, per incassare le commissioni, e, tramite la modalità di chiusura, la rimozione di tutte le posizioni di un pool, 30 giorni dopo l'annuncio della chiusura.

Solo il lock aggiunge liquidità. Dal 2026-10-01 l'hook rifiuta qualsiasi altra posizione su un pool StockFun, quindi ogni trade è uno swap contro le posizioni bloccate, e paga la tassa.

I vault non hanno prelievo. Nessuna funzione permette a qualcuno di inviare gli asset di un vault a un indirizzo di sua scelta. Le due uscite sono l'airdrop, la cui unica destinazione è il contratto dell'airdrop indicato dal protocollo, che paga gli holder del token pro rata secondo una regola che nessuno sceglie, e la modalità di emergenza, con cui l'owner di StockFun sposta un asset verso qualsiasi indirizzo, subito. Queste sono le regole dell'implementazione attuale: l'owner di StockFun può fare l'upgrade di un vault, con effetto immediato.

I limiti sono impostazioni, i feed no. I limiti di prezzo dei vault, 50 e 200 punti base di default, sono impostazioni dell'owner di StockFun, lette in tempo reale da ogni vault; il keeper può solo restringerli. Il registro dei feed scrive ogni feed una sola volta; gli heartbeat dei feed sono impostazioni, e lo sono anche, dal 2026-10-06, le sue due protezioni, che possono solo trattenere un prezzo, mai cambiarlo: il controllo del sequencer (disattivato su Robinhood Chain finché Chainlink non vi pubblica un feed di uptime) e la pausa dell'oracolo di ogni azione (attiva per ogni azione di Robinhood Chain; vedi Il rail Robinhood). La modalità di emergenza non tocca né gli uni né gli altri: sposta asset, non cambia le regole di esecuzione. Il registro, come i vault, è upgradabile dall'owner di StockFun.

Isolamento e leve

Il 2026-10-05 il fondatore ha fissato una regola di progettazione: quando qualcosa fa fallire una funzione, le altre funzioni non devono farne le spese; tutto deve poter continuare a funzionare, e tutto deve avere una leva per recuperare i fondi persi e ricevere la correzione. Il quarto ciclo di audit di quel giorno l'ha portata nel codice, e da allora i cicli di audit contano come un difetto qualsiasi violazione delle sue due parti.

Isolamento. Un guasto in una funzione, un mercato, un'azione, un ciclo, una registrazione o un destinatario non blocca mai gli altri: l'elemento viene saltato, conservato come dovuto o differito, con un evento, e il resto prosegue.

  • Un batch del bridge lascia fuori un mercato il cui vault non può rilasciare il proprio cash (MarketSkipped), e gli altri attraversano. Una consegna che il token cash rifiuta a un vault speculare resta sull'hub remoto, dovuta a quel mercato (DeliveryRefused), e gli altri mercati vengono pagati
  • Un acquisto esegue la tratta di ogni azione a sé (LegFailed), e un invio all'airdrop ogni azione a sé (AirdropSendFailed)
  • Una riscossione paga ogni azione che può e differisce le altre (ClaimDeferred)
  • Un vault che rifiuta ETH non ferma più il trading del suo mercato: l'hook conserva ciò che non ha potuto pagare come dovuto a quel vault (treasuryOwed), e il lock conserva per il suo destinatario la quota rifiutata di un incasso di commissioni (vaultOwed, creatorOwed). Chiunque li paga non appena il destinatario accetta di nuovo ETH (payTreasury, payOwed), e il keeper lo fa a ogni ciclo
  • La Lens legge ogni vault in una chiamata a sé, così un vault che non può rispondere lascia leggibili gli altri (vaultReadable). Dal 2026-10-06 quella chiamata riporta anche il rail del vault, il suo stato di pausa e l'USDC che ha inviato attraverso il bridge, e la pagina riporta ciò che l'hook e il lock devono al vault: il servizio dati dell'app non legge nient'altro per mercato, così un vault che consuma tutto il suo gas fa fallire solo i propri numeri. Dal settimo ciclo di audit quel servizio legge anche ogni modulo upgradabile (l'hook, l'oracolo, il contratto dell'airdrop, i due hub del bridge) e il token del protocollo in un gruppo a sé, così un modulo che consuma tutto il suo gas, dopo un upgrade difettoso, fa fallire solo i propri numeri

Leve. Ogni contratto che può detenere ETH o token, anche di passaggio o per errore, ha una leva per portare fuori ciò che resta bloccato, e ogni modulo può ricevere una correzione: un upgrade, o un setter che sostituisce il modulo.

  • I moduli che non conservano nulla di nessuno tra una transazione e l'altra — la factory, la Lens, gli oracoli, il registratore della detenzione, gli stock router, il router di swap ufficiale e gli adapter del bridge — hanno il rescue(asset, amount, to) dell'owner del protocollo
  • I moduli che tengono conti propri — i vault, i due hub e il contratto dell'airdrop — hanno la modalità di emergenza
  • Il rescue dell'hook prende solo ciò che gli è stato inviato per errore, mai ciò che deve. Quello del lock non prende mai le quote che conserva, né le posizioni, che solo la modalità di chiusura raggiunge. Quello del BuybackBurner prende il suo ETH solo quando nessun burn potrebbe più spenderlo. I token, che non sono upgradabili, possono portare fuori ciò che è stato inviato al loro stesso indirizzo
  • Senza leva, per progettazione: i due deployer su Ethereum e il deployer dei vault speculari, che non detengono stato, non accettano ETH e non hanno owner

Dettagli in Modalità di emergenza.

L'unica eccezione voluta. La notifica di un token al suo registratore della detenzione resta bloccante: se la notifica fallisce, il trasferimento fallisce. Una notifica a cui fosse permesso fallire lascerebbe che un holder la privasse del gas nel proprio trasferimento, così che il registro salti il movimento e la sua quota dell'airdrop cresca. La leva è immediata, di una transazione ciascuna: setRecorder(0) sul token, che ne ferma la registrazione, o un upgrade sul posto del registratore. Vedi L'airdrop.

Pacchetti offchain

Pacchetto Ruolo
shared/ ABI generate, costanti del protocollo, formattazione. Un'unica fonte condivisa da tutto il resto
backend/ Servizio prezzi. Isola l'unica dipendenza esterna della dapp
keeper/ Conversione, batch del bridge, routing remoto, monitoraggio delle consegne e, dal 2026-10-05, il passaggio dell'airdrop, il pagamento di ciò che l'hook e il lock conservano per un destinatario, e l'incasso delle commissioni LP
cairn-app/ L'app, un front end Next.js, accanto a projet/ dal 2026-10-02, quando ha sostituito la dapp React + Vite: vedi La dapp
cairn-worker/ Lo strato dati dell'app, sull'edge: legge il protocollo una sola volta per tutte le pagine aperte e invia loro le modifiche