L'hook e l'anti-snipe
Un hook di Uniswap v4 è un contratto che il PoolManager chiama in momenti precisi di uno
swap. L'implementazione attuale di StockFunHook usa sei permessi: beforeInitialize,
beforeAddLiquidity, beforeSwap, afterSwap, e i due permessi di delta che consentono
all'hook di prelevare una quota. Dal 2026-10-02 l'indirizzo dell'hook porta tutti i 14
permessi v4; le callback che l'implementazione non usa vengono lasciate passare.
L'indirizzo codifica i permessi
v4 legge i bit meno significativi dell'indirizzo di un hook per sapere quando chiamarlo. L'indirizzo quindi non si sceglie: viene minato tramite CREATE2 finché non salta fuori un valore i cui bit corrispondono ai permessi dichiarati.
Dal 2026-10-02 l'indirizzo minato è quello di un proxy, con tutti i 14 bit di permesso impostati. Un upgrade sostituisce l'implementazione dietro quell'indirizzo senza spostarlo, quindi non va mai minato di nuovo, e un'implementazione successiva può usare qualsiasi callback. L'attuale lascia passare le callback che non usa: restituiscono il proprio selettore e, dove è atteso un delta, zero. L'inizializzazione del proxy verifica che il suo indirizzo porti ogni bit.
Conseguenza pratica: l'indirizzo minato dipende dal bytecode del proxy e dagli
argomenti del suo costruttore, che contengono l'indirizzo dell'implementazione. Un nuovo
deploy va minato di nuovo. È anche il motivo per cui foundry.toml imposta
bytecode_hash = "none" — senza, l'indirizzo minato non corrisponde più al contratto
deployato.
Il permesso beforeAddLiquidity, aggiunto il 2026-10-01, ha cambiato i bit stessi:
l'indirizzo è stato minato di nuovo, e qualsiasi deploy effettuato prima di quella data è
obsoleto. Il proxy del 2026-10-02 li ha cambiati di nuovo: anche qualsiasi deploy
effettuato prima di quella data è obsoleto.
Il prelievo della commissione
In un acquisto, la commissione viene prelevata in beforeSwap, dall'ETH in entrata,
prima che avvenga lo swap. L'hook preleva la propria quota dal PoolManager e restituisce
un delta che la addebita all'acquirente. Il router StockFun e il lock della liquidità
versano l'ETH dell'acquirente nel PoolManager prima dello swap, così i loro acquisti non
attingono mai all'ETH che il PoolManager detiene già.
Qualsiasi altro router v4 paga la stessa aliquota. Ma un router che regola l'ETH
dell'acquirente dopo lo swap, come fa il V4Router di v4-periphery con la sua codifica
predefinita, si vede prelevare la tassa dall'ETH che il PoolManager detiene già, e il suo
acquisto fallisce quando la tassa è maggiore. Può succedere su un PoolManager che detiene
poco ETH, per esempio quello di una testnet. Un integratore dovrebbe versare l'ETH
dell'acquirente prima dello swap, come fa il router ufficiale. Le vendite non sono
interessate. La pipeline di sicurezza del 2026-10-01 ha documentato questo limite.
Prelevare invece la tassa come claim del PoolManager lo eliminerebbe per qualsiasi
router, ma sposterebbe il 2 % della tesoreria da pagato durante il trade ad accreditato e
pagato in seguito: il 2026-10-05 l'owner ha deciso di mantenere la tassa così come viene
prelevata oggi.
In una vendita, viene prelevata in afterSwap, dall'ETH in uscita, una volta noto
l'importo.
In entrambi i casi l'hook ripartisce subito: tesoreria, creatore, team, buyback. Solo la voce della tesoreria esce durante il trade, inviata al vault del mercato. Le altre tre voci vengono accreditate sull'hook e pagate al di fuori di qualsiasi trade.
Dal 2026-10-05 un vault che rifiuta la voce della tesoreria non fa più fallire il trade:
l'hook conserva l'importo come dovuto a quel vault (treasuryOwed, evento TreasuryOwed),
e ogni acquisto e vendita prosegue. Chiunque paga il debito a quel vault con payTreasury,
che fallisce e conserva il debito finché il vault continua a rifiutare; il keeper ci prova
a ogni ciclo. L'eccedenza dell'anti-snipe segue la stessa regola. Fino ad allora l'invio
falliva in modo esplicito: un vault che non poteva ricevere, per esempio dopo un upgrade
difettoso, faceva fallire ogni trade del suo mercato, vendite comprese.
La quota del creatore è a riscossione: si accumula sull'hook, mercato per mercato, e il
creatore la riscuote quando vuole, una transazione per mercato (claimCreatorFees). Dal
2026-10-05 un creatore che non può ricevere ETH da sé, un contratto senza modo di
riceverlo, riscuote verso un altro indirizzo (claimCreatorFeesTo); solo il creatore può
farlo.
Dal 2026-10-01 le quote del team e del buyback vengono accreditate allo stesso modo, un
saldo ciascuna, e pagate da claimTeamFees() e claimBuybackFees(). Chiunque può
chiamarle; pagano solo i wallet del team e del buyback che la factory indica al momento
della riscossione. Il BuybackBurner ritira da solo il proprio saldo all'inizio di ogni
burn. Un wallet che rifiuta l'ETH ritarda solo il proprio pagamento: la sua riscossione
fallisce e il saldo resta sull'hook.
Fino ad allora, quelle due quote venivano inviate durante il trade, con un fallback in
escrow quando l'invio falliva. L'audit di sicurezza del 2026-09-29 ha mostrato che un
wallet che accettava l'invio e poi chiamava il PoolManager poteva fermare il trading su
ogni pool. L'escrow non esiste più.
Ciò che l'hook detiene tra un trade e l'altro è dovuto a qualcuno: i saldi dei creatori,
quelli del team e del buyback, e i debiti verso i vault. L'ETH inviatogli da chiunque non
sia il PoolManager viene contato a parte, come disperso (strayEth). Dal 2026-10-05
l'owner di StockFun può portare fuori ciò che è disperso (rescue): al massimo
quell'importo di ETH, e qualsiasi token, poiché l'hook non ne detiene mai. Nulla di ciò che
l'hook deve può uscire per quella via. L'ETH forzato senza chiamata non viene contato, e
attende un upgrade.
Solo il lock aggiunge liquidità
Dal 2026-10-01, beforeAddLiquidity rifiuta ogni aggiunta di liquidità a un pool StockFun,
tranne quella del lock della liquidità.
Una posizione piazzata appena accanto al prezzo corrente funziona come un ordine limite: lo swap di un trader la attraversa e la converte, e il trader paga la tassa, mentre il titolare della posizione la aggiunge e la rimuove senza mai pagare il 5 %, né, nei primi dieci blocchi, la tassa anti-snipe. L'audit di sicurezza del 2026-09-29 lo ha riprodotto. I pool non applicano alcuna commissione LP di default, quindi nessun uso legittimo ha bisogno di una posizione di terzi.
Gli incassi di commissioni del lock stesso, con un delta di liquidità pari a zero, passano per il percorso di rimozione della liquidità, che l'implementazione attuale lascia passare: non ne sono interessati. Lo stesso vale per il recupero della modalità di chiusura, che rimuove le posizioni attraverso lo stesso percorso: vedi Il lancio a due posizioni.
Anti-snipe decrescente
Un pool v4 è attivo dal momento in cui viene inizializzato. Senza protezione, i primi blocchi successivi alla creazione verrebbero presi dai bot. Dal 2026-09-28, quei blocchi pagano una tassa più alta, che scende a ogni blocco, sia sugli acquisti sia sulle vendite. Con le impostazioni di default:
| Blocco dal lancio | Tassa |
|---|---|
| 1 | 80 % |
| Da 2 a 10 | 72, 64, 56, 48, 40, 32, 24, 16, 8 % |
| 11+ | Normale, 5 % |
Un bot che compra nel blocco di apertura paga subito l'80 %: lo sniping fa perdere soldi.
Tre cose meritano una spiegazione.
L'acquisto di lancio del creatore non richiede alcun controllo d'identità. L'unico swap
che il LiquidityLock esegue mai è l'acquisto facoltativo del creatore, dentro la propria
callback di creazione. Quindi "il chiamante è il lock" implica "siamo dentro la
transazione di creazione", e quell'acquisto paga il normale 5 %.
L'eccedenza ha una propria destinazione. Il normale 5 % mantiene la sua ripartizione
abituale. La parte che lo supera va alla tesoreria del mercato, e quindi agli holder al
prossimo airdrop. Sul mercato $STOCKFUN va al saldo del team sull'hook, pagato da
claimTeamFees().
La whitelist richiede l'identità, ed è questa la parte sottile. L'hook vede il router,
non l'acquirente. Il router StockFun porta quindi l'indirizzo del proprio chiamante negli
hook data, e l'hook si fida di quel campo solo se il chiamante è il router ufficiale,
quello registrato nella factory, che l'owner può cambiare in qualsiasi momento (accettato il
2026-09-28). In questo protocollo non si usa tx.origin da nessuna parte.
Limitazione documentata: un indirizzo in whitelist che passa per un aggregatore di terze parti durante i primi dieci blocchi non è esente.
La whitelist
Stabilita dal creatore del mercato. Gli indirizzi che contiene pagano il normale 5 % durante i blocchi anti-snipe. Fino al 2026-09-28 la lista era tenuta dall'owner e condivisa da tutti i mercati, proprio perché non potesse diventare un vantaggio da insider; ora un creatore può esentare i propri wallet. Validato il 2026-09-28: la lista è fissata nella transazione di creazione, pubblica, immutabile, e con un tetto di 20 indirizzi di default.
Il mercato $STOCKFUN
Anche qui si applica la tassa decrescente. $STOCKFUN non ha un creatore esterno: la sua
eccedenza va alle commissioni del team da riscuotere, e la sua whitelist viene stabilita
dall'owner al lancio.
Le impostazioni
Dal 2026-10-05 ogni numero di questa pagina è un'impostazione dell'owner di StockFun,
cambiata sull'hook con setTaxSettings: la tassa, il 5 % di default; le sue voci,
2 / 2 / 0,5 su un mercato lanciato e 2 / 2,5 su $STOCKFUN, con il buyback che prende il
resto; la tassa di apertura dell'anti-snipe, l'80 %; la sua diminuzione per blocco,
8 punti; i blocchi che dura, compreso quello di creazione, 10; e la whitelist più grande,
20 indirizzi.
Un cambio vale dallo swap successivo, su ogni pool, compreso un pool ancora dentro i suoi blocchi anti-snipe: la decrescita viene calcolata con le impostazioni in vigore, a partire dal blocco di lancio del pool. Quali che siano le impostazioni, l'anti-snipe non preleva mai meno della tassa. Il setter rifiuta un'aliquota oltre il 100 % e uno schema le cui voci superano la tassa. Il tetto della whitelist viene verificato quando viene creato un mercato: una lista già fissata resta com'è.
Gli upgrade
Dal 2026-10-02 l'owner di StockFun può fare l'upgrade dell'hook, con effetto immediato. La
tassa, la sua ripartizione, l'anti-snipe e le whitelist descritti in questa pagina sono
quelli dell'implementazione attuale. Un upgrade mantiene l'indirizzo dell'hook e deve
mantenere lo stesso PoolManager; la factory, che l'hook legge e che decide chi può farne
l'upgrade, è fissata nell'implementazione.