O hook e o anti-snipe

Um hook do Uniswap v4 é um contrato que o PoolManager chama em momentos precisos de um swap. A implementação atual do StockFunHook usa seis permissões: beforeInitialize, beforeAddLiquidity, beforeSwap, afterSwap e as duas permissões de delta que lhe permitem ficar com uma parte. Desde 2026-10-02, o seu endereço carrega todas as 14 permissões v4; os callbacks que ela não usa passam direto.

O endereço codifica as permissões

O v4 lê os bits menos significativos do endereço de um hook para saber quando chamá-lo. O endereço, portanto, não é escolhido: ele é minerado via CREATE2 até aparecer um valor cujos bits correspondam às permissões declaradas.

Desde 2026-10-02, o endereço minerado é o de um proxy, com todos os 14 bits de permissão ativados. Um upgrade substitui a implementação por trás desse endereço sem movê-lo, então ele nunca precisa ser minerado de novo, e uma implementação posterior pode usar qualquer callback. A atual deixa passar direto os callbacks que não usa: eles retornam o seu seletor e, onde se espera um delta, zero. A inicialização do proxy verifica que o seu endereço carrega todos os bits.

Consequência prática: o endereço minerado depende do bytecode do proxy e dos argumentos do seu construtor, que carregam o endereço da implementação. Uma nova implantação precisa ser minerada de novo. É também por isso que o foundry.toml define bytecode_hash = "none" — sem isso, o endereço minerado deixa de corresponder ao contrato implantado.

A permissão beforeAddLiquidity, adicionada em 2026-10-01, mudou os próprios bits: o endereço foi minerado de novo, e toda implantação feita antes dessa data está obsoleta. O proxy de 2026-10-02 os mudou outra vez: toda implantação feita antes dessa data também está obsoleta.

A cobrança da taxa

Numa compra, a taxa é cobrada em beforeSwap, sobre o ETH que entra, antes de o swap acontecer. O hook retira a sua parte do PoolManager e retorna um delta que a cobra do comprador. O router do StockFun e o lock de liquidez pagam o ETH do comprador ao PoolManager antes do swap, então as suas compras nunca recorrem ao ETH que o PoolManager já detém.

Qualquer outro router v4 paga a mesma taxa. Mas um router que liquida o ETH do comprador depois do swap, como faz o V4Router do v4-periphery com a sua codificação padrão, tem a taxa retirada do ETH que o PoolManager já detém, e a sua compra reverte quando a taxa é maior. Isso pode acontecer num PoolManager que detém pouco ETH, o de uma testnet, por exemplo. Um integrador deve pagar o ETH do comprador antes do swap, como faz o router oficial. As vendas não são afetadas. O pipeline de segurança de 2026-10-01 documentou essa limitação. Cobrar a taxa em claims do PoolManager, em vez disso, a eliminaria para todos os routers, mas faria os 2 % da tesouraria passarem de pagos durante o trade a creditados e pagos depois: em 2026-10-05, o owner decidiu manter a taxa como ela é cobrada hoje.

Numa venda, ela é cobrada em afterSwap, sobre o ETH que sai, quando o valor já é conhecido.

Nos dois casos, o hook divide imediatamente: tesouraria, criador, equipe, buyback. Só a linha da tesouraria sai durante o trade, enviada ao vault do mercado. As outras três linhas são creditadas no hook e pagas fora de qualquer trade.

Desde 2026-10-05, um vault que recusa a linha da tesouraria não faz mais o trade falhar: o hook guarda o valor como devido a esse vault (treasuryOwed, evento TreasuryOwed), e todas as compras e vendas continuam. Qualquer pessoa paga a dívida a esse vault com payTreasury, que falha e mantém a dívida enquanto o vault ainda recusar; o keeper tenta a cada ciclo. O excedente do anti-snipe segue a mesma regra. Até então, o envio falhava ruidosamente: um vault que não podia receber, depois de um upgrade defeituoso, por exemplo, fazia falhar todos os trades do seu mercado, vendas incluídas.

A parte do criador é baseada em pull: ela se acumula no hook, mercado a mercado, e o criador a reivindica quando quiser, com uma transação por mercado (claimCreatorFees). Desde 2026-10-05, um criador que não pode receber ETH por conta própria, um contrato sem meio de recebê-lo, reivindica para outro endereço (claimCreatorFeesTo); só o criador pode fazê-lo.

Desde 2026-10-01, as partes da equipe e do buyback são creditadas da mesma forma, um saldo para cada uma, e pagas por claimTeamFees() e claimBuybackFees(). Qualquer pessoa pode chamá-las; elas só pagam as carteiras da equipe e do buyback que a factory designa no momento da reivindicação. O BuybackBurner retira ele mesmo o seu saldo no início de cada burn. Uma carteira que recusa ETH só atrasa o seu próprio pagamento: a sua reivindicação falha e o saldo fica no hook.

Até então, essas duas partes eram enviadas durante o trade, com um fallback para escrow quando o envio falhava. A auditoria de segurança de 2026-09-29 mostrou que uma carteira que aceitasse o envio e depois chamasse o PoolManager podia paralisar a negociação em todos os pools. O escrow foi removido.

O que o hook detém entre os trades é devido a alguém: os saldos dos criadores, os da equipe e do buyback, e as dívidas com os vaults. O ETH enviado a ele por qualquer um que não seja o PoolManager é contado à parte, como extraviado (strayEth). Desde 2026-10-05, o owner do StockFun pode retirar o que está extraviado (rescue): no máximo esse valor de ETH, e qualquer token, já que o hook nunca detém nenhum. Nada do que o hook deve pode sair por esse caminho. O ETH forçado sem chamada não é contado, e espera um upgrade.

Só o lock adiciona liquidez

Desde 2026-10-01, beforeAddLiquidity recusa toda adição de liquidez a um pool do StockFun, exceto a do lock de liquidez.

Uma posição colocada logo ao lado do preço atual funciona como uma ordem limitada: o swap de um trader a atravessa e a converte, e o trader paga a taxa, enquanto o dono da posição a adiciona e a remove sem nunca pagar os 5 %, nem, nos dez primeiros blocos, a taxa anti-snipe. A auditoria de segurança de 2026-09-29 reproduziu isso. Os pools não cobram taxa de LP por padrão, então nenhum uso legítimo precisa de uma posição de terceiros.

As próprias coletas de taxas do lock, com delta de liquidez zero, passam pelo caminho de remoção de liquidez, que a implementação atual deixa passar: não são afetadas. O mesmo vale para a recuperação do modo de encerramento, que retira as posições pelo mesmo caminho: veja O lançamento em duas posições.

Anti-snipe decrescente

Um pool v4 está ativo a partir do momento em que é inicializado. Sem proteção, os primeiros blocos depois da criação seriam tomados por bots. Desde 2026-09-28, esses blocos pagam uma taxa mais pesada, que cai a cada bloco, tanto nas compras quanto nas vendas. Com os parâmetros padrão:

Bloco desde o lançamento Taxa
1 80 %
2 a 10 72, 64, 56, 48, 40, 32, 24, 16, 8 %
11+ Normal, 5 %

Um bot que compra no bloco de abertura paga 80 % de uma vez: o snipe dá prejuízo.

Três coisas merecem explicação.

A compra de lançamento do criador não precisa de verificação de identidade. O único swap que o LiquidityLock executa é a compra opcional do criador, dentro do seu próprio callback de criação. Então "o chamador é o lock" implica "estamos dentro da transação de criação", e essa compra paga os 5 % normais.

O excedente tem o seu próprio destino. Os 5 % normais mantêm a divisão de sempre. A parte acima disso vai para a tesouraria do mercado e, portanto, para os holders no próximo airdrop. No mercado $STOCKFUN, ela vai para o saldo da equipe no hook, pago por claimTeamFees().

A whitelist precisa de identidade, e essa é a parte sutil. O hook vê o router, não o comprador. Por isso, o router do StockFun leva o endereço de quem o chamou nos dados do hook, e o hook confia nesse campo somente se o chamador for o router oficial, o que a factory registra e que o owner pode mudar a qualquer momento (aceito em 2026-09-28). Nenhum tx.origin é usado em lugar nenhum deste protocolo.

Limitação documentada: um endereço na whitelist que passe por um agregador de terceiros durante os dez primeiros blocos não fica isento.

A whitelist

Definida pelo criador do mercado. Os endereços nela pagam os 5 % normais durante os blocos anti-snipe. Até 2026-09-28, a lista era mantida pelo owner e compartilhada por todos os mercados, justamente para que não pudesse virar uma vantagem de insider; agora um criador pode isentar as suas próprias carteiras. Validado em 2026-09-28: a lista é fixada na transação de criação, pública, imutável e com teto de 20 endereços por padrão.

O mercado $STOCKFUN

A taxa decrescente também se aplica. O $STOCKFUN não tem criador externo: o seu excedente vai para as taxas a reivindicar da equipe, e a sua whitelist é definida pelo owner no lançamento.

Os parâmetros

Desde 2026-10-05, todo número desta página é um parâmetro do owner do StockFun, alterado no hook com setTaxSettings: a taxa, 5 % por padrão; as suas linhas, 2 / 2 / 0,5 num mercado lançado e 2 / 2,5 no $STOCKFUN, com o buyback ficando com o resto; a taxa anti-snipe do bloco de abertura, 80 %; a sua redução por bloco, 8 pontos; os blocos que ela dura, incluindo o bloco de criação, 10; e a maior whitelist, 20 endereços.

Uma mudança vale a partir do próximo swap, em todos os pools, inclusive num pool ainda dentro dos seus blocos anti-snipe: o decaimento é calculado com os parâmetros em vigor, a partir do bloco de lançamento do pool. Sejam quais forem os parâmetros, o anti-snipe nunca cobra menos do que a taxa. O setter recusa uma taxa acima de 100 % e uma tabela cujas linhas ultrapassem a taxa. O teto da whitelist é verificado na criação de um mercado: uma lista já definida fica como está.

Upgrades

Desde 2026-10-02, o owner do StockFun pode fazer o upgrade do hook, com efeito imediato. A taxa, a sua divisão, o anti-snipe e as whitelists descritos nesta página são os da implementação atual. Um upgrade mantém o endereço do hook e precisa manter o mesmo PoolManager; a factory, que o hook lê e que decide quem pode fazer o seu upgrade, é fixada na implementação.