<!-- BlazePhoenix — Whitepaper Técnico, Versão 2.3.0 (legível por máquina, texto integral) · Português -->
> PDF canónico: https://blazephoenix.xyz/docs/BlazePhoenix_Whitepaper.pdf
> DOI: https://doi.org/10.5281/zenodo.23084091 (a versão depositada, v2.3) · todas as versões: https://doi.org/10.5281/zenodo.23084090 · DOI de conceito da primeira série de depósitos (v2.2): https://doi.org/10.5281/zenodo.22526574
> Litepaper (complemento em linguagem simples): https://blazephoenix.xyz/docs/BlazePhoenix_Litepaper.pdf
> Relatório de Verificação e Testes de Swap (setembro de 2026), as medições que este documento cita:
>   https://blazephoenix.xyz/verification-report-2026-09.md · https://blazephoenix.xyz/swap-tests-report-2026-09.md
> Este ficheiro é o texto completo do whitepaper em markdown, publicado para
> ingestão por IA e para citação. Licença do conteúdo: CC BY 4.0 — transcreve e cita com
> atribuição à BlazePhoenix e uma ligação. O código-fonte Solidity que o documento
> descreve está sob BUSL-1.1 até 2030: cita a arquitetura, não o reimplantes nem
> o clones. Superfícies para máquinas: /llms.txt · /facts.json · /knowledge-graph.jsonld
> Enumerações citáveis no seu interior: inovações I-1–I-18, equações primitivas E1–E42
> (Apêndice A) e invariantes impostos INV-1–INV-31 (Apêndice B).

# BlazePhoenix-Dex

*Tradução do original em inglês v2.3.0; prevalece o texto em inglês.*

**A cotação é a troca.**

**A exchange medida: um agregador de liquidez on-chain em que a cotação e a execução são o mesmo cálculo**

*Whitepaper Técnico — Versão 2.3.0*

| | |
|---|---|
| Versão | 2.3.0 — 2026-10-14 |
| Data | 2026-10-14 |
| Autor | Mitra |
| DOI | [10.5281/zenodo.23084091](https://doi.org/10.5281/zenodo.23084091) (v2.3) · todas as versões [10.5281/zenodo.23084090](https://doi.org/10.5281/zenodo.23084090) · DOI de conceito da primeira série de depósitos (v2.2) [10.5281/zenodo.22526574](https://doi.org/10.5281/zenodo.22526574) |
| Afiliação | BlazePhoenix — https://blazephoenix.xyz |
| Licença do texto | CC BY 4.0 — transcreve e cita com atribuição e uma ligação |
| Licença do código | BUSL-1.1 (Data de Alteração 2030-06-01) — cita a arquitetura, não reimplantes |
| Repositório | `Blaze-Phoenix-Dex`, `main` em `8916545`, 2026-09-24 — https://github.com/blazephoenixxyz-crypto/Blaze-Phoenix-Dex |

> O preço que te é mostrado é calculado pelo código público que executa a tua troca, no quadro que a executa. Ninguém — nem os autores — pode alterar a taxa ou os pisos: estão compilados no código.

## Dez linhas. Sem marketing.

1. **Nenhum servidor escolhe a tua rota.** A transação que a executa deriva-a, a partir do estado público das pools.
2. **Nenhum oráculo fixa o preço da tua troca.** Fixam-no as pools — lidas no quadro que a liquida.
3. **A cotação e o piso são um só avaliador.** Não há nenhuma costura por onde o preço possa derivar.
4. **O teu mínimo é obrigatório.** O Router recusa um swap sem ele.
5. **As afirmações de uma pool forjam-se de graça; a sua saída medida não.** O encaminhamento assenta na segunda.
6. **A taxa, a divisão e os pisos estão compilados no código.** Não existe nenhum setter. Ninguém — nem os autores — os pode mover.
7. **Sem proxy, sem caminho de atualização, sem `selfdestruct`, sem saldo em repouso.** Entre trocas, não há nada para roubar ao Router.
8. **Uma pool hostil custa-te preço e depois reverte.** Nunca entrega abaixo do teu piso.
9. **Cada número aqui é apresentado ao lado do seu denominador** — e ao lado da forma como poderia ser manipulado.
10. **Se todos os servidores que operamos desaparecessem esta noite, os contratos cotariam, encaminhariam e liquidariam amanhã.**

Tudo o que se segue é a prova, com a linha de código que impõe cada afirmação e o limite que a restringe.

## Resumo

A BlazePhoenix-Dex é um agregador de liquidez on-chain construído sobre uma só afirmação: uma cotação e a sua execução são o mesmo cálculo. A rota é derivada dentro da transação que a executa, a partir do estado público das pools, por uma biblioteca sem estado que qualquer leitor pode voltar a correr; o número que vincula na liquidação é rederivado pelo mesmo despachante no quadro de execução. Não há serviço de encaminhamento, nem oráculo de preços, nem keeper, nem caminho de atualização. Este documento especifica os cinco contratos — Core, Hub, Solver, Router, Quoter — e os operadores da Meta-Equação: o Despachante Óctuplo Ω, a Derivação Determinística 𝒟, o piso Iron-Law Φ, o Campo de Vitalidade Ψ e o projector anti-burla Ξ. Por trás deles está uma única disciplina, o Desenho Metrológico: medir cada coordenada que pode ser medida e tornar o resto monótono, para que uma entrada falsa prejudique apenas quem a fornece. Cada garantia é enunciada com o seu ponto de imposição e o seu limite. O aparato de verificação é apresentado com os seus denominadores: 1,609 testes declarados em 236 ficheiros, 268 de 268 mutantes selecionados eliminados, 14 de 15 mutantes detetados entre os que visam 43 invariantes com estado, matrizes de cobertura de força 2 (63 linhas, 258 pares) e 3 (168 linhas, 1,636 triplos), 14 + 5 relações metamórficas, três builds do otimizador em acordo e um estudo de 240 amostras sobre como uma cotação envelhece. Dezoito inovações com nome sustentam o desenho, da Meta-Equação à imunidade por exaustão; cada uma é catalogada com a sua matemática antes de a especificação começar. A geração em produção na Base, Ethereum, Optimism e Arbitrum é a V1; este documento especifica a V2, exercitada de ponta a ponta em forks da liquidez real em cada chain que serve.

## Como ler este documento

Cada mecanismo recebe uma frase simples antes de receber uma frase precisa, por isso o documento lê-se a duas profundidades: as frases simples e as figuras dão a arquitetura; as frases precisas, as tabelas e os apêndices permitem-te verificá-la. Cada garantia é uma frase — a afirmação, o ponto que a impõe, o limite que a restringe. Seis exemplos resolvidos fazem a aritmética à mão, do princípio ao fim: uma cotação de produto constante (§4), uma divisão entre duas pools (§10), o piso Iron-Law numa rota de dois hops (§11), um identificador de pool Uniswap V4 derivado da sua chave (§5), os dois regimes de taxa numa só rota (§13) e a leitura de uma liquidação (§11). Os números são apresentados ao lado do denominador contra o qual foram medidos, e o comando que os reproduz está no Apêndice C. O repositório é canónico: onde este texto e o código-fonte divergirem, prevalece o código-fonte.

## As inovações

A BlazePhoenix-Dex não é um agregador com um servidor melhor. É um agregador **sem servidor** — e chegar aí exigiu um conjunto de mecanismos que antes não existiam. Dezoito deles sustentam o desenho. Cada um é apresentado aqui com o que é, a matemática que o define, porque importa a quem negoceia e a secção que o especifica por completo.

### I-1 · Cotação ≡ Execução

**O quê.** O número que te é cotado e o número que vincula a tua troca vêm de um só avaliador — o despachante Ω do Core — executado uma vez para planear e de novo dentro do quadro de execução para liquidar. Não existe um segundo modelo de preços em parte alguma do sistema.

**Matemática.** Para cada perna $\ell$, o planeador e o executor avaliam a mesma função $\Omega(p_{\ell}, x_{\ell})$ sobre o mesmo estado público; o piso da rota é rederivado a partir desse valor obtido dentro do quadro (E15, E16), nunca lido da rota.

**Porque importa.** Todas as classes de exploit de agregadores que vivem na lacuna entre “o que o servidor disse” e “o que a chain fez” ficam sem lugar onde viver. Medido: as cotações sem deriva liquidam exatamente na sua previsão **64 vezes em 64**, em mocks e na Base em produção. (§3, §11, §12)

### I-2 · O solver on-chain, de chamada gratuita

**O quê.** `Solver.findBestRoutePlan(tokenIn, tokenOut, amountIn)` é uma função `view`. Qualquer pessoa obtém a melhor rota, sem necessidade de confiança, com um `eth_call` gratuito — sem chave de API, sem relayer, sem assinatura — e `swapBestExactIn` resolve e liquida de forma atómica numa só transação.

**Matemática.** Todo o Solver é a maximização com restrições da Meta-Equação (E1) sobre o espaço de rotas $\mathcal{R}_{\mathcal{D}}$, executada como um pipeline determinístico: derivação → classificação → sondagem → filtragem → alocação → barreira → piso.

**Porque importa.** A inteligência de encaminhamento do setor corre em servidores fechados, sem contagem de linhas auditável. A nossa consiste em 29,183 bytes de bytecode público que qualquer pessoa pode voltar a correr, obtendo a mesma resposta. (§2, §10, §11.1)

### I-3 · A Meta-Equação

**O quê.** O agregador inteiro, escrito como uma só expressão.

**Matemática.**
$$R^{\star} = \arg\max_{R}\ \mathrm{net}(R)\cdot\prod_{\ell \in R}\hat{\Psi}(p_{\ell})\cdot\mathbf{1}[\mathrm{net}(R)\ge\Phi(R)]\cdot\Xi(R)$$

**Porque importa.** A forma de produto é uma propriedade de segurança: um único fator que falhe — uma perna que cota zero, uma pool sem estatuto, uma rota abaixo do seu piso, um hook hostil — envia a pontuação da rota para exatamente zero. Sem penalizações suaves, sem pesos ajustáveis, sem rotas que falham por pouco a passar às escondidas. (§3)

### I-4 · O Despachante Óctuplo Ω

**O quê.** Seis tipos de venue — Uniswap V2, V3, V4, Algebra, Solidly estável e Solidly volátil — reduzem-se a quatro famílias matemáticas, por trás de uma só tabela de atributos e de um só despachante.

**Matemática.** Produto constante $y = \lfloor x(\mathrm{BPS}-f)\,r_{\mathrm{out}} / (r_{\mathrm{in}}\mathrm{BPS} + x(\mathrm{BPS}-f)) \rfloor$ (E2); liquidez concentrada em Q64.96, $\sqrt{P}' = L\sqrt{P}/(L + x_{f}\sqrt{P}/Q_{96})$, $y = L(\sqrt{P}-\sqrt{P}')/Q_{96}$ (E3); cada produto perigoso fatorizado através de `mulDiv` de 512 bits.

**Porque importa.** A fragmentação revela-se um problema de linguagem, não de matemática. Uma fórmula auditada por família dá preço a cada venue em cada chain; um novo fork de uma família conhecida é uma linha de tabela, não código novo. (§4)

### I-5 · Derivação Determinística 𝒟

**O quê.** As pools são **calculadas**, não pedidas. O Hub deriva cada endereço candidato a partir da factory, do par e do init-code hash, e só admite endereços que contenham bytecode de runtime.

**Matemática.** $\mathrm{pool} = \mathrm{addr}_{20}(\mathrm{keccak256}(\mathtt{0xff}\,\Vert\,\mathrm{origin}\,\Vert\,\mathrm{salt}\,\Vert\,\mathrm{initCodeHash}))$ (E8).

**Porque importa.** A resposta de uma factory pode ser falsificada; a aritmética não. A descoberta não custa nenhuma chamada externa por candidato e funciona de forma idêntica em todas as chains EVM, com os pool managers e as factories como configuração de runtime, nunca fixados no código. (§7)

### I-6 · Uniswap V4, inteiramente dentro do quadro

**O quê.** As pools V4 não têm endereço e não respondem a chamadas. A BlazePhoenix deriva os seus ids, **prova**, contra o storage do PoolManager, que cada uma está ativa, lê o preço e a liquidez através de `extsload`, percorre o livro de ticks ao longo de até dezasseis trechos, liquida através do singleton — ETH nativo incluído — e faz a triagem dos hooks apenas por aritmética.

**Matemática.** Base de storage $\mathrm{slot} = \mathrm{keccak256}(\mathrm{abi.encode}(\mathrm{poolId}, 6))$ com $\sqrt{P}$ nos bits [0,160) e a taxa de LP em [208,232) (E4); a barreira de hooks $(\mathrm{uint160}(\mathrm{hook})\,\&\,\mathtt{0x3FFF})\,\&\,((1\ll3)\mid(1\ll2)) \ne 0 \Rightarrow$ recusar, sem qualquer chamada (E18); a barreira de taxa dinâmica E19.

**Porque importa.** Derivar, provar, cotar, filtrar e liquidar V4 sem confiar em nenhuma resposta do venue — a integração V4 mais profunda que um agregador pode ter, e toda ela verificável on-chain. (§5)

### I-7 · O solver Solidly estável

**O quê.** Um solver exato e que falha fechado para a curva estável quártica usada pelos venues da classe Aerodrome e Velodrome.

**Matemática.** Invariante $k(x,y) = x^{3}y + xy^{3}$ (E5), resolvido por uma iteração de Newton limitada, com um ajuste de uma unidade contra o tomador e um teto de 64 passos (E6), após normalização decimal para 18 casas (E7).

**Porque importa.** O fluxo de stablecoins e de liquid staking concentra-se nestas curvas, onde estas entregam quase toda a entrada como saída. O solver cota-as com exatidão — e, onde um limite não pode ser provado, devolve zero em vez de um palpite. (§6)

### I-8 · O Monoslot

**O quê.** Todo o estado de encaminhamento de uma pool — atividade, classe de profundidade, taxa, tipo, flags, recência — empacotado numa **única palavra de 256 bits**.

**Matemática.** $s = a \,\vert\, f\!\ll\!8 \,\vert\, k\!\ll\!32 \,\vert\, r\!\ll\!40 \,\vert\, (c\wedge\mathtt{0xFFF})\!\ll\!48 \,\vert\, b\!\ll\!60 \,\vert\, \dots \,\vert\, B_{\mathrm{last}}\!\ll\!224$ (E9).

**Porque importa.** Um `SLOAD` classifica uma pool; um `SSTORE` sobre um `SLOAD` mantém-na atualizada. E a palavra não contém nenhum preço, por isso a memória do registo é estruturalmente incapaz de atribuir um preço errado a uma troca. (§8)

### I-9 · O Registo Auto-Regenerável e o Campo de Vitalidade Ψ

**O quê.** O protocolo aprende a liquidez negociando-a. Dezasseis slots por par, uma pontuação de aptidão ganha em swaps reais, decaimento por aritmética e uma **prova de par**: uma pool prova quais os tokens que negocia antes de ser armazenada.

**Matemática.** $\Psi = V \cdot 2^{b} \cdot (1 + 0.25\,\mathbf{1}_{\mathrm{bridge}}) \cdot (1 + 0.05\,\mathbf{1}_{\mathrm{conc}})$ (E10); a atividade reduz-se a metade a cada 24,576 segundos de silêncio, $V = \mathrm{swapCount} \gg \lfloor (t - t_{\mathrm{last}})/24{,}576 \rfloor$ (E11); classe de profundidade $b = \min(15, \lfloor \log_{10}(d/10^{15}) \rfloor)$ (E12); um recém-chegado só desaloja o mais fraco acima de uma margem, $2^{b(d_{\mathrm{new}})} > \Psi_{\mathrm{worst}} + \lfloor \Psi_{\mathrm{worst}}/4 \rfloor$ (E13).

**Porque importa.** Sem keeper, sem cron, sem curador a decidir que pools importam: o registo regenera-se a si próprio a partir do fluxo que os utilizadores já estavam a enviar. (§9)

### I-10 · A Divisão Ancorada em Capital

**O quê.** A qualidade do preço e a profundidade da pool são medidas separadamente. Uma sonda minúscula mede o preço marginal de cada pool; uma **banda de credibilidade** ancorada no capital descarta os valores atípicos; as sobreviventes partilham a ordem em proporção à profundidade medida.

**Matemática.** Centro = a mediana ponderada pela profundidade — o primeiro $r_{i}$ para o qual $\sum_{j \le i} d_{j} \ge \lceil \sum d / 2 \rceil$ — com banda $[0.95, 1.05]\times$ centro (E25); a divisão só sobrevive se $\mathrm{out}_{\mathrm{split}} \ge \mathrm{out}_{\mathrm{single}}\cdot(1 + 25/10^{6})$ (E14).

**Porque importa.** Para mover a âncora, um atacante tem de depositar mais do que metade da liquidez real do par — capital em risco, não uma doação gratuita. A garantia permanente: **uma divisão nunca paga menos do que a melhor pool única.** Medida contra uma grelha exaustiva na Base, a rota do Solver fica, no máximo, a 0.13 bps do ótimo. (§10)

### I-11 · O piso Iron-Law Φ

**O quê.** Uma saída mínima rederivada **on-chain, na execução**, a partir do impacto de preço medido e da concentração da rota — independente de tudo o que o chamador tenha fornecido.

**Matemática.** $\mathtt{floorBps} = \max(9{,}600 - \mathtt{legShv} - \min(\delta, 10^{4}) - \sigma_{\ln}/10^{14},\ 8{,}000)$ (E15), com o corte por concentração $\mathtt{legShv} = \sum_{\mathrm{hops}} \lfloor 200\,((\sum a)^{2} - \sum a^{2})/\sum a^{2} \rfloor$ (E23); a entrega tem de atingir $\mathtt{effMin} = \max(\mathtt{userMinOut},\ \mathtt{route.singleOutFloor},\ \lceil \mathtt{finalHopQuote}\cdot\mathtt{floorBps}/10^{4}\rceil)$ (E16).

**Porque importa.** Os dados do chamador só podem apertar a proteção, nunca afrouxá-la. Numa troca de 1 % da profundidade, o piso limita um sandwich a cerca de 2.7 % da troca e **recusa** para lá disso — a ida e volta do atacante torna-se negativa além desse limite. (§11.5, §14.3)

### I-12 · Medição em cada costura

**O quê.** O Router nunca acredita que uma transferência aconteceu; mede-a. Cada recolha, cada chegada a um hop e cada entrega é uma variação de saldo real, desde a primeira instrução do swap até à carteira do destinatário.

**Matemática.** Cada hop é reescalado em função da sua chegada medida; os tokens com taxa na transferência em pernas de produto constante são cotados sobre a diferença que a pool efetivamente vê, a quantidade exata que o próprio invariante da pool vai verificar.

**Porque importa.** Tokens que cobram taxa, fazem rebase ou reportam valores falsos não conseguem levar o Router a prometer o que não detém — e o Router não detém **nada em repouso** entre transações (INV-1). (§11.2, §11.4)

### I-13 · A Doutrina do Callback Único

**O quê.** Um único `fallback` responde ao callback de flash accounting de todos os venues com forma de V3 — Uniswap V3, Algebra, Pancake V3, Sushi V3, os forks concentrados do Solidly — com o contexto da perna em curso guardado em transient storage EIP-1153.

**Matemática.** O token devido é lido a partir dos sinais dos dois deltas; o pagamento é limitado de três formas — só a pool vinculada, só enquanto uma perna está em curso, nunca mais do que o orçamento registado da perna (INV-10).

**Porque importa.** Um ponto de entrada pequeno e triplamente protegido substitui um bestiário de callbacks por fork — menos bytecode, menos superfície, uma só coisa para verificar. (§11.4)

### I-14 · A Regra do Excedente e a imunidade por exaustão

**O quê.** Uma taxa de 0.28 %, compilada no código, cobrada uma vez sobre a primeira moeda-ponte que o Router detém — e **nenhum termo de taxa que cresça com a diferença entre cotação e entrega.**

**Matemática.** $\mathrm{fee} = \lceil 28 \cdot \mathrm{base} / 10^{4} \rceil$, dividida em $t_{1} = \lfloor 3{,}000\cdot\mathrm{fee}/10^{4} \rfloor$, $t_{2} = \mathrm{fee} - t_{1}$ (E17); o predicado de regime $\mathrm{feeHop} = \min\{h : \mathrm{isBridge}(\mathrm{hops}[h].\mathrm{tokenIn})\}$ (E26). Uma rota que evite todas as moedas-ponte paga em todos os hops, pelo que nenhum prefixo de dust pode levar a taxa consigo.

**Porque importa.** Tudo o que as pools entregam acima da cotação chega-te por inteiro. A taxa não pode ser aumentada contra quem negoceia nem reduzida para um integrador favorecido — ninguém detém essa chave. (§13)

### I-15 · A taxa de câmbio byte–gas ρ*

**O quê.** As quatro portas do Router são um modelo de custo afim tornado interface: resolver on-chain, ou transportar uma rota pré-resolvida em calldata — o que for mais barato nessa chain.

**Matemática.** Transportar a rota em calldata se e só se $p_{\mathrm{byte}} < \rho^{*}$, com $\rho^{*}$ medido em 66.9–105.5 gas por byte consoante a forma da rota (E22).

**Porque importa.** Cada chain tem um preço para os bytes e um preço para a computação. A BlazePhoenix mede a taxa de câmbio entre eles e entrega a quem negoceia a porta mais barata. (§17.6)

### I-16 · O projector anti-burla Ξ

**O quê.** Qualquer pool cujo hook V4 declare permissões que alteram deltas é removida do conjunto de candidatos **antes da classificação**, sem que o hook seja alguma vez chamado.

**Matemática.** $\Xi(R) \in \{0,1\}$ na Meta-Equação, avaliado pelo teste de bits E18 sobre o endereço do hook.

**Porque importa.** Um hook hostil nunca tem a oportunidade de mentir: nunca lhe é perguntado nada. Três camadas independentes — bits do endereço, uma lista de permissões com fixação por codehash e Ξ — interpõem-se entre quem negoceia e um venue malicioso. (§5.5, §14.2)

### I-17 · A Porta de Sentido Único

**O quê.** A autoridade administrativa termina de forma irreversível, no bytecode. `renounceControl` escreve uma flag que nenhum caminho de código consegue anular; depois disso, resta apenas um nível de curadores que só pode crescer.

**Porque importa.** “Não lhe vamos mexer” torna-se “não lhe conseguimos mexer”. A taxa, a divisão e os pisos nunca foram configuráveis, desde o início (INV-4); depois de a porta se fechar, mais nada o é. (§14.7)

### I-18 · O Desenho Metrológico e o denominador publicado

**O quê.** A disciplina por trás de tudo o que está acima — medir cada coordenada que pode ser medida, tornar o resto monótono para que uma entrada falsa prejudique apenas quem a fornece — e um aparato de verificação que reporta **cada número ao lado do seu denominador**.

**Matemática.** 1,609 testes declarados em 236 ficheiros; 268 de 268 mutantes selecionados eliminados, cada um emparelhado com o único teste que tem de falhar; matrizes de cobertura de força 2 (258 de 258 pares) e 3 (1,636 de 1,636 triplos) sobre os fatores de regime; 14 + 5 relações metamórficas; três builds do otimizador que concordam bit a bit; provas simbólicas em Halmos e no Certora Prover.

**Porque importa.** A maioria dos projetos publica uma contagem de testes. A BlazePhoenix publica como a sua evidência poderia ser manipulada e aquilo contra o qual mede — e recalcula-a em cada commit. (§2.3, §15)

### O placar

| Propriedade medida | Resultado |
|---|---|
| Cotações sem deriva que liquidam exatamente na sua previsão (estudo de 240 amostras) | **64 / 64** |
| Patologias de venue × portas que liquidam ou recusam com um seletor nosso — nunca de uma terceira forma | **20 / 20** |
| Mutantes selecionados eliminados | **268 / 268** |
| Ações de controlo cuja recusa é exercitada por código exato | **31 / 31** |
| Quantidades calculadas em dois sítios que um teste com nome liga entre si | **7 / 7** |
| Pares de valores de fatores de regime exercitados por construção | **258 / 258** |
| Triplos de valores de fatores de regime exercitados por construção | **1,636 / 1,636** |
| Builds do otimizador da matemática de cotação em acordo (runs 1 / 300 / 20,000) | **3 / 3** |
| Pré-visualização → entrega em quatro chains | **0–1 bps** |
| Rota do Solver vs. uma grelha exaustiva na Base | **no máximo a 0.13 bps** |
| Maior sandwich que o piso admite numa troca de 1 % da profundidade, recusando a partir daí | **≈ 2.7 %** |
| Investigadores de segurança externos creditados · Achados críticos | **25 · 0** |


## Índice

- As inovações (I-1–I-18) e o placar
- §1 O problema: uma cotação é uma promessa que outra pessoa calculou
- §2 A resposta e a disciplina: desenho guiado por invariantes e Desenho Metrológico
- §3 A Meta-Equação e o orçamento de dependências
- §4 O Despachante Óctuplo Ω — tipos, famílias, formas fechadas
- §5 Uniswap V4 de ponta a ponta — singleton, prova de existência, barreira de taxa, hooks
- §6 O solver Solidly
- §7 Derivação Determinística 𝒟
- §8 O Monoslot
- §9 O Registo Auto-Regenerável e o Campo de Vitalidade Ψ
- §10 O encaminhamento e o Alocador de Divisão
- §11 A camada de execução e o piso Iron-Law Φ
- §12 Superfícies de cotação, e como uma cotação envelhece
- §13 Política de taxas: os dois regimes e a Regra do Excedente
- §14 Modelo de segurança
- §15 O aparato de verificação, medido
- §16 Arquitetura e tamanhos
- §17 Desempenho medido
- §18 O DEX, reduzido ao osso
- §19 Estado da implantação
- §20 Token — BZPX
- §21 Programa de investigação e registo de segurança
- §22 Em que tens de confiar, e em que não precisas
- §23 Trabalho relacionado
- §24 Conclusão
- §25 Staking V4: desenho
- Apêndice A · As equações primitivas (E1–E42)
- Apêndice B · Os invariantes (INV-1–INV-31)
- Apêndice C · Comandos de reprodução
- Glossário
- Referências

---

## §1 O problema: uma cotação é uma promessa que outra pessoa calculou

Imagina que vendes um carro numa cidade com vinte concessionários. Um bom corretor visita os vinte, encontra o melhor preço e talvez divida a venda entre dois deles. A maioria dos “corretores” on-chain consulta os preços na sua própria base de dados — possivelmente desatualizada — e mostra-te um resultado. Não consegues verificar que olharam para os vinte, nem que te mostraram o melhor. Só consegues verificar que, até agora, foram honestos.

Todos os agregadores cuja documentação lemos — 1inch, CoW Swap, Velora (ParaSwap), KyberSwap, OpenOcean, Jupiter e UniswapX, tal como documentados em 2026-09-07 — funcionam assim: um serviço calcula a rota off-chain e o contrato executa a rota que lhe é entregue. O contrato não escolhe; verifica. Isso é engenharia sólida — é por isso que esses sistemas são rápidos e baratos — e tem uma consequência raramente dita com clareza: **a afirmação mais forte que um sistema assim pode fazer é que o seu operador é honesto.**

Em geral, a lacuna não é fraude. É deriva, com três origens comuns. A cotação foi calculada sobre reservas que se moveram antes de a transação ser incluída. A pesquisa foi apenas tão exaustiva quanto o orçamento do operador permitia. E cada correção entre a cotação e a execução — uma margem de slippage, uma taxa pelo caminho — foi aplicada por código que o utilizador não leu, a um número que o utilizador não consegue reproduzir. Nada disso exige má intenção. Tudo isso é invisível.

### §1.1 A fragmentação é real, e mais superficial do que parece

Um trader que quer o melhor preço enfrenta um paradoxo. A liquidez existe, espalhada por dezenas de exchanges descentralizadas, cada uma com os seus próprios contratos de pool, a sua própria curva de preço, o seu próprio esquema de endereços — mas nenhum venue a detém toda. O preço da melhor execução é o custo de falar a língua de todas as exchanges ao mesmo tempo, e de confiar em todos os tradutores entre o preço mostrado e a troca que se concretiza.

A resposta estabelecida integra os venues um a um: um conector para a Uniswap, outro para os forks Solidly, outro para cada variante de liquidez concentrada, cada um com cotação feita à medida, consultas de endereços feitas à medida, execução feita à medida. A superfície de integração cresce linearmente com o número de venues, e cada conector é um novo sítio para um defeito de cálculo de preço ou para uma discrepância silenciosa entre o número cotado e o número executado.

A fragmentação é mais superficial do que parece. Por baixo da diversidade à superfície, os criadores de mercado automatizados que detêm a maior parte da liquidez on-chain são regidos por um pequeno conjunto de invariantes. As pools de produto constante obedecem a $x \cdot y = k$. As pools de liquidez concentrada acompanham um preço em raiz quadrada, em vírgula fixa, sobre uma liquidez ativa constante por troços. A família Solidly obedece a uma quártica, $x^{3}y + xy^{3} = k$, nos seus pares estáveis, e ao produto constante nos voláteis. Há um punhado de formas, não sessenta.

Se as formas são poucas, o custo da agregação não tem de crescer com o número de venues; só tem de crescer com o número de formas. Um protocolo que implementa cada forma uma vez, corretamente, e despacha cada venue para a forma certa reduz a superfície de integração de linear a constante. Acrescentar um venue deixa de ser engenharia e passa a ser configuração: atribui-se um tipo e um modo de derivação de endereços, e a matemática existente dá-lhe preço, o router existente liquida-o, o registo existente aprende-o.

**A afirmação central do desenho:** cada venue pelo qual a BlazePhoenix encaminha é uma parametrização de uma de entre uma pequena família de funções de saída — quatro famílias operacionais numa taxonomia de seis tipos (§4) — mantidas uma única vez, numa só biblioteca sem estado, e nunca redefinidas. Acrescentar um venue significa atribuir um tipo e um modo de derivação, não escrever novo código de cálculo de preço.

### §1.2 A válvula de escape off-chain

A arquitetura de agregador predominante cota rotas numa frota de servidores, realiza um leilão entre solvers off-chain, indexa a liquidez das pools com bots keeper e envia o resultado para um contrato de liquidação on-chain leve — frequentemente por trás de um proxy atualizável cuja chave de administração pode substituir a lógica por completo. Um serviço web produz o preço, uma base de dados guarda o grafo de liquidez, um operador privilegiado pode mudar as regras, e a chain torna-se um local de liquidação para decisões tomadas noutro sítio, por software que o utilizador não consegue ver e não consegue verificar.

Esse arranjo reintroduz exatamente a confiança que a tecnologia devia eliminar. Uma cotação off-chain pode diferir da execução on-chain, e o utilizador não consegue provar que não devia ter diferido. Um keeper pode apagar-se e o router fica às cegas. Um administrador de proxy pode, numa só transação, transformar um contrato honesto num contrato hostil.

| Aspeto | Agregador resolvido off-chain | BlazePhoenix-Dex |
|---|---|---|
| Cotação | Servidores off-chain ou um leilão de solvers | Um despachante on-chain, partilhado pela pré-visualização e pela execução dentro do quadro |
| Descoberta de liquidez | Bots keeper indexam e enviam listas | Registo Auto-Regenerável — liquidez aprendida ao negociá-la — mais descoberta determinística |
| Seleção da rota | Otimizador off-chain proprietário | Solver on-chain, reproduzível por qualquer pessoa a partir do estado público |
| Superfície de atualização | Proxy controlado por um administrador | Core sem estado; sem proxy, sem caminho de atualização, sem `selfdestruct` |
| Poder privilegiado sobre os fundos | Frequentemente presente | O Router não detém nada em repouso; nenhuma função move capital do utilizador |
| Consistência entre chains | Lógica de backend por chain | Um bytecode por chain |
| Pressuposto de confiança | A honestidade do operador | O mínimo do próprio utilizador, que o contrato se recusa a aceitar como zero |

A BlazePhoenix rejeita as duas metades do negócio. Recusa a superfície de integração linear mostrando que a superfície não é linear, e recusa a válvula de escape off-chain mantendo a decisão inteira — descoberta, cotação, pontuação, encaminhamento e liquidação — dentro de contratos que qualquer pessoa pode ler e que produzem a mesma resposta em todas as chains. O custo é real: cotar uma pool concentrada on-chain é mais caro do que lê-la de uma base de dados. O que esse custo compra é a eliminação de uma classe de falhas — a divergência silenciosa e impossível de provar entre o que um servidor prometeu e o que a chain entregou. Cada decisão de desenho que se segue é uma instância dessa troca.

## §2 A resposta e a disciplina

**A coisa que escolhe é a coisa que negoceia.**

O BlazePhoenix-Dex tem um ponto de entrada que recebe seis valores — os dois tokens, a quantidade, o teu mínimo, um destinatário, um prazo — e calcula a rota dentro da transação que a executa, a partir de reservas de pools que são estado público: que venues, quanto para cada um, por que ordem. Como a rota foi derivada de estado público por código público, qualquer pessoa a pode voltar a derivar. Como o número que vincula na liquidação é re-derivado pelo mesmo despachante, no mesmo quadro, a partir do mesmo estado vivo, a cotação e a execução não são dois artefactos a reconciliar; são uma só computação, e o que separa uma pré-visualização de uma execução é o tempo, não um segundo modelo.

Outros três pontos de entrada aceitam de calldata uma rota pré-calculada, para chamadores que querem o caminho mais barato e estão dispostos a fornecer a sua própria resposta; a mesma maquinaria de medição, piso e liquidação aplica-se às quatro portas (§11). Não afirmamos que a abordagem off-chain esteja errada, nem afirmamos ser mais baratos. Afirmamos uma classe diferente de garantia — auditável em vez de prometida — para o utilizador que a quer e que pagará gas por ela.

Quatro decisões neste desenho são, tanto quanto conseguimos apurar, invulgares na área, e cada uma é enunciada com o limite que a mantém honesta.

- **Os endereços são derivados, não obtidos.** Sempre que a implantação de uma família de venues seja reproduzível, o endereço de uma pool é calculado por aritmética CREATE2 — um teorema que qualquer pessoa pode reverificar a partir de três entradas públicas — em vez de lido do storage de uma factory; onde a aritmética não é sólida, o protocolo pergunta, e uma pool perguntada prova o seu próprio par antes de ser listada (§7).
- **O estado de encaminhamento de uma pool é uma palavra.** O Monoslot empacota tudo o que é preciso para classificar um venue num único slot de 256 bits e deliberadamente não contém preço, pelo que a memória do registo pode influenciar quais pools são consultadas, mas é estruturalmente incapaz de dar preço a uma troca (§8–§9).
- **O piso é re-derivado a partir da troca que realmente aconteceu.** O Router mede o impacto realizado de cada perna e a concentração realizada de cada hop dentro do quadro de execução e recalcula o seu piso a partir dessas medições, de modo que os campos fornecidos pelo chamador podem reforçar a proteção e nunca a relaxar (§11).
- **A descoberta é cega ao implantador onde os venues não têm endereços.** Para o singleton do Uniswap V4, os identificadores de pool são derivados de parâmetros públicos e depois provados vivos contra o storage do próprio manager — uma prova que mais ninguém consegue escrever (§5).

Nenhuma destas decisões elimina o resíduo que todo o agregador carrega — o estado pode mover-se entre a assinatura e a inclusão — e é por isso que o mínimo que defines tu próprio é obrigatório, e final: todas as portas recusam um mínimo zero com `RouterE(10)` antes de qualquer token se mover.

### §2.1 Desenho guiado por invariantes

Por trás da resposta há um método. Chamamos-lhe desenho guiado por invariantes: o protocolo é especificado não como uma sequência de operações, mas como um conjunto de propriedades que têm de se verificar em todos os estados alcançáveis, com o código organizado de modo a que essas propriedades sejam estruturais — impostas pela forma do código, não pela vigilância do programador.

A maioria do software é escrita de forma imperativa, e a correção é uma esperança emergente. Para o software comum isso é aceitável, porque as falhas são recuperáveis. Numa blockchain pública, nada disso se verifica: o código é imutável depois de implantado; custodia valor diretamente; executa-se num ambiente adversarial em que cada aresta é caçada; e um único deslize aritmético é uma perda irreversível, não um simples crash.

Um invariante é uma propriedade que é verdadeira independentemente da forma como o sistema chegou ao seu estado. *O Router não detém fundos entre transações.* *Um par do registo detém no máximo dezasseis pools, e a remoção mantém as dezasseis mais aptas.* *Uma liquidação que não pagou taxa de protocolo não existe.* Três princípios colocam essas afirmações no centro:

| Princípio | Enunciado | Onde aparece |
|---|---|---|
| Calcular, não confiar | Onde um valor possa ser derivado ou provado, nunca o obter nem o presumir. | 𝒟 calcula endereços de pools; o Router re-deriva no quadro a base da taxa e o piso a partir de saldos medidos. |
| Uma única fonte de verdade | Cada primitiva matemática é definida uma só vez e importada; nunca reenunciada. | O Core contém toda a matemática de preços, derivação, piso e pontuação; Hub, Solver, Router e Quoter importam-no e nenhum redefine uma primitiva. Um registo de quantidades partilhadas (§15) classifica cada quantidade que tem dois produtores. |
| Falhar fechado | Quando uma propriedade não pode ser garantida, parar em vez de prosseguir com um palpite. | O Solver não devolve rota em vez de devolver uma fabricada (`SolverE(5)`); o solver estável devolve zero em vez de uma cotação saturada (§6); a guarda de coerência do registo reverte um venue estruturalmente impossível antes de qualquer estado ser escrito (§9). |

Um quarto princípio rege a custódia: **nenhum caminho privilegiado para os fundos.** O Solver e o Quoter são contratos de caminho de leitura; o Router é o único contrato que move dinheiro, move-o atomicamente sob o limite do próprio utilizador, e todo o poder administrativo que o pudesse redirecionar pode ser renunciado de forma permanente através da Porta de Sentido Único (§14).

### §2.2 Porque é que esta disciplina se adequa a este meio

Cada propriedade do ambiente que torna perigoso o código imperativo é uma propriedade que o código guiado por invariantes transforma em vantagem. A imutabilidade recompensa a demonstrabilidade: o código implantado não pode ser corrigido, pelo que o valor de uma prova prévia é correspondentemente alto. A composabilidade recompensa uma única fonte de verdade: uma função de preço pode ser invocada dentro de um cofre que os seus autores nunca anteciparam e, com um só Core, todos os chamadores obtêm a mesma resposta. A adversarialidade recompensa o falhar fechado: um atacante só precisa de um caminho em que o autor não pensou, e um sistema que pára quando os seus pressupostos se quebram nega-lhe a improvisação. O valor em jogo recompensa a legibilidade: um protocolo expresso como cinco operadores nomeados sobre um núcleo matemático único pode ser verificado linha a linha por pessoas que não o escreveram.

A disciplina não é gratuita, e a troca é deliberada: provar um limite de overflow demora mais do que presumir que não existe; encaminhar cada produto por uma multiplicação-divisão de precisão total custa gas que uma multiplicação ingénua não custaria; derivar um endereço custa engenharia que obtê-lo dispensa. Isso é mais custo antes da implantação em troca de eliminar as falhas que não se podem recuperar depois dela.

### §2.3 Desenho Metrológico: um morfismo, coordenadas medidas, entradas monótonas

O desenho guiado por invariantes diz o que tem de se verificar sempre. Três regras adicionais dizem como é *moldado* o código que o garante, e em conjunto formam um método que não encontrámos nomeado noutro lado da área, pelo que este documento lhe dá nome: **Desenho Metrológico** — construir um contrato como um *instrumento*. A sua tese numa linha: *código que acredita é superfície de ataque; código que mede é defesa.*

**Um morfismo, avaliado num ponto.** O agregador não contém uma integração por venue; é a avaliação de um morfismo de preços parametrizado num ponto do espaço (forma do venue, chain, modelo de taxas). Expressa como ramos, meia dúzia de tipos de venue ativos, com as suas próprias convenções de taxa, multiplica-se em centenas de combinações aos pares — bytecode multiplicativo, superfície de auditoria multiplicativa, deriva multiplicativa. Expressa como morfismo, a mesma cobertura é um punhado de *formas de estado*, um Core sem estado, convenções de taxa transportadas nas suas unidades nativas e tabelas de registo — e o bytecode cresce de forma *aditiva*: um novo venue é uma linha, não um ramo. A regra que guarda o colapso é `KIND → SHAPE`: uma família de venues são *dados* — um tipo atribuído a uma forma existente e um modo de derivação — nunca um novo caminho de código que a entrada adversarial possa selecionar. O Core enuncia as formas como uma tabela de bits (`THETA_ATTR`, §4), de modo que “este tipo lê reservas?” é um deslocamento e um AND, e não há ramo por omissão que alguém possa esquecer. O colapso tem um travão: não existe uma fórmula universal única. Duas formas fechadas são avaliadas exatamente — produto constante e liquidez concentrada — e, para toda a curva em que a replicação seria um passivo, pergunta-se ao bytecode do próprio venue (§6). O morfismo colapsa a *pertença*, nunca a *verificação*.

**As coordenadas são medidas, nunca acreditadas.** O contrato nunca age sobre um valor modelado, nominal ou fornecido pelo chamador quando existe uma medição on-chain — e nenhum dado permissionless escolhe alguma vez que código corre. Os dados fornecidos por uma parte não confiável — uma rota, uma taxa declarada, uma profundidade alegada, um id de pool — são *coordenadas*: sítios para onde apontar o instrumento, que o contrato depois lê por si próprio, falhando fechado. Cada defesa essencial neste documento é uma instância: o saldo medido após o pull em vez da quantidade nominal (§11), a base da taxa tomada de uma variação de saldo medida em vez do calldata (§13), a banda de credibilidade ancorada numa mediana ponderada por profundidade de profundidades medidas em vez de num saldo bruto que uma doação pode inflar (§10), o limitador de capacidade cortado com base nas posições medidas (§10), a barreira de taxa V4 a ler estado vivo em vez de confiar num valor sentinela (§5), a descoberta por prova de existência a ler o storage do próprio singleton (§5), e uma pool perguntada a provar os seus próprios `token0`/`token1` antes de a descoberta a listar (§7). O repositório publica a classificação de todos os campos escrevíveis pelo chamador segundo esta regra: 23 campos, 14 confirmados contra uma observação, 5 de orientação, 4 declarados com a razão (§15).

**Onde a medição acaba, começa a monotonicidade.** Alguns números não podem ser medidos nem re-derivados — o piso de um chamador, a escala declarada de um chamador, o próprio mínimo do chamador. Para estes, o desenho aceita o número e molda a função de modo que mentir só possa prejudicar quem mente: o piso atestado da rota só pode *elevar* o piso aplicado (§11); a cotação atestada de uma perna é elevada à cotação medida quando fica aquém dela (§11); a escala declarada é limitada pela chegada medida, de modo que exagerá-la não pode encaminhar fundos que nunca existiram; e o único número que o protocolo não pode escolher — o teu mínimo — é obrigatório. Uma entrada monótona não precisa de confiança, pelo que pode ser calculada off-chain, por qualquer pessoa, gratuitamente, e transportada em calldata — que é como este protocolo move trabalho para off-chain *sem mover a confiança para off-chain*, e é por isso que o Router pode oferecer uma porta de resolução e três portas de calldata com as mesmas garantias.

O Desenho Metrológico rege também a engenharia em torno do artefacto, porque um instrumento só é tão bom quanto a sua calibração. As margens de segurança são fixadas a partir de perigos medidos: a barreira de divisão situa-se em 25 ppm porque o ponto de equilíbrio da perna medido era de 3 ppm (§10); um desconto de planeamento que pesava 27× mais do que o seu perigo medido foi retirado (§10). As comparações externas trazem as barras de erro do seu método ou não são apresentadas (§17). E o próprio aparelho de medição é medido: cada instrumento de garantia foi calibrado contra um defeito já conhecido por outra via antes de o seu número ser apresentado (§15). Essa é toda a teoria; o resto deste documento é a sua prática.

## §3 A Meta-Equação e o orçamento de dependências

O agregador inteiro pode ser lido como a maximização de uma única expressão. Dados um token de entrada $t_{\mathrm{in}}$, um token de saída $t_{\mathrm{out}}$ e uma quantidade $x$, o Solver procura entre as rotas admissíveis aquela que maximiza o valor líquido recebido, sujeita a um piso de viabilidade e a uma barreira anti-burla:

$$
R^{\star} \;=\; \mathrm{arg\,max}_{\;R \,\in\, \mathcal{R}_{\mathcal{D}}(t_{\mathrm{in}},\, t_{\mathrm{out}},\, x)} \;\; \mathrm{net}(R)\cdot\prod_{\ell\in R}\hat{\Psi}(p_{\ell})\cdot \mathbf{1}[\,\mathrm{net}(R) \ge \Phi(R)\,]\cdot \Xi(R)
$$
^e1

$$
\mathrm{net}(R) \;=\; \sum_{\ell\in R}\Omega(p_{\ell},\, x_{\ell})\;-\;f_{\mathrm{proto}}
$$

Aqui $\mathcal{R}_{\mathcal{D}}$ é o espaço de rotas sobre as pools localizadas pela Derivação Determinística 𝒟 e pelo registo; $\Omega(p_{\ell}, x_{\ell})$ é a saída do despachante para a perna $\ell$ que empurra $x_{\ell}$ pela pool $p_{\ell}$; $f_{\mathrm{proto}}$ é a taxa de protocolo; $\hat{\Psi}(p_{\ell})$ é a vitalidade normalizada da perna; $\Phi(R)$ é o piso Iron-Law para o impacto e a concentração medidos da rota; e $\Xi(R) \in \{0, 1\}$ é o projetor anti-burla.

| Operador | Nome | Papel na equação | Secção |
|---|---|---|---|
| Ω | Despachante Óctuplo | Dá preço a cada perna — um ramo por tipo de pool — e comunica uma profundidade denominada em tokens ao alocador de divisão | §4 |
| 𝒟 | Derivação Determinística | Localiza as pools que a rota usa, por endereço calculado onde a família o permite, por id de pool provado para o singleton V4 | §5, §7 |
| Φ | Piso Iron-Law | Projeta a rota sobre o conjunto viável: um piso sob a saída líquida, re-derivado no quadro de execução | §11 |
| Ψ | Campo de Vitalidade | Pondera cada pool pela qualidade conquistada, lida do seu estado on-chain empacotado | §9 |
| Ξ | projetor anti-burla | Atribui o valor exatamente zero a qualquer rota que não seja segura apresentar | §5, §14 |

A fatorização é deliberada. Ω responde a *quanto devolve uma pool*; Ψ responde a *quanto confiar nela*; Φ responde a *se a rota é admissível*; 𝒟 responde a *onde vive a pool*; Ξ responde a *se a rota é segura de mostrar*. A forma de produto significa que uma única perna falhada colapsa a pontuação da rota — uma perna que cota zero, ou uma pool sem crédito, anula o produto em vez de o descontar — e o indicador anula de forma rígida qualquer rota cuja saída líquida fique abaixo do piso. Sem penalizações suaves, sem pesos ajustáveis, sem nenhuma rota que falhe por pouco a passar às escondidas.

![FIG-1 — A Meta-Equação como pipeline do Solver: candidatos de 𝒟 e do registo, classificados e truncados por Ψ, cotados por Ω, repartidos pelas pernas, verificados contra Φ e Ξ; o Router reavalia Ω e Φ no quadro de execução.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-1.png)

On-chain, o Solver realiza a equação como um pipeline (`findBestRoutePlan`): os candidatos por par são reunidos pelo registo e, quando o registo não está atualizado, por 𝒟; classificados e truncados por Ψ até `MAX_CANDIDATES = 8`; sondados e cotados por Ω; filtrados por uma banda de credibilidade; repartidos pelas pernas; e a rota montada transporta o piso que Φ atesta. O Router reavalia então Ω e Φ sobre as quantidades que efetivamente chegaram. A afirmação que a equação faz — aquela a que um auditor pode submeter o código — é que nenhum passo desse pipeline consulta algo fora dos cinco operadores. Se uma quantidade não é argumento de um dos cinco, não pode influenciar a rota: nem o marketing de um venue, nem a reputação off-chain, nem a preferência do operador.

### §3.1 O orçamento de dependências

Em vez de adjetivos — *descentralizado*, *sem servidor*, *trustless* deixaram de transportar informação — eis a lista verificável: tudo o que tem de existir, e continuar a funcionar, para que uma troca seja liquidada.

| Dependência | Agregador típico resolvido off-chain | BlazePhoenix-Dex |
|---|---|---|
| Um serviço que calcula a rota | Obrigatório | Não usado — o Solver é uma função `view` que qualquer nó serve |
| Um oráculo ou feed de preços | Varia | Nenhum — não existe qualquer chamada a feed nos cinco contratos |
| Uma rede de solvers ou um leilão | Comum | Nenhum |
| Um keeper, cron ou relayer | Varia | Nenhum — a vitalidade decai por aritmética quando é lida a seguir; o registo aprende com a negociação corrente |
| Um proxy atualizável | Comum | Nenhum — sem proxy, sem `selfdestruct`, sem inicializador; os únicos `delegatecall` são os do próprio compilador para a biblioteca pública Core, fixados no momento do link |
| Uma interface alojada | Na prática, sim | Apenas por conveniência |

A última linha é onde a maioria dos orçamentos falha discretamente. A interface alojada é uma conveniência, não uma dependência: `swapBestExactIn` recebe seis valores que uma pessoa pode montar à mão, e um integrador, um script ou o front end de um concorrente pode chamá-lo sem qualquer relação connosco de qualquer espécie. Se todos os servidores que este projeto opera desaparecessem esta noite, os contratos cotariam, encaminhariam e liquidariam amanhã exatamente como hoje. O custo dessa propriedade é que o chamador paga a pesquisa em gas; o orçamento acima é a lista das coisas de que esse gas dispensa.

A imutabilidade corta também no outro sentido. Um defeito não pode ser corrigido — o preço de um contrato que se audita uma só vez — razão pela qual os defeitos são, em vez disso, divulgados e recompensados com bounties (§21).

### §3.2 Três limites

O orçamento tem três limites, enunciados junto da afirmação que delimitam. A interface é alojada, como a de toda a gente, e um front end comprometido é a maior exposição isolada no modelo de ameaças: o contrato respeita qualquer mínimo não nulo que lhe seja entregue, pelo que o mínimo que defines é o único limite que nenhuma interface te pode retirar. A descoberta de venues lê estado que transações anteriores escreveram — público e sem permissões, mas não conjurado no momento da troca. E os poderes administrativos existem até serem renunciados através da Porta de Sentido Único; após a renúncia, o nível de controlo — pausa, papéis, tesourarias, ligações, remoções — desaparece para sempre, e só resta o nível de curador que apenas cresce (§14). Core sem estado, operação sem servidor, governação que só cresce: a tabela é a afirmação; as palavras são a sua sombra.


## §4 O Despachante Óctuplo Ω

*Em linguagem simples:* uma função que sabe dar preço a todos os tipos de pool. *Com rigor:* `universalQuote(QuoteCtx, amountIn)` no Core é o despachante de cotação do Solver e da pré-visualização do Quoter; devolve a saída esperada e uma profundidade denominada em tokens para o alocador de divisão, e uma pool a que não consegue dar preço devolve zero e é descartada antes de se enviar fosse o que fosse. O Router avalia as mesmas primitivas do Core por perna no seu próprio quadro (`_hopScaleImpactAndQuote`), um congénere mantido por razões de gas e de profundidade da stack, e a Passagem Exata do Quoter põe ainda uma pergunta diferente (§12); as três estão registadas em conjunto no registo de quantidades partilhadas do repositório, e a sua concordância é fixada por testes nomeados em vez de presumida (§15). O nome de casa vem da enumeração de oito tipos com que o despachante foi lançado; entretanto a enumeração ganhou um nono membro e cedeu três a uma excisão deliberada. A numeração mantém as suas lacunas: um Monoslot registado ontem tem de se descodificar de forma idêntica para sempre.

### §4.1 Seis tipos, quatro famílias, uma tabela de atributos

| Tipo | Constante | Família | Ramo de preço | Atributos Θ | Escada de gas (Solver) |
|---|---|---|---|---|---|
| 0 | `KIND_V2` | Produto constante (Uniswap V2, Sushi, forks) | forma fechada `outV2` sobre `getReserves` | reservas · verificável por par | 90,000 |
| 1 | `KIND_V3` | Liquidez concentrada (Uniswap V3 e forks de forma V3) | forma fechada `outV3` sobre `slot0` | concentrada na pool · verificável por par | 110,000 |
| 4 | `KIND_V4` | Singleton do Uniswap V4 | forma fechada `outV3` sobre `extsload` | concentrada no singleton | 180,000 |
| 5 | `KIND_SOLIDLY` | Solidly (Aerodrome, Velodrome, forks), estável e volátil | perguntar à pool `getAmountOut`; curva replicada como fallback | reservas · verificável por par | 90,000 |
| 6 | `KIND_ALGEBRA` | Algebra (classe Camelot), taxa dinâmica | forma fechada `outV3` sobre `globalState` | concentrada na pool · verificável por par | 110,000 |
| 8 | `KIND_V4_NATIVE` | Pool V4 que detém a moeda nativa da chain | o mesmo ramo do tipo 4 | concentrada no singleton | 215,000 |

Seis tipos, quatro famílias operacionais: produto constante {0}, concentrada {1, 6}, Solidly {5}, e o singleton V4 {4, 8}. A coluna de atributos não é prosa: é a tabela de bits `THETA_ATTR = 0x040A9400A9` no Core, quatro bits por tipo — *lê reservas*, *concentrada no endereço da pool*, *concentrada no singleton*, *expõe `token0()`/`token1()`* — de modo que toda a questão de pertença nos cinco contratos (“este tipo lê reservas?”) é um deslocamento e um AND (`kindHas`, `kindHasAny`), e um tipo sem bits falha fechado, sem ramo por omissão que alguém possa esquecer. A coluna de gas é uma segunda tabela, `THETA_GAS`, lida apenas pelo `estGas` do Solver, em unidades de 5,000 gas por perna.

**Os tipos 2, 3 e 7 estão ausentes por excisão deliberada.** A família ponderada (3) nunca produziu uma cotação encaminhável. As duas famílias Curve (2, 7) funcionavam e foram removidas na mesma, no endurecimento da fronteira de confiança de agosto de 2026, porque suportá-las exigia o único `approve` de tokens do Router, o único valor de profundidade atestado por um chamador em vez de medido a partir de uma pool, e a única exceção na prova de autenticidade de pares do Hub — três superfícies de ataque, cada uma a última da sua classe. Os números retirados nunca são reatribuídos: `decodeKind` lê o tipo dos bits do Monoslot, pelo que reutilizar o 2 reinterpretaria todas as pools alguma vez registadas sob ele, e uma guarda de CI faz falhar a build se um símbolo excisado regressar.

**O tipo de moeda nativa (8) existe porque um invariante se quebra aí e em mais lado nenhum.** O pressuposto de trabalho do Router — todo o ativo é um ERC-20 com `balanceOf` — falha exatamente quando a moeda de uma pool V4 é o ativo nativo da chain, e codificar essa exceção como um *tipo* torna-a visível no registo da pool, transportada no plano da rota e pesquisável com grep por um auditor. O preço não precisa de ramo: o identificador da pool deriva das duas moedas ordenadas, e `address(0)` ordena-se primeiro por construção. O tipo ganha o seu lugar empiricamente: medido em 2026-08-13 nas chains servidas, 62.9 % da liquidez denominada em ETH dentro do V4 estava em pools nativas (Arbitrum 99.6 %, Optimism 95.0 %, Base 48.9 %).

### §4.2 As formas fechadas

**Produto constante.** As reservas satisfazem $x \cdot y = k$ e uma taxa $f$ em bps é retirada da entrada. O Core calcula

$$
y \;=\; \mathrm{outV2}(x,\, r_{\mathrm{in}},\, r_{\mathrm{out}},\, f) \;=\; \left\lfloor \frac{x\,(\mathrm{BPS}-f)\; r_{\mathrm{out}}}{\,r_{\mathrm{in}}\cdot \mathrm{BPS} \;+\; x\,(\mathrm{BPS}-f)\,} \right\rfloor
$$
^e2

sem qualquer divisão até ao passo final, pelo que o único arredondamento é o piso do último quociente, e uma taxa de `BPS` ou mais torna a pool incotável (devolve zero). A taxa que entra nesta fórmula é `effV2Fee(declared)`: uma taxa declarada de zero ou acima de `V2_FEE_CEILING_BPS = 100` é substituída pelos 30 bps canónicos, de modo que um registo não pode deflacionar a sua própria cotação — e com ela o piso que essa cotação ancora — declarando uma taxa inverosímil; a mesma regra é espelhada no caminho de execução, de modo que ambos os lados da troca dão preço com um só número.

**Exemplo resolvido 1 — uma cotação de produto constante.** Uma pool detém $r_{\mathrm{in}} = 1{,}000{,}000$ USDC e $r_{\mathrm{out}} = 500$ WETH aos 30 bps canónicos; um trader vende $x = 10{,}000$ USDC. Nas unidades da própria pool (o USDC tem 6 casas decimais, o WETH 18) $x = 10^{10}$, $r_{\mathrm{in}} = 10^{12}$, $r_{\mathrm{out}} = 5 \times 10^{20}$:

1. Entrada ajustada à taxa: $x(\mathrm{BPS}-f) = 10^{10} \times 9{,}970 = 9.97 \times 10^{13}$.
2. Numerador: $9.97 \times 10^{13} \times 5 \times 10^{20} = 4.985 \times 10^{34}$.
3. Denominador: $10^{12} \times 10^{4} + 9.97 \times 10^{13} = 1.00997 \times 10^{16}$.
4. Saída: $\lfloor 4.985 \times 10^{34} / 1.00997 \times 10^{16} \rfloor = 4.935790 \times 10^{18}$ wei, ou seja, **4.935790 WETH** (com seis casas decimais; o contrato arredonda o último quociente para baixo ao wei).

Ao preço spot de 0.0005 WETH por USDC, os mesmos 10,000 USDC obteriam 5 WETH; a execução fica 1.28 % abaixo do spot, dos quais 0.30 % são a taxa. A medida de impacto baseada em reservas do Core para esta perna é $\mathrm{impactV2Bps} = \lceil x \cdot \mathrm{BPS} / (r_{\mathrm{in}} + x) \rceil = \lceil 10^{14} / 1.01 \times 10^{12} \rceil = 100$ bps — o número que o piso Iron-Law consome na §11.

**Liquidez concentrada.** As pools de forma V3 não guardam reservas; guardam um preço em raiz quadrada $\sqrt{P}$ em vírgula fixa Q64.96 e uma liquidez ativa $L$. Dentro de um tick, para token0 → token1 com taxa $f$ em partes por milhão e $x_{f} = \lfloor x\,(10^{6} - f)/10^{6} \rfloor$:

$$
\sqrt{P}\,' \;=\; \frac{L\,\sqrt{P}}{\,L \;+\; x_{f}\,\sqrt{P}/Q_{96}\,},
\qquad
y \;=\; \frac{L\left(\sqrt{P}-\sqrt{P}\,'\right)}{Q_{96}}
$$
^e3

e para token1 → token0, $\sqrt{P}\,' = \sqrt{P} + x_{f} Q_{96}/L$ e $y = L\,Q_{96}(\sqrt{P}\,' - \sqrt{P})/(\sqrt{P}\,\sqrt{P}\,')$, com a divisão repartida em dois estágios. O cálculo ingénuo faz overflow: $L \cdot \sqrt{P}$ pode chegar a $2^{288}$. O Core nunca o forma — todo o produto é fatorizado através de um `mulDiv` de precisão total (intermédio de 512 bits, resultado de 256 bits), pelo que cada estágio cabe comprovadamente, e um passo que moveria o preço no sentido errado ou para zero devolve zero em vez de um número. As pools Algebra (tipo 6) partilham o ramo e diferem num aspeto que o ramo trata: o seu estado e a sua taxa dinâmica vivem em `globalState`, lido uma vez (§5.4).

A fórmula é exata dentro de um único tick e não é exata através das fronteiras de tick, onde a forma de tick único sobrestima. O despachante não replica a aritmética de travessia de ticks: replicar a matemática interna de um venue é um passivo estrutural, porque qualquer divergência entre cópia e original surge como uma cotação mal avaliada. Duas coisas ocupam o seu lugar. O Core transporta um limitador de fronteira (`sqrtBoundary`) que trunca o passo na aresta do intervalo atual — exato para o que cabe dentro do intervalo e estritamente abaixo para o resto, nunca acima — e o desenho coloca-o do lado da *promessa*, não da classificação, porque limitar apenas as famílias que têm ticks compararia venues sob duas convenções. Na árvore que este documento mede, o limitador está definido mas ainda não ligado: `Router._v4LegQuote` e o braço de classificação do Core chamam ambos a forma de tick único sem limitador, pelo que uma perna concentrada que sai do seu intervalo fica limitada apenas pelo piso por perna da §11.3 e pelo orçamento de hops, com o piso Iron-Law como salvaguarda. E na execução o piso Iron-Law é aplicado contra uma cotação que o Router re-deriva no quadro a partir das quantidades que efetivamente chegaram, pelo que uma sobrestimação na fronteira do tick custa a uma rota a sua exatidão de classificação, nunca ao utilizador o piso. A Passagem Exata do Quoter (§12) dá a um integrador o número da própria pool quando este o quer.

**Profundidade.** Cada ramo devolve também uma profundidade em unidades de token — o lado de reserva mais curto para as famílias de reservas (`shortSide18`), e, para as famílias concentradas, a reserva virtual $L/\sqrt{P}$ ou $L\sqrt{P}$ que $L$ representa ao preço atual (`depthFromL18`), de modo que uma pool V3 e uma pool V2 de igual profundidade se comparam como iguais no alocador, em vez de diferirem por um fator de $\sqrt{P}$.

### §4.3 Duas unidades de taxa, transportadas nativamente

Os venues de produto constante e Solidly cotam as taxas em bps; os venues concentrados, em partes por milhão. O despachante transporta cada uma na sua unidade nativa e nunca converte entre elas, o que elimina uma classe de falhas de arredondamento ao preço de duas constantes em vez de uma. Duas famílias de venues só conhecem a sua taxa no momento da execução — as pools V4 de taxa dinâmica e a Algebra — e ambas são tratadas medindo a taxa a partir da mesma leitura de estado que fornece o preço (§5.4).

### §4.4 Um despachante, duas superfícies

| Tipo | Pré-visualização do Quoter | No quadro (plano do Solver; re-derivação do Router) |
|---|---|---|
| V2 (0) | forma fechada `outV2` | forma fechada `outV2` |
| V3 / Algebra (1, 6) | forma fechada `outV3` sobre `slot0` / `globalState`; taxa viva da Algebra medida a partir da mesma leitura | o mesmo |
| Solidly (5) | perguntar à pool; curva replicada × 9,800 / 10,000 como fallback | o mesmo |
| V4 / V4-native (4, 8) | forma fechada `outV3` via `extsload`, barreira de taxa que falha fechado (E19) | o mesmo |

O que separa uma pré-visualização de uma execução é, portanto, o tempo: o estado que se moveu entre o bloco de pré-visualização e o quadro de execução. A §12 mede exatamente essa diferença em 240 amostras.

## §5 Uniswap V4 de ponta a ponta

O Uniswap V4 não é um novo contrato de pool; é uma nova forma de venue, e invalida quatro pressupostos em que assentam todos os routers construídos entre 2020 e 2024. As pools não têm endereços — são entradas no storage de um único singleton, indexadas por um hash. Corre código arbitrário dentro do swap — um hook executa em pontos definidos da liquidação que o router está a realizar. As taxas não têm de ser constantes. E as pools podem deter a moeda nativa da chain, que não tem `balanceOf`. Esta secção responde estruturalmente aos quatro, de modo que uma perna V4 é — para o Solver, para os pisos e para quem faz a troca — indistinguível de qualquer outra perna.

### §5.1 Localizar uma pool que não tem endereço: derivar, depois provar

A Derivação Determinística 𝒟 calcula endereços (§7), mas uma pool V4 não tem endereço para calcular. O que tem é um identificador — o hash keccak da sua `PoolKey` — pelo que o modo 9 da tabela de derivação deriva *poolIds* em vez de endereços, e depois faz algo que nenhuma derivação de endereços consegue: prova que a pool existe, lendo o próprio storage do PoolManager para esse id e exigindo um preço em raiz quadrada não nulo e uma liquidez não nula. Ninguém pode falsificar essa prova, porque ninguém a não ser o gestor escreve nesse storage. Um id fabricado resolve-se em zeros e é descartado.

**Exemplo resolvido 4 — um identificador de pool V4 a partir da sua chave.** O id canónico é $\mathrm{poolId} = \mathrm{keccak256}(\mathrm{abi.encode}(c_{0}, c_{1}, \mathrm{fee}, \mathrm{tickSpacing}, \mathrm{hooks}))$ (`computeV4PoolId`), cinco palavras de 32 bytes. Toma a pool ETH nativo / USDC na Base no escalão de 0.05 %: $c_{0} = \mathtt{0x0000…0000}$ (a moeda nativa ordena-se primeiro), $c_{1} = \mathtt{0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913}$ (USDC), fee $= 500$, tickSpacing $= 10$, hooks $= \mathtt{0x0}$.

1. `abi.encode` dispõe 160 bytes: as duas moedas preenchidas à esquerda até 32 bytes cada, depois `500`, depois `10` (um `int24`, com extensão de sinal até 32 bytes), depois o hook nulo.
2. $\mathrm{poolId} = \mathtt{0x96d4b53a38337a5733179751781178a2613306063c511b78cd02684739288c0a}$.
3. O campo `pool` do registo, numa linha V4, é formado pelos 160 bits inferiores do id, $\mathtt{0x781178a2613306063c511b78cd02684739288c0a}$ — um endereço sem código; por isso, às linhas V4 nunca se pede `token0()`, nunca se lê um saldo e, em vez disso, provam-se por re-derivação (§9).
4. A base de storage da pool é $\mathrm{keccak256}(\mathrm{abi.encode}(\mathrm{poolId}, 6)) = \mathtt{0x13a3a697…73b2893d}$: o slot 6 do gestor é o mapping `pools`. O Core lê a palavra 0 nesse slot e a palavra 3 em $\mathrm{base} + 3$ (`v4SqrtAndLiq`, seletor `extsload(bytes32)` = `0x1e2eaeaf`).
5. A palavra 0 empacota $\sqrt{P}$ nos bits [0, 160), o tick em [160, 184), a taxa de protocolo em [184, 208) e a taxa de LP em [208, 232); a palavra 3 contém a liquidez ativa nos seus 128 bits inferiores. Se $\sqrt{P}$ ou $L$ for zero, a pool não existe para este protocolo.

A variante encapsulada do mesmo par — $c_{0} = \mathtt{0x4200…0006}$ (WETH), mesmo escalão — tem o id $\mathtt{0x90333bb0…ebd943a0}$: uma pool diferente com uma profundidade diferente, razão pela qual o varrimento sonda ambas as chaves e sonda primeiro a nativa (abaixo). A disposição do passo 5 não é tirada da documentação: a mesma pool, lida através desta disposição e através do contrato canónico `StateView`, devolve os mesmos números num fork da mainnet, e essa identidade é o que o comentário do Core cita.

**A escada de custos.** O varrimento que produz os ids candidatos é uma escada, com o degrau mais barato primeiro, porque uma passagem ingénua por todas as combinações de taxa e espaçamento seria uma fatura de gas inaceitável no caminho de resolução:

| Degrau | O que tenta | Custo quando acerta |
|---|---|---|
| 1 | O padrão de escalão já aprendido para este par de tokens | uma sondagem — o caminho em regime estacionário |
| 2 | Uma verificação de proveniência antes de pagar um varrimento a frio | uma leitura |
| 3 | Os escalões canónicos do Uniswap, agrupados através de `extsload(bytes32[])` | uma chamada para o lote |
| 4 | Os pares `(fee, spacing)` que a linha de registo declara | limitado pelo registo |
| 5 | A grelha geradora de arranque a frio — taxa $= 10{,}000\,j$, espaçamento $= 100\,j$, $j$ a descer a partir de `V4_GRID_MAX = 99` | no máximo `V4_GRID_PROBES = 40` sondados |

O varrimento inteiro termina ao atingir `V4_CAP = 8` pools provadas. Duas propriedades decorrem da construção e não de uma verificação: uma pool com hook nunca pode ser emitida por este varrimento — ele deriva ids *sem hook*, e o id sem hook de uma pool com hook não existe no gestor, pelo que falha a prova de vida antes de se colocar qualquer questão de política — e ids duplicados vindos de palpites de escalão diferentes colapsam num só candidato, pelo que uma pool não consegue saturar o funil por aliasing. A ordem de sondagem é, ela própria, uma política, porque o limite é gasto por aquilo que for sondado primeiro: um par contra o ativo nativo da chain tem duas chaves no V4, nativa e encapsulada, e a chave nativa foi medida como a mais profunda nas chains servidas quando a ordenação foi decidida (3.76× na Base, 292× na Robinhood Chain), pelo que é sondada primeiro.

![FIG-2 — A escada V4 de derivar e provar: cinco degraus, do padrão de escalão aprendido à grelha geradora limitada, cada id candidato provado como vivo contra o storage do gestor antes de contar para o limite de oito; ids com hook nunca existem neste caminho.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-2.png)

**A porta sem permissão.** Qualquer pessoa pode chamar `claimV4(c0, c1, fee, tickSpacing)` e fazer admitir uma pool sem hook, porque a reivindicação traz a sua própria prova: o id é recalculado a partir da chave submetida e lido de volta do storage do gestor, pelo que uma reivindicação falsa se resolve em zeros e não admite nada (`HubE(9)`). Três condições adicionais servem de barreira à porta: um dos lados do par tem de ser uma moeda-ponte encaminhável, para que um lugar no registo limitado nunca seja gasto num par que o router nunca consegue atravessar; a taxa efetiva tem de ser cotável sob a barreira de taxa mais abaixo; e a reivindicação tem de superar a mesma margem de admissão que supera um registo desencadeado por um swap (§9), com a liquidez medida da pool como a sua profundidade. O registo pode ser ensinado pelo público e não pode ser enganado por ele.

### §5.2 Ler uma pool que não responde a chamadas

Com um id provado como vivo, o despachante precisa de preço e de liquidez — e não há `slot0()` para chamar. O Core lê diretamente o storage do singleton por `extsload`, como no exemplo acima, e o ramo V4 reduz-se à forma fechada de liquidez concentrada da §4.2: a mesma matemática, a mesma disciplina de overflow. O singleton muda onde o estado vive, não o que o estado significa. Um gestor sem código ou não conforme produz palavras todas a zero — falha fechado, nunca uma reversão.

### §5.3 Liquidar com um singleton

A execução inverte o fluxo de controlo habitual. Em vez de chamar uma pool e ser chamado de volta para pagar, o Router chama `unlock` no gestor e realiza o swap inteiro dentro do callback que o gestor lhe concede: swap, depois liquidar cada moeda devida através de `sync → settle → take`, depois libertar o bloqueio. As moedas em trânsito atravessam a fronteira do unlock em transient storage (`TSLOT_V4IN`, `TSLOT_V4OUT`), pelo que o quadro não suja nenhum estado persistente e o contexto está comprovadamente vazio entre swaps. O `BalanceDelta` que o gestor devolve vem empacotado — `amount0` nos 128 bits superiores, `amount1` nos inferiores — e o Router descodifica-o como tal antes de correr qualquer aritmética de liquidação.

A moeda nativa mantém o invariante que importa. O Router é canónico em WETH em todo o lado — o valor nativo que entra em `swapExactInNative` é encapsulado exatamente uma vez à porta, e o output nativo deliberadamente não está implementado: o destinatário recebe WETH, que nenhum caminho consegue prender silenciosamente. Uma perna V4 nativa desencapsula *no último instante* dentro do seu próprio quadro de unlock — `WETH.withdraw`, depois `settle` com valor, sendo o ETH recebido de um `take` nativo re-encapsulado no mesmo quadro — pelo que o ETH nativo nunca existe em repouso no contrato. A única superfície nova que isto exigiu é um `receive()` com uma barreira tão estreita quanto o requisito permite: um slot transitório (`TSLOT_ETHOK`) guarda o único endereço autorizado a enviar ETH em bruto para o Router nesse instante — o contrato WETH canónico durante o desencapsulamento, o PoolManager durante um take nativo, zero em qualquer outro momento — pelo que ETH simples enviado por qualquer outro remetente reverte. A porta nativa falha fechado até `weth` estar ligado (`RouterE(3)`).

### §5.4 A taxa que só existe no momento da execução

Uma pool V4 de taxa estática traz a sua taxa de LP na chave, onde é imutável. O gestor de pools pode, além disso, cobrar a taxa de gestor do próprio Uniswap — limitada a 1,000 pips, um décimo de um por cento, por sentido — que o braço estático do Core não acrescenta, pelo que uma cotação sobre uma chave estática pode sobrestimar o output entregue até ao montante dessa taxa de gestor, assim que o controlador de taxas do Uniswap a ativar (é zero em todas as chains servidas à data da redação); o défice cai dentro do piso, e a base da taxa, por ser medida, ignora-o. Uma pool de taxa dinâmica traz, em vez disso, o sentinela `0x800000`, e a sua taxa real vive em `slot0`. Cotar o sentinela pelo valor facial trataria a troca como gratuita, enquanto a execução pagaria a taxa em vigor. A barreira consiste em três linhas no Core (`effV4Fee`):

$$
f_{\mathrm{eff}} \;=\; \begin{cases} f_{\mathrm{key}} & f_{\mathrm{key}} \ne \mathtt{0x800000} \\ \mathtt{0xFFFFFF}\ (\text{unquotable}) & f_{\mathrm{key}} = \mathtt{0x800000} \ \wedge\ f_{\mathrm{proto}} \ne 0 \\ f_{\mathrm{LP}}\ \text{read from } \mathtt{slot0} & \text{otherwise} \end{cases}
$$
^e19

Uma chave de taxa dinâmica acompanhada de uma taxa de protocolo não nula devolve uma taxa igual ou superior a $10^{6}$, e `outV3` devolve zero para ela: falha fechado, porque a composição das taxas de protocolo e de LP não está ancorada a nosso contento, e a taxa de protocolo medida na Base à data da redação é zero, pelo que o ramo não custa nada na prática. A mesma regra fecha a mesma costura na família vizinha: as pools Algebra são de taxa dinâmica por construção e registam o sentinela zero, pelo que `quoteV3Fee` toma como verdade uma taxa configurada não nula, a taxa de uma pool dinâmica a partir da leitura de `globalState` que já forneceu o seu preço, e — para forks de liquidez concentrada cuja taxa é indexada pelo espaçamento de ticks e vive na pool — a própria `fee()` da pool, falhando fechado em `0xFFFFFF` quando nada responde. As pools V3 estáticas não fazem nenhuma leitura extra e cotam de forma idêntica byte a byte.

Resta uma costura, que é limitada e não removida: um hook de taxa dinâmica pode substituir a sua taxa em cada swap dentro de `beforeSwap`, pelo que a taxa guardada em `slot0` não é em todos os casos a executada. Esse resíduo é contido pela lista de permissões de hooks do Hub na admissão e pelo piso Iron-Law re-derivado do output realizado na execução, pelo que uma substituição hostil resulta numa reversão ou num défice dentro do piso, nunca numa execução abaixo do piso (§14).

### §5.5 Hooks: filtrados por aritmética, nunca por interrogação

Um hook é código arbitrário a correr dentro da liquidação que o Router está a realizar. A defesa intuitiva — perguntar ao hook o que pretende fazer — não é uma defesa, porque um hook hostil mente ou reentra. A BlazePhoenix nunca pergunta nada a um hook. Em vez disso, há três camadas independentes, a mais barata primeiro, e a §14 desenvolve-as: os bits de permissão do hook vivem nos catorze bits inferiores do seu próprio endereço, fixados na implantação, e os dois bits que permitem alterar os deltas do swap são recusados por um único AND antes de qualquer token se mover (`hookAltersDeltas`, `RouterE(9)`); um hook só é encaminhável enquanto estiver na lista de permissões e enquanto o seu código de runtime ainda corresponder ao codehash fixado na admissão (`isHookLive`); e o projector Ξ remove um hook que altera deltas do conjunto de candidatos do Solver antes da classificação, pelo que a rota nunca chega sequer a ser representável. O resíduo é declarado juntamente com o mecanismo: um hook na lista de permissões e livre de deltas ainda pode reverter a meio do swap e desperdiçar o gas da tentativa — o preço de recusar, por princípio, chamar código não confiável para descobrir o que ele teria feito.

### §5.6 O que vale a integração

Cada mecanismo acima é ou uma primitiva do Core já usada noutro lado, aplicada a uma nova disposição de estado, ou uma primitiva genuinamente nova que se generaliza para lá do V4 — a descoberta por prova de existência. Nada é uma integração por pool, e nada é uma lista curada que um humano tenha de manter atualizada. As pools V4 são descobertas sem diretório, provadas contra um storage em que mais ninguém consegue escrever, com o preço dado pela mesma forma fechada que qualquer outro venue concentrado, sujeitas à barreira de taxa por medição, com uma recusa que falha fechado onde a medição não é exata, filtradas contra hooks hostis por aritmética imutável de endereços, liquidadas através do próprio protocolo de bloqueio do singleton, e alcançáveis em ETH nativo sem que o Router guarde um único wei dele em repouso. A §17 traz as medições: no censo de factories na Arbitrum, a família V4 ganha mais pares de hop do que qualquer outro venue registado, e na Optimism o censo registou aquilo que é, tanto quanto sabemos, a primeira agregação encaminhada pelo V4 dessa chain. Não conhecemos nenhum outro agregador público que derive pools V4, as prove, lhes dê preço, as filtre e as liquide inteiramente dentro da transação em execução, ETH nativo incluído, sem lista curada de pools; se encontrares um, a afirmação está errada e gostaríamos de saber.

## §6 O solver Solidly

Alguns invariantes não têm uma forma fechada suficientemente simples para serem reproduzidos com segurança, e reproduzi-los é exatamente o risco de replicação que o protocolo recusa noutros pontos. Para esses venues, o despachante pergunta à pool, pelo canal honesto mais estreito que o venue expõe — e mantém uma réplica de reserva para os forks que não respondem.

A família Solidly — Aerodrome, Velodrome e os seus forks — serve ativos correlacionados em pares estáveis com um invariante quártico que adere à diagonal muito mais estreitamente do que o produto constante, sem deixar de admitir divergência:

$$
k(x, y) \;=\; x^{3}y \;+\; x\,y^{3} \;=\; x\,y\left(x^{2}+y^{2}\right)
$$
^e5

Perto do ponto de equilíbrio, esta curva entrega quase todo o input como output — slippage mínimo exatamente onde se concentra o fluxo de stablecoins e de liquid staking. Os pares Solidly voláteis são de produto constante, e o braço volátil do Core *é* `outV2` — um só produtor, que a relação metamórfica MR7 fixa (§15).

![FIG-3 — Output em função do input para um par estável equilibrado: a quártica Solidly contra o produto constante e a diagonal de slippage zero, a partir das próprias fórmulas do Core.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-3.png)

**Caminho principal: perguntar à pool.** `getAmountOut(amountIn, tokenIn)` é calculado pelo próprio bytecode do par — taxa em vigor, curva e arredondamento incluídos — pelo que um swap que peça exatamente esse valor satisfaz por construção a verificação do invariante da pool, e não é precisa nenhuma margem. O gatilho do fallback é uma resposta de no máximo 1 wei, alinhado entre os três canais que perguntam (Solver, Router, Quoter) depois de, numa ocasião, uma pool que respondeu exatamente 1 ter enviado dois deles por ramos diferentes.

**Fallback: replicar, depois pedir menos.** Quando um fork não expõe o seletor, o despachante lê a taxa em vigor na factory do par (`getFee(pool, stable)`; uma taxa de fallback declarada só é aceite dentro do mesmo teto de 100 bps do braço V2, caso contrário 30 bps), resolve o invariante sobre reservas normalizadas em casas decimais e multiplica o resultado por 9,800 / 10,000 — um desconto de 200 bps para que o arredondamento da pool, que a réplica não consegue observar, tenha sempre folga. O desconto aplica-se apenas no fallback e nunca quando a pool respondeu por si própria.

**A resolução.** Dados o saldo de entrada pós-troca $x$ e o invariante alvo $K$ obtido das reservas pré-troca, o Core procura a raiz de $f(y) = x^{3}y + xy^{3} - K$, com $f'(y) = x(x^{2} + 3y^{2}) > 0$, por iteração de Newton com semente $y_{0} = Y$, a reserva oposta pré-troca (`_solY`):

$$
k(x, y_{n}) < K:\ \ y_{n+1} = y_{n} + \max\!\left(1,\ \left\lfloor \tfrac{K - k(x,y_{n})}{f'(y_{n})} \right\rfloor\right); \qquad
k(x, y_{n}) \ge K:\ \ y_{n+1} = y_{n} - \delta_{n},\ \ \delta_{n} = \begin{cases} \lfloor y_{n}/2 \rfloor & d_{n} \ge y_{n} \\ \max(1, d_{n}) & \text{otherwise} \end{cases},\ \ d_{n} = \left\lfloor \tfrac{k(x,y_{n}) - K}{f'(y_{n})} \right\rfloor
$$
^e6

A semente que parece natural — a aproximação de soma constante — está errada de uma forma que corrompe os preços silenciosamente: para uma pool que absorve um input várias vezes maior do que a sua reserva, cai muito acima da raiz, numa região onde $f$ é extremamente íngreme, o passo arredonda por defeito para zero, e o solver fica preso num número confiante, plausível e incorreto. Usar como semente a reserva oposta e dar passos em ambos os sentidos converge tanto para pools equilibradas como para pools fortemente desequilibradas. Um passo descendente que atravessaria zero é substituído por metade do iterado; cada passo força pelo menos uma unidade de progresso; a iteração termina quando iterados sucessivos diferem, no máximo, numa unidade e assenta no lado seguro para o invariante por um ajuste final de uma unidade contra o tomador. O ciclo está limitado a 64 iterações e o limite falha fechado: o solver devolve a própria semente, que a guarda $y \ge Y$ do chamador converte numa cotação zero — a pool é tratada como impossível de cotar, em linha com o modo como o próprio Aerodrome recusa em vez de dar um preço errado. Uma derivada que se anula segue a mesma saída.

**Normalização de decimais.** O invariante é homogéneo de grau quatro; por isso, quando ambos os tokens têm o mesmo número de casas decimais, a escala cancela-se e as reservas em bruto funcionam diretamente. Um par como DOLA (18 casas decimais) contra USDC (6) leva o desajuste para a quártica, pelo que o Core escala ambos os lados para uma base comum de $10^{18}$ antes de resolver e desfaz a escala depois:

$$
X = r_{\mathrm{in}}\cdot 10^{\,18-d_{\mathrm{in}}},\quad Y = r_{\mathrm{out}}\cdot 10^{\,18-d_{\mathrm{out}}},\quad A = \left\lfloor\frac{x\cdot 10^{\,18-d_{\mathrm{in}}}\,(\mathrm{BPS}-f)}{\mathrm{BPS}}\right\rfloor,\quad \mathrm{out} = \left\lfloor\frac{Y - y^{\star}(X+A,\,K)}{10^{\,18-d_{\mathrm{out}}}}\right\rfloor
$$
^e7

Os tokens que declaram mais de dezoito casas decimais cotam zero em vez de provocarem underflow no escalamento. As casas decimais do outro token são lidas da pool, não tiradas do chamador — uma primitiva de produtor único que aceitasse a coordenada do seu chamador reabriria a divergência que existe para fechar.

**Falha fechado em todo o domínio.** Quatro guardas decidem se a curva chega sequer a ser avaliada, e cada uma devolve zero em vez de reverter, porque uma reversão dentro de uma cotação é um `DELEGATECALL` de biblioteca que desfaz o plano inteiro do Solver para o par: $X$ e $Y$ não podem exceder $3.4 \times 10^{38}$; $X + A$ também não; e `_solKFits` exige que tanto o invariante $k = xy(x^{2}+y^{2})/\mathrm{WAD}^{3}$ como a derivada $x(x^{2}+3y^{2})/\mathrm{WAD}^{2}$ caibam numa palavra de 256 bits na semente, que é o maior ponto que Newton visita. Esse último teste é feito sem divisão — calcula a palavra superior do produto de 512 bits e compara-a com um WAD (`_mulFitsWad`) — porque a forma anterior, $a \le \max \cdot \mathrm{WAD} / b$, ela própria entrava em overflow numa pool que detinha menos de uma unidade de um token. A via de N versões da §15 encontrou essa fuga em 2026-09-05; a correção é 35 bytes mais pequena do que o código que substituiu e entrou com um teste escrito primeiro a vermelho, com um fuzz de 5,000 execuções sobre todo o domínio, um varrimento de 60,000 amostras da mesma aritmética em Python, e três mutantes na guarda.

**O resíduo medido, e a margem de 200 bps.** A réplica foi medida contra pools Aerodrome em produção, com o próprio `getAmountOut` da pool como verdade de referência:

| Pool | Estado | Verdade de referência | Output do Core | Desvio |
|---|---|---|---|---|
| USDC / USDbC | equilibrado (6 / 6 dec) | 999,534,071 | 999,534,071 | 0.000 % |
| DOLA / USDC | desequilibrado (18 / 6 dec) | 985,528,437 | 987,998,286 | 0.251 % |
| USDz / USDC | desequilibrado (18 / 6 dec) | 899,325,141 | 901,565,830 | 0.249 % |

O par equilibrado coincide até à unidade; os pares desequilibrados ficam dentro de 0.5 %, por excesso, porque o arredondamento do saldo pós-taxa da pool é invisível do exterior. É esse resíduo que explica por que razão o fallback pede 200 bps a menos: a margem garante que a verificação do invariante do par tem folga na execução, convertendo uma possível reversão por sobrecotação numa execução certa, e é aplicada de forma idêntica nas superfícies de pré-visualização e dentro do quadro, para que as duas se mantenham em sincronia. A via do oráculo canónico da §15 limita a curva de forma independente: contra uma implementação escrita a partir da especificação do venue, a cotação estável do Core fica dentro de 4 wei em 5,000 inputs gerados por fuzz.

## §7 Derivação Determinística 𝒟

Antes de uma pool poder ser cotada, tem de ser encontrada. A resposta da indústria é perguntar: uma chamada à factory do venue lê um mapping de storage e devolve um endereço, e o chamador fia-se na palavra da factory. A BlazePhoenix suporta essa resposta — quatro modos de chamada à factory cobrem os venues cujas implantações não são reproduzíveis — e prefere uma mais forte sempre que a aritmética o permite: calcular o endereço, sem nenhuma chamada externa. Um endereço calculado pode ser verificado por qualquer pessoa com os mesmos três dados de entrada; um endereço consultado só pode ser aceite por confiança.

O mecanismo é o CREATE2. A EVM torna o endereço de um contrato uma função pura do seu implantador, de um salt e do hash do seu init code:

$$
\mathrm{pool} \;=\; \mathrm{addr}_{20}\!\left(\mathrm{keccak256}(\mathtt{0xff}\,\Vert\,\mathrm{origin}\,\Vert\,\mathrm{salt}\,\Vert\,\mathrm{initCodeHash})\right)
$$
^e8

onde $\mathrm{addr}_{20}$ toma os últimos vinte bytes do hash. O Core escreve a pré-imagem de 85 bytes exatamente uma vez (`create2Address`); `deriveAddress` seleciona o polinómio de salt e a origem a partir do modo, e a derivação Algebra atestada do Hub reutiliza o mesmo produtor.

| Modo | Família | Resolução | Salt / detalhe da sondagem |
|---|---|---|---|
| 0 | V2 | chamada à factory `getPair(t0,t1)` — seletor `0xe6a43905` | — |
| 1 | V3 / Algebra | chamada à factory `getPool(t0,t1,fee)` — `0x1698ee82`; se falhar, `poolByPair(t0,t1)` — `0xd9a641e1` | — |
| 2 | Solidly | chamada à factory `getPool(t0,t1,stable)` — `0x79bc57d5` | — |
| 3 | Forks Solidly concentrados (Slipstream, Velodrome CL) | chamada à factory `getPool(t0,t1,tickSpacing)` — `0x28af8d0b` | — |
| 4 | V2 CREATE2 | aritmética pura | `keccak256(packed(t0,t1))`, origem = factory |
| 5 | V3 CREATE2 | aritmética pura | `keccak256(encode(t0,t1,fee))`; `fee == 0` é o sentinela Algebra → `keccak256(encode(t0,t1))`, origem = o `poolDeployer()` da factory (`0x3119049a`), atestado na admissão |
| 6 | Clone Solidly CREATE2 | aritmética pura | `keccak256(packed(t0,t1,stable))`, origem = factory |
| 7 | CL CREATE2 | aritmética pura | `keccak256(encode(t0,t1,tickSpacing))`, origem = factory |
| 8 | *retirado* | libertado pela excisão do Curve; uma lápide — `MODES_VALID = 0x2FF` recusa-o | — |
| 9 | V4 por derivação e varrimento | derivar poolIds sem hook e provar que estão vivos no PoolManager (§5.1) | grelha ≤ 99 escalões, ≤ 40 sondados a frio, parar em 8 pools |

Os modos 0–3 são um `staticcall` cada; os modos 4–7 são zero chamadas e exigem apenas o init-code hash correto; o modo 9 serve a única família cujas pools não podem ser localizadas de nenhuma das duas formas.

**Um teorema, uma afirmação e uma prova.** Um endereço derivado é um teorema sobre o par: dados a origem, o polinómio de salt e o init-code hash, o endereço decorre apenas do keccak, e qualquer pessoa que o conteste pode recalculá-lo. Um endereço consultado é uma afirmação de uma factory sobre o seu próprio storage — e uma factory pode responder com uma pool de outros tokens. Desde 2026-09, uma pool consultada (modos 0–3) prova o seu próprio par antes de a descoberta a listar: o Hub lê o seu `token0()` e o seu `token1()` — as mesmas duas leituras que o Router faz na costura que paga — e uma discrepância descarta o candidato, pelo que uma pool que o executor recusaria nunca é listada, planeada nem classificada. Foi a matriz de venues hostis da §15 que mudou isto: a sua primeira execução listou uma pool que uma factory admitida por um curador devolveu como resposta, o planeador classificou-a, e o executor recusou-a na costura que paga — fundos nunca em risco, o par recusado enquanto o impostor ganhava a divisão.

**Duas subtilezas nas linhas em forma de V3.** O Algebra (classe Camelot) cobra uma taxa dinâmica, pelo que uma taxa nunca pode fazer parte da sua identidade: um registo Algebra declara a taxa zero como sentinela, o modo 5 retira a taxa do salt, e a origem CREATE2 é o contrato `poolDeployer` separado que as factories Algebra expõem. Essa origem é o único dado de entrada da derivação que uma factory ainda poderia controlar depois da admissão — um proxy muda a sua resposta com o codehash intacto — pelo que o Hub a atesta uma vez em `addFactory` (`factoryDeployer`) e deriva a partir da origem atestada daí em diante; depois da renúncia ao controlo, a atestação fica congelada. Do lado das chamadas à factory, as factories Algebra expõem `poolByPair` em vez de `getPool`, pelo que uma consulta no modo 1 que não devolve nada tenta de novo com esse seletor antes de desistir.

**Cada derivação passa por uma última barreira.** O Hub descarta qualquer endereço derivado que não tenha bytecode de runtime — `extcodesize` é toda a verificação (`hasCode`) — pelo que um init-code hash errado, um registo desatualizado ou uma chain onde uma família nunca foi implantada não produzem nada, em vez de um venue fantasma. Bytecode no endereço prova existência, não honestidade, e é por isso que a admissão, a banda de credibilidade e os pisos continuam a interpor-se entre uma pool localizada e uma troca executada. A mesma pool derivada sob várias combinações `(fee, spacing)` é listada uma só vez.

**A fronteira entre derivar e perguntar é empírica.** Os venues baseados em clones, como o Velodrome e o Aerodrome, ficam na chamada à factory, embora o seu init-code hash seja conhecido, porque a sua origem CREATE2 vive dentro de um implantador interno de clones determinísticos e não na factory — o endereço não é reproduzível a partir de dados públicos, pelo que o protocolo pergunta. O Uniswap V3 é o caso emblemático no sentido oposto: o seu init-code hash é uma só constante em todas as chains porque o mesmo bytecode de pool é implantado em todo o lado, e a identidade `derived == getPool` verifica-se em forks de Ethereum, Arbitrum, Optimism e Base contra as próprias factories de cada chain (§17). Derivar onde a aritmética é sólida, perguntar onde não é, e verificar tudo de qualquer das formas.

**A descoberta consome a tabela linha a linha.** Para cada uma das no máximo `MAX_FACTORIES = 16` factories registadas, o Hub sonda todas as combinações `(fee, spacing)` declaradas — as linhas Solidly nas variantes estável e volátil, uma linha V4 a reservar até oito — pelo que o pior caso do varrimento é fixado pelo registo, não pelo humor da chain. A superfície de configuração está guardada à porta (§9): um venue estruturalmente impossível não pode ser armazenado.

## §8 O Monoslot

O storage é o custo dominante de fazer seja o que for na EVM: um `SLOAD` a frio custa 2,100 gas, e um registo que espalhasse os atributos de uma pool por slots separados pagá-lo-ia de novo por cada atributo, por cada pool, em cada rota avaliada. A BlazePhoenix empacota todo o estado de encaminhamento de uma pool numa única palavra de 256 bits — o Monoslot — lida uma vez e descodificada por aritmética pura.

| Bits | Campo | Largura | Significado |
|---|---|---|---|
| 0 | `active` | 1 | o slot está ativo |
| 1–7 | reservado | 7 | bit 5 = curva estável (lido do próprio `stable()` da pool no registo); bit 6 = lado nativo invertido; bit 7 era antes a flag de ponte, já não é escrito — o bónus de ponte é lido em direto do par (§9) |
| 8–31 | `fee` | 24 | escalão de taxa, na unidade nativa do venue |
| 32–39 | `kind` | 8 | tipo de venue (§4) |
| 40–47 | `tier` | 8 | 0 = curado (semeado por um operador), 2 = sem permissão (aprendido por negociação ou reivindicado) |
| 48–59 | `conc` | 12 | campo de concentração, mascarado para `0xFFF` antes do empacotamento |
| 60–63 | `bucket` | 4 | bucket logarítmico de profundidade |
| 64–95 | `lastUpdateTs` | 32 | marca temporal de relógio do último toque |
| 96–127 | `emaIn` | 32 | reservado para uma EMA do volume de entrada; escrito como zero no registo, não atualizado pelo tick em produção |
| 128–159 | `emaOut` | 32 | reservado para uma EMA do volume de saída; como acima |
| 160–191 | `swapCount` | 32 | contagem de atividade, saturando em $2^{32}-1$ |
| 192–223 | `regBlk` | 32 | bloco de registo |
| 224–255 | `lastBlk` | 32 | bloco do último toque |

![FIG-4 — Disposição dos bits do Monoslot: uma palavra de 256 bits, catorze campos com nome, o campo de concentração mascarado para doze bits para nunca poder transbordar para o bucket de profundidade.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-4.png)

A codificação é uma sequência de deslocamentos e ORs (`encodeSlot`):

$$
s \;=\; a \;\vert\; f\!\ll\!8 \;\vert\; k\!\ll\!32 \;\vert\; r\!\ll\!40 \;\vert\; (c \wedge \mathtt{0xFFF})\!\ll\!48 \;\vert\; b\!\ll\!60 \;\vert\; t\!\ll\!64 \;\vert\; e_{\mathrm{in}}\!\ll\!96 \;\vert\; e_{\mathrm{out}}\!\ll\!128 \;\vert\; n\!\ll\!160 \;\vert\; B_{\mathrm{reg}}\!\ll\!192 \;\vert\; B_{\mathrm{last}}\!\ll\!224
$$
^e9

Um detalhe é uma guarda, não uma conveniência: o campo de concentração é mascarado para doze bits *antes* do deslocamento, pelo que nunca pode transbordar para o bucket de profundidade nos bits [63:60] — o empacotamento proíbe a classe de sobreposição silenciosa de campos que corrompe estado empacotado, em vez de confiar que os chamadores se mantêm dentro do intervalo. A descodificação é igualmente mecânica: cada acessor é um deslocamento e uma truncagem; a rotina que escreve o bucket limpa os seus quatro bits antes de os definir; a contagem de swaps satura em vez de dar a volta, pelo que um slot cheio nunca pode fazer o histórico de uma pool movimentada voltar a zero. A marca temporal de relógio, carimbada pelo Hub em cada tick e em cada registo, comanda tanto o decaimento de vitalidade da §9 como a barreira de frescura de descoberta do Solver.

Repara no que a palavra não contém: um preço. O Monoslot traz tudo o que é preciso para classificar uma pool — atividade, classe de profundidade, taxa, tipo, flags, recência — e nada que possa ser confundido com uma cotação, pelo que a memória do registo é estruturalmente incapaz de dar preço a uma troca. Os preços são calculados de fresco, a partir das reservas em direto, dentro do quadro que negoceia com base neles; a palavra empacotada nunca faz mais do que decidir que pools vale a pena consultar. O caminho de atualização respeita a mesma economia: um swap através de uma pool conhecida reescreve a palavra uma vez — contagem, bucket, marcas temporais, um `SSTORE` sobre um `SLOAD` — pelo que o custo marginal de manter o registo atualizado viaja dentro de transações que os utilizadores já estavam a enviar.

Porque é que uma só palavra importa é uma questão de multiplicação. O Solver sonda até `MAX_CANDIDATES = 8` venues por par em até três topologias, pelo que uma única troca resolvida pode pontuar umas duas dezenas de pools antes de mover um token. A 2,100 gas por slot a frio, uma disposição de cinco slots por pool põe o custo dessa passagem de pontuação nas centenas de milhares de gas; o Monoslot põe-no numa leitura por pool, e o `psisOf` do Hub devolve a pontuação de cada candidato numa única chamada agrupada. O Monoslot não é uma otimização aplicada ao encaminhamento on-chain; é a razão pela qual o encaminhamento on-chain tem sequer um custo comportável.

## §9 O Registo Auto-Regenerável e o Campo de Vitalidade Ψ

A maioria dos agregadores conhece os seus venues porque um keeper indexa pools off-chain e publica listas on-chain — um processo que exige confiança, uma janela de desatualização e uma dependência operacional, três coisas que um protocolo que resolve rotas on-chain não pode aceitar. A BlazePhoenix assume a posição oposta: o registo aprende a liquidez negociando-a.

### §9.1 Aprender negociando, e a prova do par

Em cada perna executada, o Router chama o `recordSwap` do Hub (`onlyRouter`, `whenLive`), passando a pool, o seu tipo, a sua taxa, o par, os montantes e a profundidade que mediu. O Hub começa por recusar qualquer tipo que o Router não pudesse ter executado (`KINDS_EXECUTABLE`) — uma defesa local que não depende de o Router continuar a ser o que era na implantação — e depois segue um de dois caminhos.

O Monoslot de uma pool conhecida é atualizado: a contagem de swaps sobe a partir da sua base *atualmente decaída*, o escalão de profundidade é recalculado, o bloco e o timestamp de relógio avançam — uma palavra compactada reescrita, nenhuma chamada externa. Uma pool desconhecida segue o caminho frio. Tem primeiro de passar na admissão (`_canInsert`, mais abaixo). Depois tem de provar a afirmação que está prestes a guardar: para cada tipo em forma de par (`KINDS_PAIR_PROOF` = V2, V3, Solidly, Algebra), o Hub lê o `token0()` e o `token1()` da própria pool e exige que correspondam ao par — no máximo duas chamadas `staticcall`, e apenas no caminho frio. Cada argumento de `recordSwap` é calldata controlado pelo chamador e transportado na rota do Router — pool, tipo e profundidade —, pelo que, sem esta prova, um atacante regista um contrato que ele próprio escreveu, sob um par que ele escolheu, com uma profundidade que ele escolheu, sem deter nenhum dos dois tokens. Para os dois tipos V4, cujo campo `pool` é um id truncado sem bytecode, a prova é a re-derivação: o espaçamento de ticks é recuperado e o id é recalculado e comparado, só sem hook, pelo que uma pool com hook nunca se pode registar por esta porta; uma pool V4 nativa é comparada nas duas orientações de `(address(0), T)`. Uma discrepância *salta* o registo e nunca reverte, porque o swap do utilizador já foi liquidado e nunca pode falhar por causa de uma decisão do registo.

A prova do par no registo é nova em setembro de 2026, e a medição que a originou é a da §15: quinze mutações do código-fonte foram corridas contra todos os invariantes com estado, e o mutante que removia esta prova sobreviveu a todas as campanhas na primeira execução, porque nenhum teste tinha alguma vez oferecido ao Hub uma pool que negociasse outros tokens. A campanha do Hub fá-lo agora em cada execução — o par invertido, um token partilhado, dois alheios — e `invariant_ActiveEntriesTradeThePair` lê o `token0`/`token1` de cada entrada ativa; o mutante é uma entrada de guarda que esse invariante elimina. A descoberta transporta a mesma prova para as pools consultadas (§7).

Não há indexador para correr nem nenhum momento em que o protocolo fique cego porque um servidor está em baixo. Uma porta de operador, `seedPool`, pré-povoa pares na implantação (nível 0, curado) e uma porta sem permissão, `claimV4`, admite pools V4 sem hook mediante a sua própria prova (§5.1); ambas são otimizações, não dependências — um registo vazio regenera-se até ficar povoado através da negociação comum.

### §9.2 O score

O Campo de Vitalidade Ψ separa a qualidade da capacidade, lendo apenas o Monoslot e o estado atual de ponte do par (`psi` do Core):

$$
\Psi(s, t) \;=\; V(s, t)\cdot 2^{\,b(s)} \cdot \left(1 + \tfrac{2{,}500}{10^{4}}\,\mathbf{1}_{\mathrm{bridge}}\right)\cdot\left(1 + \tfrac{500}{10^{4}}\,\mathbf{1}_{\mathrm{conc}}\right)
$$
^e10

O escalão de profundidade $b = \min(15, \lfloor \log_{10}(d / 10^{15}) \rfloor)$ entra através do seu peso $2^{b}$: cada ordem de grandeza de profundidade duplica o peso, pelo que a profundidade conta de forma sublinear — uma pool profunda é firmemente favorecida, mas uma pool apenas saudável não é apagada por uma gigante. Uma pool num par ponte ganha +25 %, porque as pontes são o tecido conjuntivo do grafo de liquidez; uma pool concentrada ganha mais +5 %. O bónus de ponte é lido em direto a partir do par por um único produtor (`_pairBridged`), e não a partir de um bit congelado no registo, e dentro de um par é uniforme, pelo que nunca pode reordenar pools do mesmo par.

**O decaimento — um só mecanismo.** A atividade decai com a inatividade segundo uma única regra de relógio (`_decayedSwapCount`):

$$
V(s,t) \;=\; \mathrm{swapCount}(s) \;\gg\; \left\lfloor \frac{t - t_{\mathrm{last}}}{24{,}576\ \mathrm{s}} \right\rfloor, \qquad V = 0 \ \text{once the shift exceeds } 31.
$$
^e11

O passo é `VITALITY_DECAY_STEP_SECONDS = 24,576` — cerca de 6.8 horas — e trinta e duas reduções para metade extinguem qualquer score, pelo que uma pool silenciosa chega a zero, e pode ser plenamente expulsa, ao fim de 786,432 s, cerca de 9.1 dias. Um único swap reanima-a, e a reanimação é honesta: a contagem retoma a partir do que o decaimento deixou de pé, nunca do total anterior ao decaimento, pelo que um único swap de dust depois de um longo silêncio não pode restaurar a posição acumulada de uma pool. A função de score mantém dois zeros separados: um slot *morto* — vazio, nunca atualizado, ou para lá do horizonte — tem um score verdadeiramente zero e sai da classificação, enquanto um slot *vivo* cuja contagem pequena apenas desapareceu por arredondamento com o deslocamento recebe o mínimo de um, pelo que uma pool real, tocada recentemente, nunca desaparece por um artefacto de arredondamento. A janela está deliberadamente em segundos de relógio: uma janela contada em blocos significa uma duração real diferente em cada chain, e uma implementação anterior que deslocava a cada 16 blocos decaía até zero cerca de 128× mais depressa do que o documentado.

![FIG-5 — Decaimento da vitalidade: uma contagem de 4,096 reduz-se a metade a cada 24,576 s e chega a zero ao fim de 32 passos; um swap no dia 4 reanima-a a partir da base decaída, não do total histórico.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-5.png)

### §9.3 Expulsão

Cada par contém no máximo `MAX_SLOTS = 16` pools. Quando uma décima sétima quer entrar, o Hub calcula o score de cada titular pelo Ψ completo — profundidade, bónus e tudo o resto, pelo que uma recém-chegada profunda pode desalojar uma ocupante rasa mas ativa — e só admite a recém-chegada se o seu score projetado superar o da titular mais fraca por uma margem (`_canInsert`):

$$
\Psi_{\mathrm{new}} \;>\; \Psi_{\mathrm{worst}} + \left\lfloor \Psi_{\mathrm{worst}}/4 \right\rfloor, \qquad \Psi_{\mathrm{new}} = 2^{\,b(d_{\mathrm{new}})}
$$
^e13

sendo a recém-chegada pontuada de forma conservadora — vitalidade um, o seu próprio escalão de profundidade, sem bónus — e uma recém-chegada de profundidade zero recusada de imediato. A margem fecha um vetor de griefing: com uma simples regra de desalojar a mais baixa, um adversário poderia manter dezasseis slots rasos mal ativos e deixar de fora uma concorrente profunda; com a classificação por Ψ e uma margem, a pool genuinamente mais profunda continua a ganhar. O limite da constante é declarado onde é imposto: o peso da recém-chegada é uma potência de dois, enquanto o score da titular é contínuo, pelo que a margem efetiva vai de cerca de 100 % (uma titular logo acima de um) até cerca de 25 % (uma titular em 51, menor recém-chegada admissível 64); os 25 % da regra são também o piso do comportamento, abaixo do qual nunca se desce. Uma titular muito negociada é difícil de desalojar até que o decaimento faça o seu trabalho — dois dias inativos custam-lhe sete reduções para metade. Uma reivindicação V4 sem permissão tem de superar a mesma margem, com a liquidez medida da pool como profundidade.

### §9.4 A descoberta, e o seu regulador de gas

A descoberta é uma função view pública: para qualquer par, o Hub percorre a sua lista de factories, deriva candidatos pelos modos da §7, aplica `hasCode` e a prova do par, e o Solver junta o resultado ao conjunto registado, deduplicado por endereço, pelo que nenhuma das fontes pode suprimir a outra. Para limitar o gas, o Solver aplica uma barreira de frescura (`_registryFresh`): quando pelo menos `MIN_FRESH_VENUES = 3` venues registados *curados* do par foram tocados dentro de `DISCOVERY_TTL_SECONDS = 3,600`, confia no registo e salta a varredura de derivação. Só as linhas curadas (nível 0) podem servir de garantia: uma linha sem permissão é escrita por quem fez swap primeiro, e contá-la permitia que três pares de dust autorregistados, mantidos frescos por três swaps de dust por hora, desligassem a descoberta para um par e escondessem todos os venues honestos nunca registados. A linha sem permissão continua a ser candidata; já não escolhe o caminho. A barreira é um regulador de gas e de cobertura, e nunca um parâmetro de segurança — o piso Iron-Law e o mínimo do utilizador protegem cada execução, por mais desatualizado que o registo esteja, porque nenhum dos dois lê sequer o registo.

### §9.5 A superfície de configuração

As portas de registo do Hub são guardadas à entrada. `addFactory` rejeita, antes de qualquer estado ser escrito (`HubE(5)`): um tipo fora de `KINDS_ROUTABLE`; um modo fora de `MODES_VALID`; um modo CREATE2 com init-code hash zero; um slot de salt V2 associado a algo que não o tipo V2; um slot de clone associado a um tipo que não Solidly; um slot de salt V3 associado a algo que não V3 ou Algebra, sendo exigido a um registo Algebra que declare todas as taxas como a sentinela zero; e uma linha V4 derive-scan associada a qualquer tipo que não V4 ou com listas de taxas e de espaçamentos mal emparelhadas. Uma factory conhecida é atualizada no próprio lugar e nunca recebe uma segunda linha, pelo que um endereço não pode esgotar os dezasseis lugares (`HubE(4)`); depois da renúncia ao controlo, uma factory cujo código runtime mudou não pode ser rearmada, e uma linha de derivação não pode ser convertida numa linha de consulta. `allowHook` fixa o codehash do hook na admissão, e um hook só é encaminhável enquanto estiver na lista de permissões *e* inalterado (`isHookLive`); depois da renúncia, a remoção da lista deixa de existir e um hook que mudou fica em pausa para sempre. As pontes são no máximo `MAX_BRIDGES = 3`; `addBridge` é um poder de curador que sobrevive à renúncia, `removeBridge` um poder de controlo que morre com ela.

### §9.6 A fronteira estrutural

Uma frase limita tudo o que ficou acima: **Ψ pode esconder um venue; nunca lhe pode dar o preço errado.** O score classifica e trunca o conjunto de candidatos — nenhuma cotação, nenhum piso e nenhuma alocação o leem, porque são calculados a partir de medições feitas dentro da transação; a memória só chega à seleção da rota por omissão. Seja o que for que o registo acredite, o pior que pode trazer à superfície é um preço atual pior mas real, e o valor que esse preço pode deixar passar é limitado pelo mais estrito entre a banda de credibilidade, o piso Iron-Law re-derivado dentro do quadro e o mínimo que o utilizador definiu. O capital está fora de alcance por construção. O registo decide o que é visto; não tem voto sobre o que é pago.

## §10 O encaminhamento e o Alocador de Divisão

Uma pool de produto constante dá preço segundo uma regra: as suas duas reservas, multiplicadas, nunca podem diminuir. Coloca $\Delta$ na pool com uma retenção de taxa $\gamma$ (uma taxa de venue de 0.30 % significa $\gamma = 0.997$) e recebes $y\,\gamma\Delta / (x + \gamma\Delta)$, com o teu próprio input no denominador: quanto mais empurras através de uma pool, pior paga cada token adicional. O slippage é aritmética, e a sua cura também: dividir a mesma ordem por pools do mesmo par move menos cada pool.

**Exemplo resolvido 2 — uma divisão por duas pools.** Uma ordem de 100 contra duas pools do mesmo par, ambas a 0.30 %: a pool A tem 1,000 de cada lado, a pool B tem 4,000 de cada lado.

| Rota | Aritmética | Recebes |
|---|---|---|
| Todos os 100 em A | $1{,}000 \times 99.7 / 1{,}099.7$ | 90.661 |
| Todos os 100 em B | $4{,}000 \times 99.7 / 4{,}099.7$ | 97.275 |
| 20 em A, 80 em B | $1{,}000 \times 19.94 / 1{,}019.94 \;+\; 4{,}000 \times 79.76 / 4{,}079.76$ | $19.550 + 78.201 = 97.751$ |

A divisão 20 / 80 é escolha do próprio alocador, não um palpite: os pesos são proporcionais à profundidade medida face à candidata mais profunda — A pesa $1{,}000/4{,}000 = 2{,}500$ em 10,000, B pesa 10,000 — pelo que A fica com $2{,}500 / 12{,}500 = 20$ % da ordem. A divisão bate a melhor pool única em 0.476 tokens, 48.9 bps do seu output. A barreira de divisão pergunta então se esse ganho justifica a segunda perna: o limiar é $97.275 \times (1 + 25 / 10^{6}) = 97.278$, e 97.751 supera-o, pelo que a divisão se mantém. Cada linha pode ser verificada com uma calculadora, e o efeito acumula-se: o impacto no preço é a resposta de cada pool à *sua própria* fatia, pelo que cada perna admissível acrescentada a uma rota move menos cada pool.

![FIG-6 — Output em função da parte enviada para a pool profunda no exemplo de duas pools: uma curva côncava com o máximo perto de 80 %, com o ponto proporcional à profundidade escolhido pelo alocador assinalado.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-6.png)

### §10.1 Formas de rota e orçamentos

O Solver constrói três topologias e devolve a que maximiza (`findBestRoutePlan`, com a segunda melhor como alternativa): uma rota *direta* num hop; uma rota com *ponte* através de um intermediário; uma rota com *ponte dupla* através de dois — três hops, a forma mais profunda que o Solver constrói e o máximo que o Router aceita (`MAX_HOPS = 3`). Cada hop divide-se em pernas paralelas sob dois orçamentos deliberadamente separados: `MAX_LEGS_PER_STAGE = 4` responde a *quantas pernas cabem num hop*, `MAX_LEGS = 11` responde a *quantas cabem numa rota*, e juntos dão 4, 4 + 4 e 4 + 4 + 3 — o último hop de uma rota de três hops fica com três porque o teto global o aperta, não porque alguém tenha escrito um caso especial. As pontes vêm de um conjunto, configurado pelo operador no Hub, de no máximo três tokens; o Solver expande todas as pontes configuradas e deixa o `totalOut` medido decidir, em cada troca. Uma rota cujo impacto medido exceda `MAX_ROUTE_IMPACT_BPS = 9,000` não é de todo devolvida, e um par sem rota admissível recusa com `SolverE(5)` em vez de fabricar uma. O Router impõe o seu próprio limite de cinco pernas por hop em qualquer rota fornecida pelo chamador (`MAX_LEGS_PER_HOP = 5`, `RouterE(3)`).

### §10.2 O funil

Para cada par, o Solver reúne as pools registadas e, a menos que o registo esteja fresco (§9.4), as descobertas; remove qualquer pool cujo hook altere deltas (o projector Ξ, aplicado aqui para que a porta com planeamento nunca possa montar uma rota que o Router recusaria); classifica a união por Ψ numa única chamada agregada e mantém `MAX_CANDIDATES = 8` — deliberadamente mais do que o orçamento de pernas de qualquer hop, para que uma pool profunda listada atrás de vários venues finos seja vista, ponderada e possa desalojá-los, em vez de ficar de fora por causa da ordem da lista. Um empate exato em Ψ desempata a favor da taxa mais baixa, pelo que, com um registo frio, o funil é função do preço e não do histórico.

Cada candidato é então sondado uma vez, a um centésimo da ordem (`amountIn / 100`, ou a ordem inteira quando isso arredonda para zero), captando a sua taxa marginal e a sua profundidade na mesma chamada. As taxas marginais separam com nitidez dois sinais que as taxas de troca a tamanho total confundem: uma pool com preço desatualizado tem uma taxa marginal errada qualquer que seja o tamanho, enquanto uma pool pequena mas saudável tem uma taxa marginal correta e apenas um output fraco a tamanho total. Para os tipos em forma de par, a profundidade declarada é limitada pelo que a pool detém fisicamente do token de saída, pelo que um par sintético que declare $3 \times 10^{30}$ detendo um token de cada lado é ponderado pelo que detém.

### §10.3 A banda de credibilidade

Antes da alocação, os candidatos têm de ser credíveis, e a credibilidade tem de estar ancorada numa quantidade que custe algo a falsificar. O centro da banda é a **mediana ponderada pela profundidade** das taxas marginais dos sobreviventes (`_depthWeightedMedian`): as taxas são ordenadas com as respetivas profundidades a acompanhá-las, e a mediana é a taxa em que metade da *massa de profundidade* foi ultrapassada. O seu ponto de rutura é 50 % da massa — para a mover, um atacante tem de superar em profundidade metade da liquidez real do par — e as profundidades que pondera são `getReserves` para pools de reservas, a liquidez ativa para pools concentradas e a liquidez medida para V4: quantidades que uma simples doação a uma pool não move. Esta última propriedade é a razão pela qual a âncora não é o maior saldo real: uma transferência para uma pool infla `balanceOf` sem mover a reserva nem o preço e é recuperável pelo doador, pelo que não é capital em risco — um investigador externo demonstrou a captura da anterior âncora de saldo através de uma doação, e a âncora foi substituída. Os candidatos cuja taxa marginal se afaste do centro mais de `MEDIAN_FILTER_BPS = 500` (±5 %) são descartados antes de qualquer envio; um conjunto de um só candidato não é de todo filtrado, e um conjunto cujo centro arredonde para zero recorre à mediana simples, para que um hop de outro modo encaminhável não seja eliminado por um artefacto de arredondamento. A largura é uma escolha calibrada: as curvas Solidly estáveis que cotam pares de liquid staking ficam tipicamente a 20–40 % da taxa verdadeira e são excluídas; uma pool saudável cuja leitura para este tamanho de troca difere um pouco do centro é admitida. A faixa metamórfica da §15 mediu a banda a partir de fora: com uma pool com preço $10^{10}$ afastado do da sua irmã, o plano paga 35 % menos do que a pool aberrante sozinha — a mediana a recusar acreditar nela.

### §10.4 O alocador e as suas três guardas

Os pesos são proporcionais à profundidade medida, normalizados face à maior profundidade do conjunto (`_weights`) — uma só normalização, sem modos, porque a profundidade de cada família é denominada em tokens (§4.2) e, portanto, comparável. A alocação proporcional é a escolha robusta para um ambiente adversarial: não precisa de iteração nem de um modelo de curvatura por venue, e evita a falha catastrófica que uma divisão uniforme produz — num caso WETH/USDC medido, dividir 50 / 50 entre uma pool de 790 WETH e uma pool de dust com 0.34 WETH devolveu 1,302 USDC, quando concentrar na pool profunda devolveu 1,638; a alocação ponderada pela profundidade devolveu 1,638. Quando o funil contém mais sobreviventes do que o orçamento do hop, mantêm-se os melhores sobreviventes *por peso*, até ao orçamento, pelo que uma pool profunda listada tarde desaloja pools finas listadas cedo. Três guardas ficam então entre a alocação e a rota em que ela se torna.

- **O limitador de capacidade.** A fórmula de liquidez concentrada de tick único modela a liquidez do tick atual como se abrangesse todos os preços, pelo que, numa pool fina, pode prometer mais do que a pool alguma vez deteve — 117× mais num caso observado. Uma perna concentrada num venue em forma de pool (tipos 1 e 6) é, por isso, limitada a `MAX_CONC_DRAIN_BPS = 3,000` — 30 % — do saldo real *medido* da pool no token de saída. O limitador não chega às pernas V4: o singleton guarda os tokens de todas as pools num só saldo, pelo que o Solver salta a leitura para os tipos 4 e 8, e uma promessa V4 não tem limite físico para além do piso da §11.3 — o piso é o seu limite. O limitador tem dois níveis: quando a cotação excede tudo o que a pool detém, a promessa é fisicamente impossível, e o limitador corta o *input comprometido* da perna na mesma proporção, passando em cascata o input libertado para as pernas restantes e deixando tudo o que não for encaminhável para ser devolvido ao chamador; quando a execução é agressiva mas possível, só a promessa é limitada, porque se mediu que cortar capital nesse caso força execuções parciais em pools que executam bem. As fórmulas limitadas por reservas não podem prometer demais e ficam intactas. Este limitador lê `balanceOf` deliberadamente, onde a banda não o faz: a banda faz uma pergunta *relativa* que uma doação pode enviesar, o limitador faz uma pergunta *física* — esta pool consegue pagar isto? — e uma doação aumenta aquilo que a pool consegue realmente pagar.
- **A barreira de divisão.** Cada perna extra custa gas real, e o alocador deliberadamente não contém nenhum termo de preço do gas, porque comparar gas no token nativo com output no token da troca exigiria exatamente o oráculo de preços que o protocolo se recusa a ter. O substituto sem oráculo é um limiar: uma divisão só é mantida se $\mathrm{out}_{\mathrm{split}} \ge \mathrm{out}_{\mathrm{single}} \cdot (1 + 25/10^{6})$ — `MIN_SPLIT_IMPROVEMENT_PPM = 25` —, caso contrário a alocação colapsa numa só perna. O limiar é um número medido: o verdadeiro ponto de equilíbrio entre o gas de uma perna e a sua melhoria mediu 3 ppm na Base (320 bytes de calldata por perna extra a 105.5 gas por byte), e a barreira fica a cerca de oito vezes isso, denominada em partes por milhão porque um quarto de ponto base não existe em pontos base; o seu histórico — 20 bps, depois 5, depois 0.25 — é o registo de dois valores que nunca tinham sido calibrados face a uma medição. Quando a barreira colapsa uma rota, mede dois candidatos de perna única a tamanho total em vez de um — a pool mais profunda e a melhor taxa marginal — porque as taxas marginais favorecem as pools rasas, enquanto a profundidade é o indicador da capacidade de levar o tamanho todo; ganha a melhor execução.
- **Seguro por medição, não por margem.** Um desenho anterior cortava 5 bps a cada perna das rotas mais longas no momento do planeamento, como seguro contra a deriva entre pernas. A deriva foi depois medida em nove pares da Base no mesmo bloco: pior caso −2 bps, uma ordem de grandeza abaixo do seguro, que todas as rotas honestas com várias pernas pagavam em cada troca — 27× o seu risco medido. O corte foi retirado; os pisos, impostos sobre o output realizado, suportam esse risco com custo de planeamento zero. A medição foi feita numa janela calma e o contra-argumento está registado no código-fonte: se a prudência alguma vez for restaurada, o lugar certo é o piso, que é verificado, e não a estimativa, que apenas classifica.

A rota montada transporta o que o Router vai re-derivar: o input comprometido e o output esperado de cada perna, o impacto da rota ponderado pelas partes, e o piso Φ que o Solver atesta a partir da mesma aritmética que o Router impõe (§11). O Solver também dá preço à execução de cada perna, por tipo, a partir da escada `THETA_GAS` e publica o total como `estGas`, um valor indicativo que a rota transporta e que nada on-chain lê. A regra prática do leitor sobrevive sem alteração a toda esta maquinaria: compara a melhoria que o router afirma com o gas que a tua carteira mostra, antes de confirmares.

## §11 A camada de execução e o piso Iron-Law Φ

O Solver propõe; o Router dispõe — de forma atómica, ou de modo nenhum. O Router é o único contrato que move fundos, não guarda nenhuns entre transações e assenta num princípio: um mecanismo por responsabilidade, aplicado universalmente. Não presume nada que possa medir.

### §11.1 Quatro portas, um executor

| Porta | Assinatura (abreviada) | Autorização | Rota |
|---|---|---|---|
| `swapExactIn` | `(route, amountIn, userMinOut, recipient, deadline)` | `approve` + `transferFrom` clássicos | a partir do calldata |
| `swapExactInWithPermit2` | `(route, amountIn, userMinOut, recipient, deadline, permit, signature)` | transferência por assinatura Permit2 num só passo, através do contrato Permit2 canónico; sem aprovação permanente para o Router | a partir do calldata |
| `swapExactInNative` | `(route, userMinOut, recipient, deadline)` payable | valor nativo, encapsulado uma vez na porta; falha fechado até `weth` estar ligado (`RouterE(3)`) | a partir do calldata |
| `swapBestExactIn` | `(tokenIn, tokenOut, amountIn, userMinOut, recipient, deadline)` | clássica | resolvida dentro do quadro pelo Solver (`findBestRoutePlan`) e depois executada através de uma auto-chamada, com o pagador passado explicitamente |

Só `swapBestExactIn` invoca o Solver na transação; as outras três recebem a rota que o chamador calculou off-chain, gratuitamente, através do Quoter (§12). As quatro convergem num único executor privado (`_execute`), pelo que todas as verificações abaixo correm em todas as portas. Uma conta delegada EIP-7702 chama as mesmas portas que um contrato chamaria; não existe nenhuma entrada separada para ela.

Duas recusas correm antes de qualquer coisa se mover. Um mínimo zero é recusado em todas as portas — `RouterE(10)`, sem exceções, sem flag de compatibilidade — porque o mínimo é o único limite que o contrato não pode calcular em nome do utilizador, e uma guarda que pode estar ausente não é uma guarda. E uma rota com mais de três hops, mais de cinco pernas num hop, ou um hop cujo token de entrada não seja o output do hop anterior é recusada com `RouterE(3)`: a continuidade dos hops é o que torna conhecido o saldo “alheio” anterior ao swap de cada token intermédio, pelo que uma rota forjada não pode indicar um token encalhado como o seu input e escalar para dentro do swap todo o saldo que o Router tem desse token.

### §11.2 Medição, desde a primeira instrução

Seja qual for a porta usada, a primeira coisa que o Router faz é medir o que chegou: lê o delta do seu próprio saldo depois de puxar os fundos, em vez de confiar no montante nominal, pelo que um token que entrega a menos na transferência entra na rota com o seu tamanho verdadeiro. As linhas de base nascem uma só vez: o saldo do token de entrada antes do swap (`baseIn`) e o do token de saída (`toutStart`) são tirados à entrada, e cada medição posterior é um delta face a eles, pelo que os tokens que já estavam no contrato — dust, doações, tokens encalhados por histórias não relacionadas — ficam excluídos do que um swap pode pagar. Uma rota que consiga gastar abaixo da sua própria linha de base falha na aritmética verificada — o desfecho seguro, já que esses fundos nunca foram deste swap para gastar.

Uma rota de vários hops é um plano, e os planos encontram a realidade em cada fronteira entre hops. O Router reescala as pernas de cada hop face ao saldo que *efetivamente* chegou — o hop 0 face ao input medido depois de puxar os fundos, limitado pelo que a rota comprometeu (para que o Router nunca empurre à força uma ordem previamente cortada para dentro de uma pool fina); cada hop seguinte face ao saldo medido do token ponte acima da sua linha de base alheia — executando cada perna $\mathrm{amt} = \mathrm{amountIn}_{\mathrm{leg}} \cdot \mathrm{real}/\mathrm{planned}$ (`_hopScaleImpactAndQuote`). Uma perna escalada para zero é saltada; o input não gasto e os resíduos de ponte são devolvidos ao pagador, nunca ao Router. A mesma passagem lê uma vez o estado da pool de cada perna e produz, a partir dessa única leitura, o montante escalado da perna, o seu impacto medido e a sua cotação dentro do quadro — as três quantidades que os pisos consomem — pelo que as famílias de reservas e concentrada não pagam nenhuma `staticcall` extra pela sua medição.

### §11.3 Três pisos sob cada perna

**O piso por perna.** A contribuição medida de cada perna para o saldo de saída do Router tem de atingir `LEG_FLOOR_BPS = 8,000` — 80 % — do seu limite, ou o swap inteiro reverte com `RouterE(5)` (`_execScaled`), pelo que uma única pool alvo de sandwich ou manipulada faz falhar a transação de imediato, em vez de esconder a sua perda dentro de um total de resto saudável. O limite é a cotação atestada pelo chamador, pro rata ao montante efetivamente gasto — *elevada* à cotação medida dentro do quadro sempre que a atestação cubra menos de `MIN_QUOTE_COVERAGE_BPS = 5,000` desta. Isto é um máximo, não um mínimo, de propósito: num piso, `min(claimed, measured)` com uma afirmação deflacionada devolve a deflacionada e relaxa, que é o ataque que a barreira fecha. A guarda corre sempre que existe alguma base de piso — a atestação do chamador ou a cotação dentro do quadro — pelo que escrever zero numa rota já não desliga o piso do próprio chamador. A sua limitação: um venue sem cotação mensurável e sem atestação passa para os pisos agregados e para o mínimo do utilizador, que o limitam de qualquer forma.

**O piso agregado por hop.** O piso por perna é local, enquanto a composição é global: um atacante que detenha uma perna de entre $L$ poderia extrair cerca de $20\,\% \cdot (L-1)/L$ de um hop sem fazer falhar nenhum piso individual. Por isso, cada hop pode perder no máximo o que uma perna atestada *média* poderia legitimamente perder: $\sum \mathrm{got} + \lfloor (\mathrm{BPS} - \mathrm{LEG\_FLOOR\_BPS}) \cdot \lfloor \sum \mathrm{attested} / n \rfloor / \mathrm{BPS} \rfloor \ \ge\ \sum \mathrm{attested}$ — a folga é 20 % da perna atestada média, caso contrário `RouterE(5)`. A média e não o máximo, porque com um máximo o atacante inflaciona a sua própria perna para inflacionar o orçamento partilhado. Para uma perna, a regra reduz-se exatamente ao piso por perna — zero rigidez nova, por construção.

**O piso de rota Φ** é a §11.5.

### §11.4 Um callback, um unlock

Cada venue em forma de V3 — Uniswap V3, Algebra, os forks Solidly concentrados, Pancake V3, Sushi V3 — usa o mesmo padrão de flash accounting sob um nome de callback diferente: a pool chama de volta a meio do swap com um delta para token0, um delta para token1 e dados arbitrários, exigindo pagamento. Em vez de um callback com nome próprio por fork, o Router expõe um único `fallback` que responde a todos — a **Doutrina do Callback Único**: lê os dois deltas, identifica pelos seus sinais o token que deve e paga exatamente esse montante, tirando o contexto da perna em curso do transient storage (`TSLOT_POOL`, `TSLOT_TOKEN`, `TSLOT_AMT`). Como um fallback é acessível a qualquer pessoa, é guardado em três frentes: só paga à pool comprometida para a perna atual, recusa-se a agir quando não há nenhuma perna em curso (o contexto transitório é zero entre swaps) e nunca liberta mais do que o orçamento registado da perna — uma segunda exigência dentro da mesma perna é recusada com `RouterE(6)`. Um fork V3 acabado de lançar com um nome de callback novo é suportado no dia em que é implantado.

O singleton V4 é envolvido pela mesma interface de hop: `unlock`, depois swap, `sync → settle → take`, novo lock, com as moedas transportadas em transient storage e a costura nativa da §5.3. Antes de qualquer perna V4 executar, o Router lê o endereço do hook e recusa a perna se os seus bits declararem permissões que alteram deltas (`RouterE(9)`); o hook filtrado é o hook executado, porque o PoolManager canónico devolve os dados do unlock tal e qual (`test/V4SievedHookIsTheExecutedHook.t.sol`). A regra de forma de rota é a ordem canónica, em toda a rota: depois de executada uma perna com hook, nenhuma perna sem hook executa a seguir, neste hop ou em qualquer hop posterior (`sawHooked`), pelo que um hook não pode observar uma perna sem hook posterior da mesma rota antes da liquidação; uma perna com hook só pode estar num hop anterior se todas as pernas depois dela também tiverem hook.

**Taxa na transferência, nas pernas que a comportam.** Alguns tokens entregam a menos em cada transferência. Nas pernas de produto constante, o Router trata isto pelo padrão canónico — transferir primeiro, depois ler as reservas e o saldo da pool no mesmo estado posterior à transferência, e dar preço ao output com base na diferença que a pool efetivamente vê — uma quantidade correta por construção, porque é exatamente a quantidade que o próprio invariante da pool vai verificar. O ramo só é ativado quando um token mede a menos (`TSLOT_FOT`), e o que custa ativá-lo é declarado com ele: o piso de rota derivado da cotação foi calculado sem ver a taxa de transferência e é abandonado para esse swap; o piso do protocolo é reescalado pelo rácio líquido medido (arredondado para cima, a direção conservadora); os limites por perna são reajustados pelo mesmo rácio; e o mínimo do utilizador passa a ser a restrição vinculativa. As pernas concentradas não suportam taxa na transferência por desenho — o flash accounting tem de pagar exatamente o que é devido — pelo que um token taxado numa rota só V3 é recusado à partida com `RouterE(13)`, em vez de reverter dentro de uma pool.

### §11.5 O piso Iron-Law Φ, por inteiro

Nem todas as rotas que podem executar devem fazê-lo — uma rota que devolve 60 % do valor justo é pior do que nenhuma troca — por isso, por baixo de tudo o que ficou acima, está um piso que o protocolo deriva por si próprio. É uma fração de retenção em pontos base (`ironFloorBpsShv`, `legShaveBps` do Core):

$$
\mathtt{floorBps} \;=\; \max\!\left(\;9{,}600 - \mathtt{legShv} - \min(\delta,\, 10^{4}) - \sigma_{\ln}/10^{14},\;\; 8{,}000\;\right)
$$
^e15

$$
\mathtt{legShv} \;=\; \sum_{\mathrm{hops}} \left\lfloor 200 \cdot \frac{(\sum_{i} a_{i})^{2} - \sum_{i} a_{i}^{2}}{\sum_{i} a_{i}^{2}} \right\rfloor \;=\; \sum_{\mathrm{hops}} \left\lfloor 200\,(n_{\mathrm{eff}} - 1) \right\rfloor
$$
^e23

Três constantes decidem-no: `FLOOR_BASE_BPS = 9,600`, `FLOOR_PER_LEG_BPS = 200`, `FLOOR_HARD_MAX_LOSS_BPS = 2,000`. O piso começa em 96 % para um swap limpo de uma só perna, afrouxa um ponto base por cada ponto base de impacto medido $\delta$ e 200 bps por cada perna extra *efetiva*, e é limitado de modo a nunca descer abaixo de 8,000 bps: o protocolo nunca admitirá conscientemente uma rota que retenha menos de 80 % da sua referência, sejam quais forem os inputs. O corte por perna é calculado a partir da *concentração* da troca entre as pernas — $(\sum a)^{2}/\sum a^{2}$, o número efetivo de pernas, exatamente $N$ para $N$ partes iguais e exatamente 1 para uma perna dominante — pelo que uma divisão ganha afrouxamento na proporção de quão genuinamente está dividida, e uma perna com uma parte ínfima ganha um montante ínfimo, quer declare zero quer um wei. Por Cauchy–Schwarz, o numerador nunca sofre underflow. O termo de impacto é a média, ponderada pelas partes, dos impactos medidos das pernas ao longo da rota. Duas propriedades são impressas como parte da definição: o termo de volatilidade $\sigma_{\ln}$ existe na assinatura e é passado como zero literal em todos os pontos de chamada — um hook para um futuro estimador, atualmente inerte — e o impacto da família de reservas exclui a taxa, enquanto o impacto da família concentrada inclui a taxa, cada um na forma que a especificação da sua família lhe dá.

O que faz de Φ uma imposição e não uma heurística é onde corre e sobre o quê. A rota entregue ao Router transporta campos indicativos — um total cotado, um piso atestado — e o Router não confia em nenhum deles: dentro do quadro de execução, mede o impacto real de cada perna, calcula o corte por perna a partir dos montantes que recebe, recalcula `floorBps` e aplica-o à **cotação do último hop dentro do quadro, ao montante que efetivamente lá chegou** — uma referência denominada no token de saída, derivada do estado da pool lido durante esta execução, impossível de falsificar por calldata. A escolha da referência é o que permite sequer que a guarda dispare: uma fração do output *realizado* nunca pode exceder o output realizado. Quando o último hop não pode ser cotado dentro do quadro — uma lacuna de liquidez no tick atual, uma sentinela de taxa — a referência recorre à cotação atestada do hop, que a barreira de cobertura já elevou e a medição da taxa na transferência já reajustou, pelo que uma lacuna de liquidez just-in-time (JIT) numa pool fina não pode desarmar o piso; a âncora do piso é sempre um hop que moveu valor e que produz o output da rota. A verificação corre sobre o output bruto, antes de qualquer taxa do lado do output. O mínimo efetivo é um máximo de três termos,

$$
\mathtt{effMin} \;=\; \max\!\left(\mathtt{userMinOut},\;\; \mathtt{route.singleOutFloor},\;\; \left\lceil \mathtt{finalHopQuote} \cdot \mathtt{floorBps}/10^{4} \right\rceil\right)
$$
^e16

e a sua assimetria é o essencial: os campos fornecidos pelo chamador podem apertar a proteção e nunca a podem afrouxar. O Solver atesta `singleOutFloor` a partir dos mesmos `legShaveBps` e `ironFloorBpsShv` sobre os mesmos montantes, pelo que, para uma rota construída pelo Solver, o piso atestado e o piso imposto coincidem por construção (`test/FloorParitySolverRouter.t.sol`), e o harness de regimes da §15 fixa os dois quadros em cada linha gerada: com a taxa retirada do input, o piso imposto fica em $[\mathrm{attested} \times (1 - \mathrm{fee}),\ \mathrm{attested}]$; com a taxa retirada do output, é igual ao piso atestado.

![FIG-7 — O piso Iron-Law: retenção em função do impacto medido para uma perna única, duas pernas iguais e quatro pernas iguais; o limitador rígido de 80 %; o ponto do Exemplo resolvido 3 assinalado.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-7.png)

**Exemplo resolvido 3 — o piso numa rota de dois hops.** Uma rota A → WETH → B: o hop 0 divide 600 A para a pool P e 400 A para a pool Q; o hop 1 envia o WETH produzido através de uma única pool R. Medido no quadro: as pernas do hop 0 mostram impactos de 100 e 60 bps, a perna do hop 1 40 bps, e a média ponderada pelas partes ao longo da rota é 80 bps. A cotação dentro do quadro do hop 1, ao montante de WETH que efetivamente chegou, é 1,000.000 B.

1. Concentração do hop 0: $(600 + 400)^{2} = 1{,}000{,}000$; $600^{2} + 400^{2} = 520{,}000$; $n_{\mathrm{eff}} = 1.923$; corte $= \lfloor 200 \times 480{,}000 / 520{,}000 \rfloor = \lfloor 184.6 \rfloor = 184$ bps.
2. O hop 1 tem uma perna: $(\sum a)^{2} - \sum a^{2} = 0$; corte 0. `legShv` total = 184.
3. $\mathtt{floorBps} = \max(9{,}600 - 184 - 80 - 0,\ 8{,}000) = 9{,}336$: a rota tem de reter 93.36 % da sua referência.
4. $\mathtt{protocolFloorOut} = \lceil 1{,}000.000 \times 9{,}336 / 10{,}000 \rceil = 933.600$ B.
5. Com `userMinOut` = 990 B definido por quem faz a troca e `singleOutFloor` = 933.6 B atestado pelo Solver, `effMin` = 990 B — o limite do próprio utilizador é o vinculativo, como deve ser numa rota honesta. Uma entrega de 998.4 B liquida; uma entrega de 985 B é recusada com `RouterE(5)`, e a transação inteira, incluindo o swap de cada pool, nunca aconteceu.

Se quem faz a troca tivesse definido `userMinOut` = 900 B, o piso do protocolo seria o vinculativo, em 933.6 B: uma execução a 930 B, 7 % abaixo da referência dentro do quadro, é recusada, mesmo superando o número do utilizador.

### §11.6 A liquidação, e como ler uma

A liquidação fecha o quadro da mesma forma que o abriu: por medição. O Router toma o delta do token de saída face à linha de base de entrada como output bruto (`RouterE(8)` se for zero), corre a verificação de piso acima, cobra a taxa onde o regime a coloca (§13), transfere o líquido para o destinatário e mede o delta de saldo *do destinatário*, impõe `userMinOut` sobre esse montante entregue — para que um token de saída com taxa na transferência não possa fazer o utilizador escorregar abaixo do seu limite — e lê uma vez o livro-razão de taxas: uma liquidação que não pagou nada ao protocolo é recusada (`RouterE(15)`), e numa rota ancorada um segundo pagamento é recusado (`RouterE(16)`). Depois, e só no caminho de sucesso, chama o `recordSwap` do Hub uma vez por perna executada (`_recordHits`) com os montantes que o hop conseguiu gastar — o rácio entre medido e declarado aplicado a cada perna — que é a única escrita externa que um swap realiza; nada é escrito quando o piso rejeita.

Cada liquidação emite `ExecutionProof(user, tokenOut, quoted, realized, floorUsed, blockNumber)`: a cotação de referência produzida no mesmo quadro que a execução, publicada como uma série on-chain que qualquer pessoa pode re-derivar com um `eth_call` a `findBestRoutePlan` nesse bloco. Os seus campos, sem afirmar mais do que provam: `user` é o pagador, nunca `msg.sender`; `quoted` é a cotação do último hop — prova o último hop, não a rota; `realized` é o que foi entregue, medido no destinatário; `floorUsed` é o piso do protocolo que tinha de ser superado. Cada evento `Fee(token, amount, toT1, toT2)` indica o token e a divisão da taxa.

**Exemplo resolvido 6 — ler uma liquidação.** A rota do Exemplo 3 liquida e emite `ExecutionProof(0xUSER, B, 1,000.000, 998.400, 933.600, N)` e um `Fee(WETH, 0.014, 0.0042, 0.0098)`.

| Quantidade | Valor | Leitura |
|---|---|---|
| `quoted` | 1,000.000 B | a cotação do último hop dentro do quadro, ao WETH que efetivamente chegou |
| `realized` | 998.400 B | entregue ao destinatário, medido aí; 9,984 bps da cotação |
| `floorUsed` | 933.600 B | `floorBps` 9,336 aplicado à cotação; a execução ficou 64.8 B acima dele |
| `Fee` | 0.014 WETH num só evento | o regime ancorado: 28 bps dos 5.000 WETH que o hop 0 produziu, pagos no input do hop 1, 30 % para a primeira tesouraria; nada foi tirado de B |
| distância a `userMinOut` | 8.4 B | o limite de 990 B do utilizador deixou 0.84 % de folga |

O entregue menos o cotado é a resposta do mercado, não do protocolo: a taxa saiu antes, em WETH, e não existe nenhum corte do lado do output nesta rota. Um evento `Fee` denominado no token de saída só aparece numa rota direta para uma moeda ponte (§13).

### §11.7 As recusas do Router

| Código | Significado | Onde |
|---|---|---|
| `RouterE(1)` | chamada de controlo não autorizada | `onlyControl` |
| `RouterE(2)` | em pausa, ou renúncia tentada durante a pausa | `whenLive`, `renounceControl` |
| `RouterE(3)` | input inválido — endereço zero, porta nativa não ligada, número de hops, pernas por hop, descontinuidade entre hops | pontos de entrada, `_execute` |
| `RouterE(4)` | prazo ultrapassado | pontos de entrada |
| `RouterE(5)` | output abaixo de um piso — por perna, agregado por hop, piso de rota ou `userMinOut` | `_execScaled`, `_execute` |
| `RouterE(6)` | callback não autorizado — pool errada, nenhuma perna em curso, segunda exigência | `fallback` |
| `RouterE(7)` | reentrância | `nrEntrant` (lock transitório) |
| `RouterE(8)` | swap falhado — output zero, tipo desconhecido, taxa igual ou superior ao montante | `_execute`, `_execScaled`, `_chargeHopFee` |
| `RouterE(9)` | o hook V4 altera deltas | pré-compromisso da perna V4 |
| `RouterE(10)` | `userMinOut == 0` com `amountIn > 0` | todas as portas |
| `RouterE(13)` | token com taxa na transferência numa rota só concentrada | `_execute` |
| `RouterE(14)` | resgate não colocado em fila ou dentro do seu período de espera de 48 horas | `executeRescue` |
| `RouterE(15)` | liquidado sem pagar a taxa do protocolo | livro-razão de taxas, fim de `_execute` |
| `RouterE(16)` | taxa paga duas vezes numa rota ancorada | livro-razão de taxas, fim de `_execute` |

Os códigos 11 e 12 não estão atribuídos. Uma superfície de revert tão enumerável como a API é o que permite às matrizes de regimes da §15 julgar cada linha por uma só regra — liquidar, ou recusar com um seletor nosso — e chamar a qualquer outra coisa uma terceira via.

## §12 Superfícies de cotação, e como uma cotação envelhece

Há dois sítios de onde pode vir um número chamado “a tua cotação”, e são caminhos de código diferentes: o **Quoter**, um contrato de pré-visualização só de leitura que uma interface chama antes de assinares, e o **caminho dentro do quadro**, em que o Solver e o Router calculam cotações dentro da transação em execução. A §4.4 deu a verdade por tipo; esta secção apresenta as superfícies e mede a lacuna entre elas.

### §12.1 As superfícies do Quoter

| Função | Devolve | Notas |
|---|---|---|
| `previewPlan(tIn, tOut, amountIn)` | um `Preview` | o plano do Solver, empacotado com a taxa e a margem de segurança |
| `previewPlanWithMinOut(…, userMinOut)` | um `Preview` | o mesmo, com `canExecute` avaliado face ao mínimo do chamador |
| `previewAndEncode(…)` / `previewAndEncodeWithMinOut(…)` | um `Preview` e a calldata para `swapExactIn` | a forma como um integrador obtém uma cotação — o estudo da §12.2 usa exatamente isto |
| `batchQuote(entries[])` | até `MAX_BATCH = 32` pré-visualizações | um par que não pode ser planeado deixa uma entrada inicializada a zero |
| `previewPlanExact(tIn, tOut, amountIn)` | a rota e uma saída líquida exata | a Passagem Exata: cada perna concentrada é ensaiada contra o próprio swap da pool |

**O que é uma pré-visualização.** A struct `Preview` é indicativa por desenho — as verificações vinculativas são as que o Router re-deriva dentro do quadro — e os seus campos estão documentados no local da definição: `grossOut` ecoa o total do plano; `protocolFee` é o efeito da taxa sobre a saída, modelado por regime exatamente como o Router a cobra (§13) — uma vez numa rota ancorada, uma vez por hop numa rota em exaustão, arredondado para cima tal como o Router arredonda; `safetyBuffer` é a margem entre pernas

$$
s \;=\; \min\!\left(\max(0,\, n-2) + 5a,\;\; 10\right)\ \text{bps}
$$
^e21

zero com duas pernas ou menos, um ponto base por perna acima de duas, mais cinco por cada perna de produto constante cotada com uma taxa *presumida* (uma taxa declarada que o Core substituiu ao abrigo do seu teto), sob um único teto partilhado de dez, porque uma margem sem teto deixa de ser uma margem e passa a ser um piso; `netOut` é $\mathrm{grossOut} - \mathrm{protocolFee} - s$; `ironFloor` ecoa o piso atestado; `topology` e `bridgeUsed` são derivados da contagem de hops e da âncora de taxa que o Router vai usar — a mesma varredura do mesmo produtor, por isso a pré-visualização e o executor não podem nomear pontes diferentes. A regra para integradores cabe numa frase e é o conselho que mais peso carrega neste documento: deriva o teu mínimo da tua própria expectativa de preço, nunca de um campo da pré-visualização.

**A Passagem Exata.** Para uma pré-visualização exata ao nível da pool num venue concentrado, o Quoter chama a verdadeira entrada de swap da pool; a pool chama de volta a exigir pagamento; o callback do Quoter, em vez de pagar, reverte — levando os deltas calculados no payload da reversão. A reversão desfaz todo o estado, nada é pago, e a saída descodificada é o próprio swap do venue sobre o estado atual, executado e revertido; o V4 é tratado de forma idêntica através de um unlock cujo callback reverte com o delta empacotado. Uma pool que recuse o ensaio mantém a afirmação do próprio plano, escalada pela corda abaixo dela — nunca acima, porque a saída de um AMM é côncava. O hop 0 fica limitado ao que o plano comprometeu, para que uma rota limitada pela capacidade não seja ensaiada num tamanho que o Router nunca vai gastar. Desde 2026-09-03, o escalar devolvido é líquido da taxa do protocolo, deduzida uma vez tal como a pré-visualização a deduz, por isso um mínimo derivado dele é honrado pelo piso (`test/QuoterExactNetOut.t.sol`). Este é o instrumento do Quoter do lado da pré-visualização; a superfície que vincula é a re-derivação dentro do quadro.

### §12.2 Como uma cotação envelhece

Uma cotação é uma promessa sobre um bloco futuro. O estudo obtém-na como um integrador o faz — `previewAndEncode` devolve a pré-visualização e a calldata —, deixa o mundo mover-se (zero a três trocas de outra pessoa através das mesmas pools, cada uma até 3 % da reserva menos profunda, todas na direção do utilizador, para que cada uma delas prejudique), deixa passar zero a dez segundos e executa a calldata sem alterações. 240 amostras num universo de três tokens de mocks de produto constante (A, B = moeda-ponte, C; direto para a ponte, dois hops através dela, dois hops no sentido inverso), cada resultado classificado (`test/QuoteDelayStatistics.t.sol`):

| Deriva entre cotação e execução | Amostras | Liquidadas | Recusadas pelo piso (`RouterE(5)`) | Entregue / previsto — média | mín. |
|---|---|---|---|---|---|
| nenhuma | 64 | 64 | 0 | 10,000 bps | 10,000 |
| 1 – 100 bps | 43 | 43 | 0 | 9,952 bps | 9,803 |
| 100 – 300 bps | 133 | 102 | 31 | 9,966 bps | 9,653 |

| Atraso entre cotação e execução | Amostras | Liquidadas | Recusadas (`RouterE(5)`) | Entregue / previsto — média | mín. |
|---|---|---|---|---|---|
| 0 s | 17 | 15 | 2 | 9,989 bps | 9,857 |
| 1 – 5 s | 99 | 89 | 10 | 9,959 bps | 9,653 |
| 6 – 10 s | 124 | 105 | 19 | 9,983 bps | 9,659 |

![FIG-8 — Como uma cotação envelhece: amostras liquidadas e recusadas por classe de deriva, com a razão entregue/previsto de cada amostra liquidada; as mesmas 240 amostras agrupadas por atraso não mostram tendência.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-8.png)

O tempo não move uma cotação; a deriva move. Verificado em cada amostra: uma cotação sem deriva liquida com qualquer atraso e entrega exatamente a sua previsão (64 de 64); uma liquidação nunca entrega abaixo do piso que a pré-visualização atestou; não há terceiro resultado. Depois do prazo (`deadline = now + 5`, executado a `+10`), 20 de 20 são recusadas com o código do próprio prazo, `RouterE(4)`, e nenhuma liquida. Com até 1 % de deriva adversa, todas as cotações continuam a ser executadas, dentro de 2 % da sua previsão; com 1–3 %, o piso recusa uma em cada quatro em vez de a executar abaixo da saída atestada, e as execuções ficam dentro de 3.5 % da previsão — a curva de sandwich da §14 vista do lado da cotação.

**Base real** (`test/fork/QuoteDelayFork.t.sol`, 1,000 USDC → WETH, pools reais, o protocolo implantado num fork no bloco atual): executada 0, 3, 6 e 10 s depois, sem mais nada a mover-se, a cotação entregou exatamente a sua previsão nas quatro vezes. Com 10,000 · 50,000 · 200,000 · 1,000,000 · 5,000,000 USDC negociados à sua frente pela mesma rota e a calldata desatualizada executada 10 s depois, as cinco liquidaram dentro do piso, a 9,999 · 9,998 · 9,994 · 9,974 · 10,000 bps da previsão: um milhão de dólares à frente de mil custa a esses mil um quarto de um por cento, e a troca de cinco milhões foi encaminhada por pools que a rota de mil dólares não toca. As distribuições acima são sobre mocks; a Base real dá alcance num par, num bloco, não uma distribuição.

### §12.3 O que custa uma cotação através da ABI

Gas medido em torno da chamada externa, quarenta tamanhos em cada caso no universo de três tokens (`test/QuoterGasStatistics.t.sol`) e cinco tamanhos na Base real (`test/fork/QuoterGasFork.t.sol`):

| Mundo | `previewPlan` média | mín. | máx. | σ | `previewAndEncode` média | σ |
|---|---|---|---|---|---|---|
| mocks — descoberta: o par conhecido apenas da factory, uma pool encontrada | 121,313 | 116,468 | 123,491 | 1,433 | 123,317 | 1,851 |
| mocks — registo atualizado: três pools semeadas cotadas | 235,574 | 227,205 | 237,843 | 1,815 | 239,647 | 1,937 |
| Base real — a frio: registo vazio, factories admitidas varridas | 1,524,221 | | | | 1,525,341 | |
| Base real — a quente: atualizado após uma execução, duas pools registadas | 1,414,633 | | | | 1,416,037 | |
| Base real — de novo a frio após o TTL da descoberta | 1,359,925 | | | | 1,361,582 | |

`batchQuote` de dez entradas em mocks: 2,055,390 de gas, 205,539 por entrada. O mock de registo atualizado custa mais do que a descoberta porque cota três pools onde a descoberta encontrou uma; a comparação honesta é a da Base real, em que a varredura da descoberta é cerca de 7 % de uma cotação — e uma cotação é uma chamada de leitura que um integrador nunca paga on-chain.

## §13 Política de taxas: os dois regimes e a Regra do Excedente

*Em termos simples:* o protocolo cobra 0.28 % uma vez, sobre um montante medido, numa moeda que a tesouraria quer deter, e conta que o fez. *Em termos precisos:* `PROTOCOL_FEE_BPS = 28` é uma constante de compilação no Core, sem setter em parte nenhuma do bytecode implantado; a taxa é `mulDivUp(base, 28, 10,000)` — arredondada para cima, pelo que uma taxa zero é inalcançável para qualquer base não nula — dividida em `TREASURY1_SHARE = 3,000` bps para a primeira tesouraria e o restante para a segunda (calculado como `fee − t1`, para que as duas somem sempre a taxa sem dust), com as tesourarias fixadas na construção e congeláveis para sempre pela Porta de Sentido Único. Nenhuma chave pode subir a taxa contra quem negocia e nenhuma chave a pode baixar para um integrador favorecido: a questão da taxa foi respondida em tempo de compilação e retirada da lista de coisas que uma chave pode fazer.

### §13.1 Onde a taxa é cobrada: dois regimes, ambos nomeados

A regra desde 2026-08-22 cabe numa frase: **cobrar uma vez, sobre a primeira moeda-ponte que o Router detém.** O Router percorre a rota à procura do primeiro hop cujo token de entrada seja uma ponte registada (`hub.isBridgeToken`, pela ordem dos hops) — esse hop é o `feeHop` — e cobra 28 bps da entrada *medida* desse hop: no hop 0, o montante puxado medido, limitado pelo que a rota comprometeu; num hop posterior, o saldo da moeda-ponte no Router acima da sua linha de base alheia, a quantidade que já resiste à taxa na transferência e a saldos avulsos. O Router não cobra mais nada nessa rota. Uma rota direta cujo destino é, ele próprio, uma moeda-ponte (TOKEN → WETH) cobra sobre a saída, depois da verificação do piso — o piso valida a qualidade do swap, a parte do protocolo sai do montante já validado, e o mínimo do utilizador é comparado com o que ele realmente recebe. Este é o **regime ancorado**. Porquê na ponte e não no destino: as pontes são WETH e USDC, e a tesouraria recebe uma moeda líquida que quer deter, em vez de dust de qualquer token de cauda que seja o destino. Porquê na entrada do hop 1 e não na saída do hop 0: são o mesmo token e o mesmo montante, mas a entrada do hop 1 é medida pelo saldo real, que é a medição que o Router já faz.

A regra tem um segundo regime que a frase não nomeava até 2026-09-05. Uma rota construída à mão através de pools que o registo não manteria, sem moeda-ponte como entrada de nenhum hop, nunca encontra um `feeHop`; o predicado que cobra é então verdadeiro para *todos* os hops, e cada hop paga 28 bps sobre a sua própria entrada medida. Este é o **regime de exaustão**, e é uma regra deliberada, não um descuido: cobrar uma rota destas uma única vez, no hop 0, foi experimentado dentro do conjunto de testes nessa data e reabriu a fuga que a política de exaustão existe para fechar — um primeiro hop sem valor leva o ponto de cobrança da taxa para dust e o hop real não paga nada (`test/FeeEscapeViaJunkPrefix.t.sol`); cinco testes fixados recusaram a alteração na mesma execução. Não há índice em que se possa inserir dust que escape a todos os hops, e é isso que significa “imunidade por exaustão”. O Solver constrói todas as rotas multi-hop através de pontes registadas, por isso uma rota construída pelo Solver paga sempre exatamente uma vez; o regime de exaustão é o que um chamador encontra quando contorna o registo, e o Quoter modela-o (`_pack` cobra `hops.length` vezes quando nenhuma entrada de hop é uma ponte, e uma vez caso contrário), por isso a pré-visualização e a entrega coincidem nos dois regimes (`test/ExhaustionRegimePreviewParity.t.sol`).

![FIG-9 — Os dois regimes de taxa tal como o Router os decide: percorrer os hops à procura da primeira entrada que seja uma moeda-ponte; as rotas ancoradas pagam uma vez nesse hop (ou na saída de uma rota direta para uma moeda-ponte); as rotas sem entrada em ponte pagam uma vez por hop; o livro-razão conta e recusa zero, e recusa dois numa rota ancorada.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-9.png)

### §13.2 O compromisso tem um único produtor, e o contrato conta

Dois selos acompanham os regimes. A soma das entradas declaradas das pernas de um hop — a base da taxa no hop 0 e o denominador da escala — é calculada por uma única função, `_legSum`; antes de 2026-09-05, cada um somava as pernas no seu próprio ciclo, dois produtores de um mesmo número. E o livro-razão da taxa: `_payFee`, a única função que transfere a taxa, conta para um slot transitório (`TSLOT_FEE`); cada liquidação lê o slot uma vez, recusa uma entrega que não pagou nada (`RouterE(15)`) e, numa rota ancorada, um segundo pagamento (`RouterE(16)`), e depois limpa-o. As duas verificações do livro-razão são *salvaguardas*: isoladamente, nenhum teste as consegue fazer disparar, porque o predicado que as antecede não deixa nenhum caminho que liquide sem pagar ou que pague duas vezes numa rota ancorada. São o contrato a recusar em tempo de execução o que os testes recusam em tempo de revisão, em caminhos que ainda não existem; são listadas como salvaguardas, não são contadas como cobertas em lado nenhum e estão ausentes da guarda de mutação, que só admite mutantes que um teste nomeado mata.

### §13.3 A Regra do Excedente

A **Regra do Excedente** é o argumento de alinhamento do desenho da taxa, enunciado tal como o código o implementa: a parte do protocolo é 28 bps de uma base medida, uma vez numa rota ancorada e uma vez por hop numa rota em exaustão, e não há em parte alguma da liquidação um termo que escale com a diferença entre o que foi cotado e o que foi entregue. Onde a base é uma entrada — todas as rotas multi-hop e todas as rotas diretas cujo destino não é uma moeda-ponte — a saída fica intacta: tudo o que as pools entregam acima da cotação chega ao destinatário por inteiro, e a taxa não pode subir porque uma execução saiu favorável. Onde a base é a saída — uma rota direta para uma moeda-ponte — a taxa é 28 bps da entrega bruta, excedente incluído, e nada mais. O eixo em que um agregador é mais tentado a desviar uma fatia é a lacuna entre cotação e execução; este desenho não dá a essa lacuna nenhum termo de taxa, por isso a taxa anunciada é a verdadeira e única taxa. A base nunca é lida da calldata: `route.totalOut` chega ao Router como a alegação de um estranho e não é lido por nada (`test_FeeBase_IgnoresLiedAboutTotalOut`).

**Exemplo resolvido 5 — os dois regimes numa só rota.** As pontes são {WETH, USDC}; quem negocia vende 10,000 A.

*Ancorado, dois hops.* A → WETH → B. O hop 0 não é cobrado (a sua entrada, A, não é uma ponte). As pools do hop 0 pagam 5.000 WETH, medidos como o saldo de WETH do Router acima da sua linha de base alheia. `feeHop` = 1: a taxa é $\lceil 5.000 \times 28 / 10{,}000 \rceil = 0.014$ WETH, dividida em 0.0042 para a primeira tesouraria e 0.0098 para a segunda, e o hop 1 gasta 4.986 WETH em B. Um evento `Fee`; o livro-razão marca 1 e fica satisfeito; a pré-visualização deduziu 28 bps uma vez.

*Ancorado, direto para uma ponte.* A → WETH num só hop. Nada é cobrado sobre a entrada. As pools entregam 5.000 WETH brutos; o piso é verificado sobre 5.000; depois, a taxa do lado da saída, $\lceil 5.000 \times 0.0028 \rceil = 0.014$ WETH, é paga e são entregues 4.986 WETH; `userMinOut` é comparado com 4.986. Um evento `Fee`, denominado no token de saída.

*Exaustão, dois hops.* A → C → B, em que nenhum de A, C ou B é uma ponte — uma rota que nenhum Solver constrói. O hop 0 paga $\lceil 10{,}000 \times 0.0028 \rceil = 28$ A e envia 9,972 A para as suas pools, que pagam 2,000 C; o hop 1 paga $\lceil 2{,}000 \times 0.0028 \rceil = 5.6$ C e envia 1,994.4 C para B. Dois eventos `Fee`; o livro-razão marca 2 sem `feeHop`, por isso `RouterE(16)` não se aplica; a taxa efetiva é $1 - 0.9972^{2} = 55.9$ bps, e a pré-visualização disse-o.

### §13.4 A taxa, medida de fora do Router

`test/FeeSeals.t.sol` não lê nenhum dos números do Router: o token da taxa vem da regra e da lista de pontes, a base vem das diferenças de saldo das pools (o que saiu do Router para o hop da taxa, ou o que as pools do hop anterior pagaram) ou das do destinatário, a taxa vem das diferenças de saldo das tesourarias, a contagem vem dos eventos `Fee` — sobre todas as formas que o Router aceita (um a três hops; ponte em nenhuma posição, na primeira, na do meio ou na última; uma ou duas pernas por hop), montantes sob fuzz de $10^{12}$ a $10^{21}$ wei, 2,000 execuções, nenhuma falha, e o Router sem guardar nada depois de cada liquidação.

| Forma da rota | Regime | Onde cai a taxa | Medido |
|---|---|---|---|
| A → B (nenhum é ponte) | exaustão, um hop | entrada do hop 0, uma vez | taxa = ⌈28 bps × entrada⌉, um evento |
| W → A (ponte à entrada) | ancorado | entrada do hop 0 | igual |
| A → W (ponte à saída, direta) | ancorado, lado da saída | a saída | taxa = ⌈28 bps × saída bruta⌉, entregue = bruto − taxa |
| A → C → B (sem ponte) | exaustão, dois hops | entrada medida de cada hop | dois eventos |
| W → A → B | ancorado no hop 0 | entrada do hop 0 | um evento |
| A → W → B | ancorado no hop 1 | a moeda-ponte que o hop 0 produziu | um evento, ⌈28 bps × o que as pools do hop 0 pagaram⌉ |
| A → C → W (ponte só como saída de dois hops) | exaustão | entrada de cada hop | dois eventos |
| A → C → D → B · A → W → C → B · A → C → W → B | como acima | como acima | 3 · 1 · 1 eventos |

**A frequência com que os testes da taxa detetam um defeito** foi medida em vez de presumida (`docs/assurance/fee-seal-detection.json`): cada mutante da taxa — o predicado do regime deslocado num sentido ou no outro, o produtor do compromisso, as duas verificações do livro-razão e os três mutantes da taxa do estudo de invariantes — foi executado com vinte sementes de fuzz por cada teste com fuzz e uma vez por cada teste determinístico; a taxa de deteção é reportada com um intervalo de Wilson a 95 % e, onde nada escapou, com o limite da regra de três para a probabilidade de não deteção.

| Mutante | Fuzz FeeSeals | Campanha do Router (2 hops, 2 pernas) | Matriz de cobertura t = 2 | Fuga por prefixo-lixo | Paridade da pré-visualização em exaustão |
|---|---|---|---|---|---|
| a exaustão cobra apenas o hop 0 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | não | sim | sim |
| a exaustão salta o hop 0 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | não | sim | sim |
| o compromisso conta apenas a primeira perna | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | não | não | não |
| taxa duplicada | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | sim | sim | sim |
| taxa do lado da entrada nunca cobrada | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | não | sim | sim |
| taxa cobrada dos dois lados | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | não | sim | sim |
| salvaguarda: liquidação sem taxa deixa de ser recusada | 0/20 [0.00, 0.16] | 0/20 [0.00, 0.16] | não | não | não |
| salvaguarda: pagamento duplo ancorado deixa de ser recusado | 0/20 [0.00, 0.16] | 0/20 [0.00, 0.16] | não | não | não |

![FIG-10 — Taxa de deteção de cada mutante da taxa por cada teste, como mapa de calor: mortes sobre execuções, com o intervalo de Wilson; as duas salvaguardas aparecem como as linhas que nada vê.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-10.png)

Lida uma linha: que testes veem este defeito. Lida uma coluna: o que um teste consegue e não consegue ver. A primeira medição encontrou a campanha do Router cega ao mutante de exaustão que poupa o hop 0 e ao produtor do compromisso, porque só construía rotas diretas de uma perna; a campanha foi alargada no mesmo dia para percorrer dois hops e dividir o hop 0 por duas pools, com uma moeda-ponte no universo para que uma só campanha contenha todos os regimes, e ambos são agora vistos 20 de 20. A matriz de cobertura só vê a taxa duplicada, porque as suas linhas atravessam sempre uma ponte. Vinte sementes a 20 de 20 limitam a probabilidade de não deteção de uma única campanha a 15 %, e é por isso que a guarda de mutação corre tanto o teste nomeado como a campanha.

Resumindo a secção na forma que este documento usa — afirmação, local de imposição, limite: ninguém pode mexer na taxa nem na divisão, porque nenhuma delas tem setter no bytecode implantado; um chamador não pode reduzir a taxa subdeclarando uma cotação, porque a base é um saldo medido e `route.totalOut` não é lido por nada; um chamador não pode fugir à taxa com um prefixo sem valor, porque uma rota sem entrada em ponte paga em cada hop; e uma liquidação não pode pagar nada nem pagar duas vezes numa rota ancorada, porque o Router conta — com o limite de que as duas verificações do próprio contador são salvaguardas que nenhum teste consegue fazer disparar.

## §14 Modelo de segurança

*Em termos simples:* o Router não guarda nada entre transações, cada swap é tudo-ou-nada, e cada classe de ataque que este repositório considerou é respondida por uma verificação nomeada ou declarada fora do âmbito. *Em termos precisos:* o catálogo de ameaças é `docs/assurance/threats.json`, 23 classes retiradas do registo público de exploits; cada uma nomeia o símbolo de guarda que a recusa, e um script de CI faz falhar o build se o símbolo sair de `src/` ou o teste nomeado sair de `test/`. A cobertura de um catálogo é um piso para aquilo que foi considerado, nunca um teto para aquilo que existe.

### §14.1 Ataques e as verificações que os recusam

| Classe (id) | A verificação que a recusa | Onde é imposta | Estado | O teste que mostra que a verificação pode falhar |
|---|---|---|---|---|
| Reentrância (DASP-1) | bloqueio transitório `nrEntrant` em todas as portas que movem valor; a superfície de callback autentica o seu chamador | Router `nrEntrant` → `RouterE(7)`; `fallback` → `RouterE(6)` | bloqueada | `invariant_reentrancyBlocked` (`test/RouterAdversarialV4FromV1.t.sol`) |
| Controlo de acesso (DASP-2) | quatro papéis; todas as portas privilegiadas protegidas por barreira; o nível de controlo renunciável para sempre | Hub `onlyAdmin` / `onlyControl` → `HubE(1)`; Router `onlyControl` → `RouterE(1)` | bloqueada | `test/HubAllowHookAfterRenounce.t.sol`, `test/ControlEvents.t.sol` |
| Overflow/underflow aritmético (DASP-3) | aritmética verificada em todo o código; cada bloco `unchecked` traz um limite escrito; a representabilidade das curvas difíceis testada na fronteira (`MAX_SQRT_PRICE_MINUS_ONE`) | Core | bloqueada | `test/BoundaryEquality.t.sol`, `test/CompilerPanicSurface.t.sol` |
| Negação de serviço por iteração ilimitada (DASP-5) | todas as dimensões da rota limitadas: `MAX_HOPS = 3`, `MAX_LEGS_PER_HOP = 5`, `MAX_LEGS = 11`, `MAX_CANDIDATES = 8`, `MAX_SLOTS = 16`, `MAX_FACTORIES = 16` | Router `_execute` → `RouterE(3)`; Solver; Hub → `HubE(4)` (factories), `_canInsert` (slots) | bloqueada | `test/RouteHopCeiling.t.sol` |
| Dependência da ordem das transações / sandwich (DASP-7) | o piso Iron-Law, com limitador rígido em `FLOOR_HARD_MAX_LOSS_BPS = 2,000`, imposto independentemente do mínimo do chamador, que só o pode apertar | Core `ironFloorBpsShv`; Router `_execute` → `RouterE(5)` | bloqueada (limitada, §14.3) | `test/regime/SandwichCurve.t.sol`; `invariant_DeliveredNeverBelowTheProtocolFloor` |
| Reentrância entre funções através de um venue (SWC-107) | o mesmo bloqueio transitório abrange todo o swap, incluindo os callbacks das pools | Router `nrEntrant` | bloqueada | `test/V4LockedRegionReentrancy.t.sol` |
| Manipulação do oráculo de preços (SOK-ORACLE) | não há feed: a cotação de referência é produzida no quadro de execução a partir dos venues negociados, e o piso é derivado dela (`ironFloorBps`) | Core; Router `_execute` | bloqueada | `test_Parity_SplitRoute_AttestedFloorEqualsEnforcedFloor` (`test/FloorParitySolverRouter.t.sol`) |
| Quantidade fornecida pelo chamador em substituição de uma medida (SOK-FEE-BASE) | a base da taxa é um saldo medido (`_chargeHopFee`); `route.totalOut` não é lido por nada | Router `_chargeHopFee` | bloqueada | `test_FeeBase_IgnoresLiedAboutTotalOut` (`test/BlazePhoenixRouter.t.sol`) |
| Tokens com taxa na transferência e tokens com rebasing (SOK-FOT) | cada montante que importa é uma diferença de saldo medida (`balanceOf`), nunca um montante de transferência presumido | Router, em cada costura | bloqueada | `test/FotFloorReprice.t.sol`, `test/PartialFotAtPrePulledDoors.t.sol` |
| Venue hostil admitido no registo (SOK-VENUE-ADMISSION) | a admissão é exclusiva do curador, uma linha por endereço; a origem da derivação é atestada na admissão (`factoryDeployer`) e congelada após a renúncia | Hub `addFactory`, `_probe` | bloqueada | `test_C4_FirstPin_AfterRenounce_MustNotAttestTheLiveAnswer` (`test/T19ReadmissionEdge.t.sol`) |
| Venue admitido cuja lógica muda por trás de um proxy (SOK-PROXY-VENUE) | readmissão após a renúncia recusada quando o runtime mudou (`factoryCodehash`); onde um proxy pode mudar a sua resposta sem mudar o seu código, é a resposta que fica fixada | Hub `addFactory` → `HubE(1)` | bloqueada | `test/FactoryCodehashPin.t.sol`, `test/RenouncedFactoryRearm.t.sol` |
| Linha de venue convertida de derivada em consultada após a ossificação (SOK-MODE-FLIP) | uma linha de derivação não se pode tornar uma linha de consulta depois de `controlRenounced`; o aperto no sentido inverso continua permitido | Hub `addFactory` | bloqueada | `test_C4_S3_DeriveRowMustNotBecomeAnAskRowAfterRenounce` (`test/T19ReadmissionEdge.t.sol`) |
| Métrica publicada que reporta a declaração do chamador (SOK-VOLUME) | o registo recebe o montante que o hop conseguiu gastar, a partir da razão entre medido e declarado (`hopScale`) | Router `_recordHits` | bloqueada | `test_INV_F4_VolumeInEqualsTheMeasuredPoolDelta` (`test/VolumeEventFidelity.t.sol`) |
| Pré-visualização que não prevê a execução (SOK-QUOTE-EXEC) | pré-visualização e entrega verificadas como iguais nos dois regimes de taxa (`previewRoute`, `_pack`) | Quoter; Router | bloqueada | `test_INV_F2_PreviewPredictsDeliveryWithNoBridge` (`test/ExhaustionRegimePreviewParity.t.sol`) |
| Derivação determinística desviada para um endereço do atacante (SOK-V4-DERIVE) | a pré-imagem CREATE2 tem um único produtor (`create2Address`); o id de uma pool deriva da sua própria chave; `hasCode` e a prova de vida descartam o que não se resolve | Core; Hub `_probe`, `_scanV4` | bloqueada | `test/ConditionAdequacyCore.t.sol`, `test/KindIsDerivedNotDeclared.t.sol` |
| Hook malicioso num venue com hook (SOK-HOOK) | três camadas, §14.2: bits imutáveis do endereço, lista de permissões com fixação do codehash (`hookAllowed`, `isHookLive`), o projector Ξ | Router → `RouterE(9)`; Hub `allowHook` → `HubE(8)`; Solver `_topKPools` | bloqueada | `test/V4SievedHookIsTheExecutedHook.t.sol`, `test/SeedPoolHookMustBeAllowed.t.sol`, `test/RenouncedHookRearm.t.sol` |
| Esgotamento do registo por admissão repetida (SOK-GRIEF-SEATS) | uma linha por endereço; uma adição repetida atualiza a linha existente em vez de consumir um lugar (`MAX_FACTORIES`) | Hub `addFactory` → `HubE(4)` | bloqueada | `test/RenouncedFactoryRearm.t.sol` |
| Chamada externa arbitrária ou sumidouro de transfer-from (SOK-ARBITRARY-CALL) | o executor nunca aceita um alvo de chamada fornecido pelo chamador; a interação com o venue é despachada a partir de um conjunto fechado de formas selecionadas pelo tipo (`_execScaled`), e um tipo desconhecido reverte | Router `_execScaled` → `RouterE(8)` | bloqueada | `test/regime/HostileVenueMatrix.t.sol` |
| Repetição de assinatura em aprovação delegada (SOK-SIG-REPLAY) | a aprovação delegada é tratada pelo Permit2 canónico (`permitTransferFrom`); o sistema não tem nenhum esquema de assinatura próprio | Router `swapExactInWithPermit2` | bloqueada | `test/RouterPermit2OneStep.t.sol` |
| Captura da governação (SOK-GOV) | não há governação: nem voto por token, nem timelock, nem proxy; os únicos poderes privilegiados são a admissão de venues e a pausa, ambos renunciáveis | — | fora do âmbito | — |
| Atualização maliciosa (SOK-UPGRADE) | os contratos são imutáveis; não há proxy nem slot de implementação | — | fora do âmbito | — |
| Comprometimento de uma ponte ou de um venue externos (SOK-BRIDGE-EXT) | os venues de terceiros são compostos, não controlados; a sua falha é limitada aqui pelo piso e pelo mínimo do chamador, e a sua segurança interna não é reivindicada | — | fora do âmbito | — |
| Comprometimento da chave privada de um utilizador (SOK-KEY) | fora da fronteira de confiança; registado porque os dados de incidentes publicados lhe atribuem uma grande parte das perdas | — | fora do âmbito | — |

Dezanove das vinte e três classes são respondidas por uma guarda nomeada; quatro estão fora do âmbito, com a razão registada. O catálogo é verificado no sentido inverso por um fecho de ativos (`assets.json`): seis coisas que o sistema detém ou decide — fundos em trânsito, autorização delegada, a taxa do protocolo, a integridade do registo, saldos retidos, o gas do chamador — cruzadas com cinco formas de uma coisa se perder, trinta células, cada uma resolvida numa classe de ameaça, numa justificação de fora do âmbito ou num estado explícito *aberto*. Dezanove células estão cobertas, três estão fora do âmbito, cinco não se aplicam, e três estão abertas e publicadas como tal: griefing sobre a denominação da taxa, reter dust para tornar a recuperação antieconómica, e um chamador deparar-se com um de três panics do compilador alcançáveis em vez de uma recusa nomeada. Nenhuma das células abertas é um caminho para os fundos de outra pessoa.

### §14.2 Hooks hostis: três camadas, a mais barata primeiro

Um hook é código arbitrário que corre dentro da liquidação que o Router está a realizar, e a defesa ingénua — perguntar-lhe o que vai fazer — não é defesa nenhuma, porque um hook hostil mente ou reentra. Em vez disso, erguem-se três camadas independentes, dispostas de modo a que a mais barata e mais certa corra primeiro; limitam a alteração de deltas, e o único resíduo que não alcançam — um hook sem deltas a sobrepor-se à sua taxa dinâmica (§5.4) — é limitado, em vez disso, por Φ e pelo mínimo do chamador.

**Camada 1 — os bits de permissão vivem no endereço, e o endereço não pode mentir.** O V4 codifica as permissões de um hook nos 14 bits menos significativos do seu próprio endereço de contrato; esses bits são fixados na implantação pelo salt CREATE2, e o próprio PoolManager verifica os mesmos bits antes de invocar o hook, por isso um hook não pode ter uma permissão que o seu endereço não declare. Exatamente dois bits permitem a um hook modificar a contabilidade do swap, e o Router mascara-os com um único AND antes de qualquer token se mover (`hookAltersDeltas`):

$$
\left(\mathrm{uint160}(\mathrm{hook})\ \&\ \mathtt{0x3FFF}\right)\ \&\ \left((1 \ll 3) \mid (1 \ll 2)\right) \ne 0 \;\;\Longrightarrow\;\; \text{leg refused, } \mathtt{RouterE(9)}
$$
^e18

Nenhuma chamada a código não confiável, nada a enganar, e a evasão exigiria um endereço cujos bits contradissessem a própria imposição do manager. Um proxy pode substituir cada linha da sua lógica e, mesmo assim, não ganhar nenhum bit que o seu endereço nunca teve — e é por isso que esta recusa está a distância de projeção zero (§15.9), ao passo que a fixação do codehash por baixo dela não está.

**Camada 2 — uma lista de permissões, fechada por omissão, com o código fixado.** Um hook com bits limpos pode ainda reverter maliciosamente para fazer griefing ou queimar gas, por isso uma pool V4 só é encaminhável se o seu hook estiver na lista de permissões do curador, e o Hub fixa o codehash do hook na admissão: um hook cujo runtime mude mais tarde é pausado automaticamente sem ser expulso (`isHookLive` falso) e só retoma se for readmitido — um poder que, após a renúncia, é recusado para qualquer hook cujo código tenha mudado. O limite da fixação está declarado no local: vincula o código de runtime, por isso apanha uma reimplantação ou uma mutação direta e não apanha um proxy de delegação cuja implementação seja trocada enquanto o seu próprio runtime se mantém idêntico byte a byte, porque a EVM não dá a um contrato nenhuma forma de ler o storage de outro. Admitir um hook atualizável é um juízo humano que esta fixação não pode substituir. As camadas que não dependem dela mantêm-se de qualquer modo.

**Camada 3 — a rota nem sequer é mostrada.** O projector Ξ remove do conjunto de candidatas do Solver, antes da classificação (`_topKPools`), qualquer pool cujo hook altere deltas, e o canal de leitura do Hub só serve hooks que estejam ativos; uma rota que toque num hook inadmissível não participa na maximização. Uma regra de forma da rota completa-o: ordem canónica, em toda a rota — nenhuma perna sem hook é executada depois de um hook ter corrido (§11.4).

![FIG-11 — Três camadas contra hooks hostis, a mais barata primeiro: a máscara de bits do endereço (nenhuma chamada a código não confiável), a lista de permissões com a fixação do codehash (fechada por omissão), o projector Ξ (rota não representável). Cada camada responde a uma capacidade diferente; o resíduo — um hook limpo e listado que reverte para desperdiçar gas — está nomeado.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-11.png)

Derrotar a pilha exige um hook que não tenha bits de delta, esteja na lista de permissões sem alterações e, mesmo assim, subverta a liquidação — uma combinação que o recurso da Camada 1 à imposição imutável do próprio V4 exclui quanto à alteração de deltas; o resíduo de substituição da taxa da §5.4 permanece, e o piso limita-o. O resíduo está declarado na tabela: um hook na lista de permissões e sem deltas pode ainda reverter a meio do swap e desperdiçar o gas da tentativa. E a alavanca única do crivo está nomeada: o hook crivado vincula o swap executado porque o PoolManager canónico ecoa os dados de unlock literalmente e só chama de volta quem fez o unlock; o `setV4Manager` do Hub, um poder de controlo, é o único endereço em que esse pressuposto assenta, e um manager desonesto faz colapsar a saída medida, de modo que o próprio limite do chamador recusa o swap (campanha `HostileV4Manager`) — limitado, não ausente.

### §14.3 Limitado, não eliminado: desatualização, ordenação e a curva de sandwich

Uma cotação é uma afirmação sobre o passado, e a troca acontece no futuro. A porta de resolução dentro do quadro fecha por completo a metade dessa lacuna que cabe ao operador — a rota é derivada dentro da transação que a executa, a partir das reservas tal como estão nesse bloco. O que resta é a metade da própria chain: a pool pode mover-se entre o momento em que assinas e o momento em que a tua transação é incluída. Ninguém pode impedir isto de dentro de um contrato, porque a ordenação é decidida antes de o código correr; um protocolo que afirme ter eliminado o front-running ou tirou a tua troca da fila pública, confiando em quem quer que agora a detenha, ou está a descrever algo mais estreito do que parece. O que este protocolo faz é limitá-lo, duas vezes e de forma independente: o teu mínimo limita o dano ao número que escolheste, e o piso Iron-Law — re-derivado pelo Router a partir do impacto medido e da cotação dentro do quadro do último hop, e não de nada que o atacante ou a rota tenham fornecido — limita-o outra vez, por conta do próprio protocolo.

O limite é medido do lado do atacante (`test/regime/SandwichCurve.t.sol`): a rota e o piso da vítima são fixados no momento da cotação, como numa transação pendente; o atacante negocia uma fração da profundidade da pool antes da vítima, a vítima executa, o atacante faz a troca inversa. O venue é um par de produto constante — a forma que todos os modelos de sandwich usam — por isso a curva é uma propriedade do piso. Numa troca de 1 % da profundidade (10,000 contra 1,000,000 de cada lado):

| O atacante move | Vítima | Perda da vítima face à cotação | Ida e volta do atacante |
|---|---|---|---|
| 0.1 % da profundidade | liquida | 0.47 % | +13.9 |
| 0.5 % | liquida | 1.26 % | +68.9 |
| 1 % | liquida | 2.22 % | +136.7 |
| 2 % | liquida | 4.12 % | +268.7 |
| 3 % ou mais | **recusada** | 0 | −174.5 … −544.9 |

![FIG-12 — A curva de sandwich do lado do atacante: a perda da vítima face à cotação e a ida e volta do atacante, por fração da profundidade movida antes da vítima; a fronteira de recusa perto de 3 %, fechada para cima.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-12.png)

A garantia verificada em cada ponto: uma vítima liquidada nunca recebe menos do que o piso atestado no momento da cotação, por isso a perda é limitada pela distância entre a cotação atestada e o piso atestado; e a região de recusa é fechada para cima — para lá da fronteira, toda a manipulação maior é recusada e o atacante fica com o preço que moveu nas mãos. O número que vale a pena citar é a última linha liquidada: o piso limita o que um sandwich pode tirar a uma troca de 1 % a cerca de 2.7 % dela, e transforma a troca do atacante numa perda no momento em que tirasse mais. A rota dentro do quadro acrescenta um dissuasor mais discreto: não há um caminho publicado de antemão que um searcher possa estudar, porque o caminho não existe até ao bloco que o executa. Um mínimo largo é um convite; um mínimo apertado é, de todos os controlos desta secção que te pertencem, o mais eficaz.

### §14.4 Venues hostis

As patologias de venue têm a sua própria matriz (§15.5): dez comportamentos anómalos — uma pool que não paga nada, que paga metade, que devolve uma bomba de returndata de 64 KiB, que queima todo o gas na leitura ou no swap, um token cujo `decimals()` nunca retorna, um callback de pagamento disparado duas vezes, uma pool que reentra no Router antes de pagar, um `slot0()` que reverte, uma factory que responde com uma pool de outros tokens — cruzados com a porta de calldata e a porta de resolução, 20 de 20 células a liquidar com o montante entregue igual à diferença de saldo e nada deixado no Router, ou a recusar com um seletor nosso. Um swap que queima todo o gas reencaminhado é a única célula que nenhum chamador pode decidir pelo contrato que chama; a transação reverte por inteiro e o saldo do utilizador fica intacto. Cada leitura protegida que o Core faz a um venue está limitada a `GAS_CAP = 100,000` de gas, por isso um venue que queima gas numa *leitura* custa um montante limitado e é descartado, sem ser fatal.

### §14.5 O front end hostil

Em todos os agregadores alguma vez construídos, a interface propõe o mínimo, e uma interface descuidada propõe-no mal — nenhum contrato pode saber o que terias escolhido. O que um contrato pode fazer é tornar a proposta demonstrável: cada swap emite `ExecutionProof` — a cotação usada, o montante entregue, o piso aplicado — de forma permanente, on-chain, para que a qualidade de execução de qualquer interface seja um registo público, por transação, que qualquer pessoa pode auditar, incluindo tu. Uma interface que proponha consistentemente maus mínimos escreve a sua própria acusação no registo de eventos. A defesa que completa o mecanismo é um hábito: olha para o mínimo antes de assinares; é o único campo que é inteiramente teu.

### §14.6 O que uma chave hostil pode e não pode fazer

Antes da renúncia, existem chaves administrativas, e a forma honesta de as descrever é pela capacidade, assumindo um detentor hostil; a enumeração completa dos poderes está na §16.4.

**O que uma chave hostil do Router pode fazer:** redirecionar o destino da taxa (`setTreasuries`); pausar swaps (`setPaused`); reapontar os contratos WETH e Permit2 que as portas nativa e Permit2 chamam (`setWeth`, `setPermit2`), o que torna essas duas portas apenas tão fiáveis quanto os endereços definidos; pôr em fila e, 48 horas depois, executar um resgate de tokens retidos no Router (`queueRescue`, `executeRescue`, `RESCUE_DELAY = 48 hours`, anunciado on-chain por `RescueQueued`). **O que não pode fazer:** mexer na taxa, na divisão ou nos pisos, porque são constantes de compilação sem setters; levar capital, porque não há proxy, nem caminho de atualização, nem `selfdestruct`, nem aprovação permanente de fundos dos utilizadores a favor do Router, e o Router não guarda nada em repouso — as funções que o fariam não estão desativadas, estão ausentes.

**O que uma chave hostil do Hub pode fazer:** listar um venue ou um hook (`addFactory`, `allowHook`), semear pools (`seedPool`, através de um lugar de operador), pausar a aprendizagem do registo (`setPaused`), reapontar a visão que o Hub tem do Router, do Solver e do Quoter (`setRoles`), e reapontar o manager V4 (`setV4Manager`, a alavanca única do crivo). **O que não pode fazer:** dar mal o preço a uma execução, porque o registo só decide o que é visto (§9.6) — o mais grave que uma listagem hostil alcança é a lacuna entre uma cotação e *o teu mínimo*; o capital está fora de alcance, a tua tolerância de slippage não, o que é mais uma razão para seres tu a definir o mínimo, e de forma apertada.

### §14.7 A Porta de Sentido Único

A autoridade administrativa termina de forma irreversível, no bytecode, e não por promessa. Tanto o Hub como o Router expõem `renounceControl`, e cada um recusa ser chamado enquanto estiver em pausa (`RouterE(2)`, `HubE(2)`): um protocolo pausado e depois renunciado seria um estado terminal que ninguém quer e de que ninguém consegue sair, e pausar vale a pena precisamente porque o controlo se mantém para agir. A flag de renúncia é escrita `true` em exatamente um local de cada contrato e escrita `false` em nenhum, por isso nenhuma função no bytecode implantado pode reabrir a porta — a diferença entre “não vamos” e “não conseguimos”.

O que fecha e o que fica aberto é enumerado, não resumido. No Router, morre tudo o que está sob `onlyControl`: `setAdmin`, `setTreasuries`, `setPermit2`, `setWeth`, `setPaused`, o caminho de resgate — as tesourarias, as ligações e a flag de pausa congelam para sempre nos valores atuais, e o Router continua a executar swaps sob essa configuração fixa. No Hub, morre o **nível de controlo**: `setRoles`, `setOperator`, `setPaused`, `setV4Manager`, `removeBridge` e a *retirada da lista* de hooks. O **nível de curador** sobrevive, e só faz crescer o registo: `addFactory` (recusando, após a renúncia, qualquer factory cujo runtime tenha mudado ou qualquer linha de derivação que se tornaria uma linha de consulta), `addBridge` (só adição, no máximo três, idempotente), `allowHook(h, true)` (recusando um hook listado cujo código tenha mudado); os lugares de operador existentes mantêm `seedPool` e `addV4`, e nenhum lugar novo pode ser concedido. Uma listagem maliciosa após a renúncia não consegue drenar: as pools são validadas na cotação e na execução e limitadas pelo piso e pelo mínimo do chamador. O registo continua a aprender com as trocas. Quem repetir “renunciado” acerca deste protocolo deve ser capaz de dizer que portas ficam abertas — admissão, pontes, listagem de hooks, semeadura curada — e quais fecham: todos os poderes que redirecionam ou congelam.

### §14.8 O que este modelo te pede

O protocolo fecha o que um contrato pode fechar: falsificação de endereços, falsificação de callbacks, falsificação da contabilidade, hooks hostis, aritmética. Limita o que nenhum contrato pode eliminar: a desatualização e a ordenação, através do teu mínimo e do piso. E publica provas contra aquilo que nem sequer pode limitar: um front end que propõe maus mínimos em teu nome. Todas as linhas convergem para o mesmo campo. Define tu mesmo o teu mínimo, deliberadamente, sempre — é a única proteção desta secção cuja qualidade não depende da competência de ninguém senão da tua.

## §15 O aparato de verificação, medido

*Em termos simples:* cada número aqui é impresso ao lado do denominador contra o qual foi medido, é recalculado a partir de um checkout limpo por um script ou por um comando `forge` com nome (Apêndice C), e é seguido daquilo que não estabelece. *Em termos precisos:* a árvore medida é `main` em `8949a9d` e o ramo que lhe deu origem, no perfil de release (`optimizer_runs = 300`, `via_ir`), 2026-09-05.

### §15.1 A suite em números

| O quê | Contagem | Como é contado |
|---|---|---|
| testes declarados | 1,609 funções `test*` / `invariant*` / `check*` em 236 ficheiros `.t.sol` | `grep` sobre `test/` |
| verdes no perfil de release, excluindo as suites de fork | 1,319 passaram · 0 falharam · 1 omitido, de 1,320 | `forge test --no-match-path 'test/fork/**'` |
| verdes em liquidez real | 119 de 119 nas 39 suites da via de fork, cinco chains; mais os três testes na Base real do §12 | `forge test --match-path 'test/fork/**'` com um RPC de arquivo |
| invariantes com estado | 43 funções `invariant_*` em 14 campanhas | `grep -rc 'function invariant_' test` |
| mutantes selecionados, todos eliminados | 268 de 268 | `.github/scripts/mutants.py`; `check_targets.py` |
| matrizes de cobertura de regime | força 2: 63 linhas, todos os 258 pares · força 3: 168 linhas, todos os 1,636 triplos · de 5,184 combinações | `covering_array.py --check` |
| tamanhos entregues (bytes de runtime; limite EIP-170 de 24,576; barreira do projeto de 24,000) | Hub 23,648 · Router 23,781 · Solver 19,686 · Quoter 11,429 · Core 6,442 | `FOUNDRY_PROFILE=release forge build --sizes` |

### §15.2 A cadeia de evidência e a guarda de mutação selecionada

Uma propriedade só vale tanto quanto o caminho mais curto entre uma ameaça e algo que falharia se a propriedade se quebrasse: `threat → property → guard → test → mutant`. Uma guarda é designada pelo símbolo, um teste pelo nome, um mutante pela linha exata que altera; se qualquer dos três sair da árvore, o build falha. Cada teste de regressão da suite foi visto a falhar uma vez, pela razão que lhe dá o nome — uma correção chega com o teste que estava a vermelho contra o código sem ela.

A guarda de mutação contém 268 mutantes escritos à mão, cada um a emparelhar uma linha exata do código-fonte com o único teste que tem de falhar quando essa linha é alterada — uma guarda apagada, uma comparação invertida no limite que decide uma recusa, uma autorização alargada, um código de erro trocado com o do vizinho. Três propriedades fazem dela uma guarda e não uma pontuação: o teste emparelhado é corrido primeiro a verde na árvore não mutada; uma mutação que o otimizador remove — bytecode de runtime idêntico — é reportada como *inerte*, nunca como eliminada; e uma verificação estática de um segundo confirma que cada mutante ainda aponta para exatamente uma linha. 203 de 203 são eliminados. O número é adequação face a *este* registo: uma pontuação saturada é um piso, não um teto.

### §15.3 Mutantes apontados aos invariantes

Até 2026-09-05, nenhum dos mutantes selecionados designava um invariante com estado como o teste que tem de morrer perante ele. As 43 funções `invariant_*` em 14 campanhas estavam a verde, e nada tinha perguntado se alguma delas podia ficar a vermelho: uma campanha cujo handler nunca alcança o estado que uma propriedade protege certifica essa propriedade sobre um universo vazio e, vista de fora, parece idêntica a uma que o alcança. A medição é a da guarda, apontada às campanhas: alterar uma guarda no código-fonte, correr todos os invariantes com uma semente, registar quais deles notam (`docs/assurance/invariant-mutants.json`).

| Mutante | O que remove | Notado por |
|---|---|---|
| a transferência final paga um wei a menos | o não guardar nada | `RouterHoldsNothing`, `routerHoldsNothing`, `HoldsNothingBeyondTheSeed` |
| a taxa do protocolo duplica | o teto da taxa | `FeeNeverExceedsProtocolMax` |
| a taxa do lado da entrada nunca é cobrada | o piso da taxa | `FeeNeverEscapes`, `DeliveredNeverBelowUserMinOut` |
| a taxa é cobrada nos dois lados | uma taxa, um lado | `FeeIsChargedOnExactlyOneSide` |
| 30 % de cada taxa vai para um endereço morto | a conservação | `conservationA/B/C/H`, `TokenConservation`, `LedgerConservationA` |
| a guarda perna-par admite uma perna no par errado | hops homogéneos | `DivergentLegNeverSettles`, `HoldsNothingBeyondTheSeed`, `StrandedMoneyIsNeverSwept` |
| `whenLive` deixa de verificar `paused` | a pausa | `PausedRouterNeverSettles` |
| o bloqueio de reentrância deixa de recusar | o bloqueio | `reentrancyBlocked` |
| o piso do protocolo é reduzido a metade | o piso | `DeliveredNeverBelowTheProtocolFloor` — fechado em 2026-09-05 |
| `MAX_SLOTS` passa a 17 | o limite do registo | `neverExceedsMaxSlots` |
| a prova de par no registo é removida | a autenticidade do par | `ActiveEntriesTradeThePair` — fechado em 2026-09-05 |
| o varrimento do resíduo de entrada ignora a sua linha de base | dinheiro retido | `StrandedMoneyIsNeverSwept`, `HoldsNothingBeyondTheSeed` |
| o varrimento do resíduo de ponte ignora a sua linha de base | dinheiro retido | o mesmo par — fechado em 2026-09-05 |
| a medição da saída ignora a sua linha de base | dinheiro retido | o mesmo par |
| a verificação de `userMinOut` pós-taxa é reduzida a metade | — | sobrevive, por desenho: uma sentinela de regressão inalcançável em universos de campanha sem token de saída com taxa na transferência; dois mutantes unitários vigiam-na |

![FIG-13 — Mutantes apontados aos invariantes: quinze mutações do código-fonte contra quarenta e três invariantes com estado, os invariantes que ficaram a vermelho por mutante, os três fechados em 2026-09-05 ao dar a uma campanha a ação que lhe faltava, e a única sentinela que sobrevive por desenho.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-13.png)

Onze de quinze foram notados na primeira medição; vinte nomes distintos de invariantes ficaram a vermelho pelo menos uma vez. Três dos quatro sobreviventes foram fechados no mesmo dia ao dar a uma campanha a ação que lhe faltava — pools alheias oferecidas sob o par, uma rota de dois hops sobre um saldo intermédio pré-semeado, uma baleia a mover a pool 0–8 % contra uma rota cotada antes de a rota desatualizada ser executada — cada um verificado a vermelho sem a sua guarda; duas guardas sem qualquer tipo de vigia era o número que esta medição existia para imprimir, e agora é zero. Catorze de quinze são notados; os catorze são entradas da guarda emparelhadas com o invariante que morre perante eles. Uma suite verde com uma guarda não vigiada lá dentro foi a forma de ambas as regressões documentadas nesta base de código; a medição que encontra uma corre agora sobre cada guarda que as campanhas reivindicam.

### §15.4 Matrizes de cobertura de regime

Os critérios de cobertura indexam o código; a mutação indexa uma falha injetada; nenhum dos dois indexa o estado que uma *fixture* fixa antes da chamada. São enumerados dez desses fatores — família de venue (V2, V3, Solidly), hops (1–3), pernas por hop (1–2), se o token de entrada é uma ponte registada, se o intermédio o é, a forma da taxa na transferência (nenhuma, só na recolha, em cada transferência), as casas decimais do token de entrada (18, 6), a porta (rota em calldata, resolução na transação, Permit2), o controlo (ativo, renunciado) e se o par está cheio — 5,184 combinações. `covering_array.py` gera matrizes em que cada par (força 2) ou cada triplo (força 3) de valores de fatores aparece em pelo menos uma linha, sendo cada linha uma fixture passada por um harness (`test/regime/RegimeHarness.sol`) com uma só asserção: o swap liquida, com o montante entregue igual ao delta do saldo do destinatário, pelo menos o piso que o Router emitiu e nada deixado no Router — ou é recusado com um seletor nosso. Um panic, um seletor alheio, uma entrega a menos ou um saldo retido é uma terceira via e faz falhar a linha.

| Força | Linhas | Tuplos cobertos | Liquidadas | Recusadas, nossas | Não construíveis | Terceira via |
|---|---|---|---|---|---|---|
| 2 | 63 | 258 pares | 53 | 4 | 6 | 0 |
| 3 | 168 | 1,636 triplos | 158 | 10 — `SolverE(5)` ×7, `RouterE(13)` ×3 | 0 | 0 |

![FIG-14 — Matrizes de cobertura de regime: resultados de cada linha gerada com força 2 (63 linhas) e força 3 (168 linhas) — liquidada, recusada com um seletor nosso, não construível, terceira via — sobre 5,184 combinações de dez fatores.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-14.png)

As recusas são o planeador sem caminho com ponte para construir e o executor a recusar um token taxado numa rota só concentrada; as seis linhas com força 2 que não podem ser construídas (o token taxado só na recolha não tem forma com seis casas decimais) são impressas pelo nome e contam no denominador. As famílias que não estão na matriz — V4, V4 nativo, Algebra, a porta nativa, hooks — estão declaradas em `regimes-covering.json`. A primeira execução da matriz tornou explícito um quadro que os testes de paridade só tinham fixado de um lado: o piso que o Router impõe é igual ao piso atestado quando a taxa é retirada da saída, e fica dentro de $[\mathrm{attested} \times (1 - \mathrm{fee}), \mathrm{attested}]$ quando é retirada da entrada — ambos os quadros são agora afirmados em cada linha. O ficheiro gerado é verificado contra o seu gerador na CI, por isso a matriz não pode derivar dos fatores que afirma cobrir.

### §15.5 A matriz de venues hostis

As patologias de tokens tinham os seus testes; as patologias de venues não tinham nenhum numa matriz. `test/regime/HostileVenues.sol` contém um mau comportamento por venue e `HostileVenueMatrix.t.sol` cruza cada um com a porta de calldata e a porta de resolução sob a regra da matriz de cobertura:

| Venue | Porta de calldata | Porta de resolução |
|---|---|---|
| não paga nada / paga metade | recusado `RouterE(5)` | recusado `RouterE(5)` |
| bomba de returndata na leitura das reservas | liquida | liquida |
| a leitura das reservas queima todo o gas | recusado `RouterE(8)` | o planeador nunca o seleciona |
| o swap queima todo o gas | toda a transação reverte, saldo intacto | toda a transação reverte, saldo intacto |
| `decimals()` queima todo o gas | liquida | liquida |
| callback de pagamento disparado duas vezes | recusado `RouterE(6)` | recusado `RouterE(6)` |
| reentra no Router antes de pagar | liquida; o swap aninhado nunca correu | liquida; o swap aninhado nunca correu |
| `slot0()` reverte | liquida pela cotação atestada | o planeador nunca o seleciona |
| a factory responde com uma pool de outros tokens | nunca listada | nunca listada |

Vinte de vinte células: liquidam ou recusam com um seletor nosso, nunca uma terceira via. A última linha é o que a primeira execução da matriz mudou — a descoberta listava uma pool com que uma factory admitida por um curador respondia, e o executor recusava-a na costura que paga; uma pool pedida prova agora o seu próprio par antes de a descoberta a listar (§7).

### §15.6 Oráculos canónicos

Cada mock da suite cota com as próprias fórmulas do Core, por isso um defeito numa fórmula é invisível para todos os testes de paridade que as usam: o oráculo é o objeto. `test/regime/CanonicalOracles.t.sol` contém três implementações escritas a partir dos invariantes publicados dos venues — produto constante com a taxa na entrada, o passo de preço em raiz quadrada do V3 num só tick com o arredondamento da própria pool contra quem negoceia, a curva estável Solidly resolvida pelo método de Newton — e faz fuzz do Core contra elas, 5,000 execuções cada, afirmando primeiro a direção (o Core nunca promete mais do que a matemática do venue entrega) e depois o aperto.

| Família | Direção | Aperto medido |
|---|---|---|
| Uniswap V2 | o Core nunca excede a especificação | exato ao wei |
| Solidly estável | o Core nunca excede a curva em mais do que o último passo do próprio solver | dentro de 4 wei |
| Uniswap V3 | o Core nunca excede a especificação em mais de uma unidade na última casa (ulp) do preço em raiz quadrada, equivalente a $L / 2^{96}$ wei | abaixo de um wei para todas as pools com $L < 2^{96}$ |

O limite do V3 é expresso na quantidade que o causa — a pool arredonda o seu novo preço contra quem negoceia e o Core arredonda-o uma vez, por isso os dois podem diferir numa unidade de $\sqrt{P}$ — e a asserção é o limite, não a amostra (13 wei numa saída de $6.5 \times 10^{34}$ com $L = 10^{30}$). Os oráculos são escritos a partir das especificações, não a partir do bytecode dos venues; esse é o seu limite.

### §15.7 Relações metamórficas

Um oráculo escrito a partir da mesma fórmula não consegue apanhar a fórmula. Uma relação metamórfica pergunta antes como a saída se tem de *mover* quando a entrada se move, e a própria curva do venue responde a isso sem uma implementação de referência. `test/CoreMetamorphicRelations.t.sol` contém catorze relações sobre a matemática de cotação do Core e `test/RouteMetamorphicRelations.t.sol` cinco sobre o plano do Solver num universo de duas pools com um Hub real e um Solver real:

| Nível | Relação | O que diz |
|---|---|---|
| Core, V2 · V3 · estável | MR1 monótona | mais entrada, nunca menos saída |
| Core, V2 · V3 · estável | MR2 subaditiva | dividir uma ordem pela mesma pool nunca ganha |
| Core, V2 · estável | MR3 sem ida e volta | entrar e depois voltar pelas reservas atualizadas nunca devolve mais do que entrou |
| Core, V2 · V3 · estável | MR4 equivariância de escala | escalar a ordem e a pool em conjunto escala a saída, a menos do arredondamento |
| Core, V2 · V3 | MR5 monótona na taxa | uma taxa mais alta nunca paga mais |
| Core, V3 | MR6 simetria de direção | ao preço 1.0 os dois ramos de `outV3` concordam a menos de dois ulps |
| Core, Solidly | MR7 identidade | o ramo volátil *é* `outV2`, um só produtor |
| plano | MR-R1 | a divisão nunca paga menos do que pagaria a melhor pool isolada |
| plano | MR-R2 | monótona em `amountIn` |
| plano | MR-R3 | acrescentar uma pool dentro da banda de preço nunca baixa o plano |
| plano | MR-R4 | a ordem de registo move o plano no máximo uma unidade de peso da divisão |
| plano | MR-R5 | o piso atestado nunca excede a saída esperada |

Três dos limites foram medidos antes de serem escritos, e o número na asserção é o mecanismo, não a amostra. MR6: com $L = 8.5 \times 10^{37}$ e 1,374 wei de entrada, um ramo cotou 1,073,741,823 wei — exatamente $L / 2^{96}$, um ulp — enquanto o outro cotou zero, com o seu passo arredondado para nada, falhando fechado; a relação estabelece dois ulps, um por ramo. MR-R1 e MR-R3: com uma pool com preço a $10^{10}$ de distância da outra, o plano pagou 35 % menos do que a pool atípica sozinha — a mediana ponderada pela profundidade a recusar acreditar nela — por isso as relações valem sobre as pools que a banda admite, e o domínio mantém os dois preços dentro de ±4 %. MR-R4: uma pool cujo peso de profundidade é arredondado por defeito até ao mínimo é mantida como perna de dust quando registada primeiro e cortada quando registada em segundo lugar, o que move o plano em $3 \times 10^{-7}$ da saída — manter ou cortar uma pool de peso mínimo na divisão depende da sua posição, e isso está agora escrito onde foi encontrado.

### §15.8 N-versão: o mesmo código-fonte sob outra geração de código

A suite executa um só binário — o que as definições de release emitem, e `profile_parity.py` mantém a suite nessas definições. Qualquer outra definição do otimizador é um programa diferente compilado a partir do mesmo código-fonte, e o compilador é um componente. `test/nversion/` compila a matemática de cotação do Core sob mais dois perfis — `optimizer_runs` 1 e 20,000, tudo o resto idêntico — e `NVersionCore.t.sol` implanta os três binários lado a lado e afirma a igualdade sobre entradas geradas por fuzz: `outV2`, `outV3`, `outSolidly`, `outSolidlyStable`, `mulDiv`, `mulDivUp`, 3,000 execuções cada sobre todo o domínio de entrada. A via afirma primeiro que o bytecode alternativo *difere* do entregue, para que não possa passar comparando um programa consigo próprio, e um artefacto em falta é uma falha, não uma omissão.

**Os três binários concordam.** O compilador não foi o achado. A primeira execução da via sobre o domínio completo fez reverter a *referência*: a verificação de ajuste da curva estável dividia `max · WAD / b`, e essa própria divisão entrava em overflow numa pool com menos de uma unidade de um token; uma segunda fuga — uma reserva de entrada de baleia contra uma reserva de saída de dust — passava a verificação do invariante e provocava overflow na derivada. Nenhum dos dois era um número errado; ambos eram reverts dentro de uma cotação, e `universalQuote` é um `DELEGATECALL` de biblioteca, por isso uma pool registada com um wei do token de saída desfazia o plano do Solver para o seu par. A reparação (§6) faz a pergunta que a divisão substituía e entrou com um teste escrito primeiro a vermelho; uma guarda adicional — um teto ao iterado de Newton — foi escrita, considerada inobservável por qualquer teste quando as duas verificações se mantêm, e removida em vez de ser mantida. A sua classe é a que este repositório nomeia em primeiro lugar — falhar aberto — encontrada por um instrumento que não a procurava.

### §15.9 Distância de projeção

Todos os defeitos confirmados neste repositório, internos ou reportados, têm uma só forma: uma verificação observa um objeto enquanto um objeto *diferente* decide o comportamento. Isso faz com que a propriedade interessante de uma recusa não seja a sua complexidade, mas a sua distância — quão longe o que ela lê está daquilo que decide. `projection_distance.py` classifica o predicado que guarda cada `revert` nos cinco contratos: uma constante, um imutável, um delta de saldo ou uma quantidade calculada dentro do quadro a partir de um destes está à distância 0; um campo da rota do chamador, ou uma consulta ao storage mutável de outro contrato, está à distância 1; uma propriedade de um contrato que pode delegar o seu comportamento é ilimitada. Em 99 pontos de recusa: **86 à distância 0, 11 à distância 1, 2 ilimitados.** Os dois pontos ilimitados são ambos fixações `EXTCODEHASH` — o código de um hook admitido e o de uma factory admitida — e não são simétricos: para os hooks, o resíduo é fechado pelos bits do endereço que a fixação não transporta (§14.2); para as factories não há equivalente, e o resíduo é limitado pela admissão de pools, pelo piso por perna e pelo mínimo do utilizador, por isso o dano é degradação da rota e não drenagem, documentado no próprio ponto. O limite do crivo: lê um predicado e não consegue ver que um valor foi restringido três quadros acima; um campo declarado pelo chamador que é também o seletor da pool está à distância 0 só porque uma atribuição os liga, e essa atribuição é fixada por `test/V4SievedHookIsTheExecutedHook.t.sol`.

### §15.10 Independência da evidência, o registo de quantidades partilhadas e o artefacto

Para cada guarda que suporta carga, o aparato regista quantas confirmações *independentes* existem — por fonte, oráculo, ferramenta, ambiente e metodologia — e reporta o mínimo, porque uma cadeia de evidência falha no seu elo mais fraco; as propriedades que suportam carga são confirmadas por pelo menos duas vias que não partilham nenhuma hipótese. O registo de quantidades partilhadas (`SHARED_QUANTITIES.md`) enumera todas as quantidades com mais de um produtor ou consumidor, declara a *pergunta* a que cada uma responde e classifica o que liga as cópias — `SINGLE`, `PINNED`, `WEAK`, `OPEN`, `UNVERIFIED` — com uma regra de CI que despromove uma linha cujo teste não alcança o que afirma fixar; todas as quantidades com dois produtores no registo relacional (7 de 7) estão ligadas por um teste com nome. E o artefacto compilado é lido, não só o código-fonte: opcodes que nunca podem aparecer (`SELFDESTRUCT`, `CALLCODE`, `ORIGIN`); os opcodes transitórios ainda presentes no executor, pelo que o bloqueio de reentrância não se tornou discretamente storage persistente; cada função declarada presente no despachante; três dos cinco contratos a emitir zero escritas em storage; 88.3 % do fluxo de instruções na forma entregue provado como executado por um limite inferior sólido, verificado contra um contrato de referência de verdade conhecida que o instrumento tem de classificar corretamente antes de imprimir; e, para um swap V2 honesto gravado e reproduzido no Router de release com o opcode verificado em cada passo, 4,382 instruções do Router e 407 instruções do Hub executadas, zero discrepâncias — 28.2 % e 2.5 % das duas secções de código, sendo o complemento código que nenhum cenário gravado executou, não código morto.

### §15.11 O que nada disto estabelece

- **Nenhuma probabilidade de correção.** A literatura sobre a validação de fiabilidade ultraelevada é explícita quanto a os testes não conseguirem produzir uma; aqui não se declara nenhuma.
- **A adequação por mutação é adequação face a este registo.** É selecionado à mão; uma pontuação saturada é um piso.
- **As coberturas de ameaças e de regimes são pisos sobre o que foi considerado.** Classes e fatores que ninguém nomeou ficam fora do denominador por construção.
- **As distribuições do §12 são sobre mocks.** A Base real dá alcance, não uma distribuição.
- **As taxas de deteção são por teste, com 256 execuções de fuzz por semente.** Um teste que falha a deteção com esse orçamento pode detetar com um maior.
- **Este repositório é a V2, e a V2 não está implantada** (§19).

Cada instrumento acima foi calibrado antes de o seu número ser impresso: corrido primeiro contra um defeito já conhecido por outra via, e corrigido onde não o detetou — um comparador de texto que lia documentação como comportamento porque comparava texto dentro de comentários, uma regex de cobertura que não previa um bloco de opções de chamada, uma pesquisa de contrapartes cuja lista de padrões estava vazia. Um instrumento não vale nada enquanto não encontrar a instância já conhecida; um veredicto sem pesquisa é vacuidade; e tudo o que o compilador decide é medido, nunca estimado.

Não conhecemos nenhuma outra base de código DeFi pública que publique uma guarda de mutação selecionada e nomeada, com testes que eliminam cada mutante e relato de mutações inertes; um registo de quantidades partilhadas com uma regra de CI que o despromove; mutantes apontados aos seus invariantes com estado, com o sobrevivente publicado; uma matriz de cobertura de força 3 sobre os seus fatores de regime sob uma só asserção; testes N-versão da sua matemática de cotação; uma curva medida de como as suas cotações envelhecem; ou a taxa de deteção dos seus próprios mutantes de taxa com um intervalo de confiança. Os artefactos estão no repositório; se encontrares uma instância anterior, a afirmação está errada e gostaríamos de saber.

## §16 Arquitetura e tamanhos

*Em termos simples:* cinco contratos, um dos quais é matemática pura importada pelos outros quatro, e nenhuma peça de matemática é definida duas vezes. *Em termos precisos:* o Core é uma biblioteca sem estado, sem storage, sem proprietário e sem caminho de atualização; Hub, Solver, Router e Quoter importam-no e nenhum redefine uma primitiva, por isso uma só auditoria da matemática cobre todos os consumidores.

### §16.1 Cinco contratos: o que cada um guarda, o que cada um pode chamar

| Contrato | Guarda | Pode chamar | Escreve estado persistente | Tamanho (bytes de runtime) |
|---|---|---|---|---|
| **Core** (biblioteca) | nada — funções pure e view: Ω, 𝒟, Φ, Ψ, o codec do Monoslot, transferências seguras, `mulDiv` | pools e tokens, só leitura, cada `staticcall` protegido limitado a `GAS_CAP = 100,000` | nunca — nem `tstore`, nem `sstore` | 6,442 |
| **Hub** | o registo (um Monoslot por pool, ≤ 16 por par), linhas de factories (≤ 16), pontes (≤ 3), lista de permissões de hooks com fixações de codehash, entradas V4, papéis; com namespace ERC-7201 | pools e factories, só leitura, através do Core; o PoolManager V4 via `extsload` | em `recordSwap` (só o Router), na admissão e na configuração | 23,648 |
| **Solver** | nada — só `view` | o Hub (leituras do registo, descoberta), pools através do Core | nunca | 19,686 |
| **Router** | administrador, tesourarias, `permit2`, `weth`, `paused`, `controlRenounced`, fila de resgate; **nenhum saldo de tokens em repouso** | o token de entrada, as pools da rota, o token de saída, o Hub (`isBridgeToken`, `isHookLive`, `recordSwap`), o Solver (só `swapBestExactIn`, `view`), WETH e o PoolManager para V4, Permit2 para a sua porta, as tesourarias, o destinatário — nunca um alvo fornecido pelo chamador | a sua própria configuração; a única escrita externa por swap é `Hub.recordSwap` no caminho de sucesso | 23,781 |
| **Quoter** | nada | o Solver (`view`), o Hub (`isBridgeToken`, só leitura), pools para a execução de ensaio da Passagem Exata (chamadas e revertidas) | nunca | 11,429 |

![FIG-15 — Topologia de cinco contratos: o Core (matemática pura: Ω · 𝒟 · Φ · Ψ) importado pelo Hub (registo, estado Ψ, pontes, fixações de hooks), pelo Solver (otimizador de rotas, view), pelo Router (execução atómica, o único contrato que move fundos) e pelo Quoter (pré-visualização, view e execução de ensaio). As setas são chamadas; a única seta sólida para o storage por swap é Router → Hub.recordSwap; todas as outras setas que partem do Solver e do Quoter são apenas view.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-15.png)

A confiança corre num só sentido. O Hub confia no Router para chamar `recordSwap` (`onlyRouter`) e em mais ninguém; o Router confia no Hub para três factos de que uma rota precisa — se este token é uma ponte, se este hook está ativo, e a escrita do registo — e para nada que dê preço a uma troca. O Solver confia no registo do Hub apenas como uma lista de coordenadas a medir. O Quoter confia no plano do Solver a título indicativo e reavalia o preço das pernas concentradas contra as próprias pools. Nada confia no calldata: uma rota chega ao Router como a afirmação de um estranho.

### §16.2 A vida de um swap

![FIG-16 — A vida de um swap: `previewAndEncode` (view) → calldata → uma porta → `_execute` → venues → liquidação, com a verificação de cada passo designada pelo seu código de recusa: mínimo e prazo na porta; forma e continuidade dos hops; chegada medida; por hop, reescalamento, taxa se este for o hop da taxa, piso por perna e barreira de cobertura, agregado do hop; varrimentos; saída bruta; o piso da rota Φ; a taxa do lado da saída, se houver; entrega medida no destinatário; `userMinOut`; o livro-razão das taxas; `recordSwap` por perna executada; `ExecutionProof`.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-16.png)

1. **Pré-visualização** (off-chain, gratuita): `previewAndEncode` corre `findBestRoutePlan` — registo e, se não for recente, descoberta; Ξ; classificação Ψ; sondas; a banda; alocação; o limitador; a barreira de divisão; o piso atestado — e devolve o `Preview` e o calldata. Quem negoceia define `userMinOut` a partir da sua própria expectativa de preço.
2. **A porta**: `swapExactIn` (ou uma função irmã) verifica o prazo (`RouterE(4)`), recusa um mínimo zero (`RouterE(10)`), recolhe a entrada e mede o delta.
3. **`_execute`**: número de hops, pernas por hop e continuidade dos hops (`RouterE(3)`); a análise da taxa; linhas de base criadas uma só vez.
4. **Por hop**: reescalar face à chegada medida; cobrar a taxa se este for o hop da taxa (ou em cada hop, em exaustão); ler cada pool uma vez para montante, impacto e cotação; executar cada perna pela forma que o seu tipo seleciona (`RouterE(8)` para um tipo desconhecido, `RouterE(9)` para um hook que altera deltas); o piso por perna com a barreira de cobertura e o agregado do hop (`RouterE(5)`); o callback paga apenas à pool comprometida (`RouterE(6)`).
5. **Varrimentos**: a entrada não gasta e os resíduos de ponte acima das suas linhas de base regressam ao pagador.
6. **Liquidação**: saída bruta como delta (`RouterE(8)` se for zero); `floorBps` a partir do impacto medido e da concentração; o piso da rota face à cotação dentro do quadro do último hop e o máximo entre três valores (`RouterE(5)`); a taxa do lado da saída numa rota direta para uma moeda-ponte; transferência, entrega medida no destinatário, `userMinOut` sobre o montante entregue (`RouterE(5)`); o livro-razão das taxas (`RouterE(15)`, `RouterE(16)`).
7. **A única escrita**: `Hub.recordSwap` por perna executada, com montantes medidos; depois, os eventos `ExecutionProof`, `Swap` e `Fee`. Nada é escrito quando alguma verificação recusa; a transação, incluindo o swap de cada pool, nunca aconteceu.

### §16.3 Tamanhos face ao EIP-170

| Contrato | Bytes de runtime | Abaixo da barreira de 24,000 bytes | Abaixo do EIP-170 (24,576) |
|---|---|---|---|
| Router | 23,781 | 219 | 795 |
| Hub | 23,648 | 352 | 928 |
| Solver | 19,686 | 4,314 | 4,890 |
| Quoter | 11,429 | 12,571 | 13,147 |
| Core | 6,442 | 17,558 | 18,134 |
| Total | 84,986 | | |

![FIG-17 — Tamanhos de runtime dos cinco contratos face à barreira de 24,000 bytes do projeto e ao limite EIP-170 de 24,576 bytes, medidos no perfil de release; o router V1 implantado (14,624 bytes) como referência de escala.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-17.png)

A barreira é afirmada dentro da própria suite (`DeployedSizeGate`) no mesmo perfil em que a suite corre, que `profile_parity.py` mantém idêntico ao perfil de release — uma suite que testasse um binário que a chain não pudesse aceitar estaria a testar o objeto errado. O tamanho é medido, nunca estimado: uma guarda estimada em dezenas de bytes chegou a medir várias centenas porque a forma escolhida prolongava o intervalo de vida de uma variável. O Router e o Hub estão a poucas centenas de bytes da parede, e é por isso que a prova de par do §9 custa 179 bytes e a reparação da curva estável do §6 é 35 bytes *mais pequena* do que o código que substituiu: cada byte acrescentado é pago com um byte removido.

### §16.4 A superfície de ataque, contada

Uma superfície de ataque é o que um adversário pode escrever, o que um contrato guarda, quem ele chama e quem detém poder sobre ele. Aqui, cada uma destas é uma quantidade contável.

**O que um chamador pode escrever.** Uma rota é uma estrutura tipada — no máximo 3 hops × 5 pernas, cada perna com dez campos (`pool`, `hooks`, `kind`, `fee`, `tickSpacing`, `zeroForOne`, `stable`, `amountIn`, `expectedOut`, `auxId`) — e nenhum campo designa um alvo de chamada nem transporta um blob de calldata. `docs/assurance/fields.json` classifica cada campo que o chamador pode escrever e que chega ao estado, a um evento ou a uma guarda, 23 no total:

| Classe | Contagem | Significado | Exemplos |
|---|---|---|---|
| **confirmado** | 14 | a execução lê o campo *e* uma verificação compara-o com uma observação | `leg.kind` re-derivado a partir da forma da pool (Hub `recordSwap`); `leg.fee` em pools concentradas, onde a pool responde; `leg.amountIn`, reescalado pela chegada medida; `leg.expectedOut`, elevado pela barreira de cobertura; `hop.tokenIn`/`tokenOut`, sujeitos a barreira face aos próprios `token0`/`token1` da pool; `leg.hooks` e `leg.auxId` em V4, que entram no id da pool executada |
| **direcional** | 5 | o campo dirige um movimento de tokens, por isso um valor falso pune o chamador e não precisa de verificação separada | `leg.pool` em venues de par e concentrados (os tokens são empurrados para ela); `leg.zeroForOne` em V4 (uma direção errada falha fechado na contabilidade do gestor); `route.singleOutFloor` (monótono — só pode apertar); os campos indicativos da rota (`totalOut`, `estGas`, …), que ninguém lê |
| **declarado** | 4 | chega ao estado, a um evento ou a uma guarda, e nada o observa — cada um com a sua razão registada | `leg.fee` em pares V2 (nenhum par expõe `fee()`; limitado pelo teto de 100 bps e usado igualmente pela cotação e pela execução, por isso as duas não podem divergir); `leg.hooks` em pernas não V4 (alimenta apenas a ordenação que coloca as pernas com hook no fim; uma mentira custa ao chamador a sua própria rota); `leg.expectedOut` tal como publicado no evento `Volume` (limitado perto de +25 % pelo piso por perna que consome o mesmo campo; nenhum consumidor on-chain); `leg.stable` (o Hub mede `stable()` no registo e ambos os consumidores leem a mesma declaração) |

A classificação do registo, o piso do protocolo e a base da taxa são calculados apenas a partir de quantidades confirmadas. O Hub confirma `kind`; o Router confirma os montantes, os tokens e as taxas das pools concentradas; a derivação confirma os campos V4 por construção.

**O que o Router guarda entre transações.** Saldo de tokens zero — `INV-1`, afirmado por `invariant_RouterHoldsNothing`, `invariant_routerHoldsNothing` e `invariant_HoldsNothingBeyondTheSeed` ao longo das campanhas, e vigiado por quatro mutantes de guarda (uma transferência com um wei a menos, e cada uma das três linhas de base removida). As taxas fluem para as tesourarias dentro do swap; os resíduos regressam ao pagador dentro do swap; a única coisa que pode ficar no Router é um envio por engano, que o resgate de 48 horas existe para devolver e que as linhas de base de cada swap excluem do pagamento. Três dos cinco contratos — Core, Solver, Quoter — não emitem qualquer escrita em storage.

**Quem um swap chama.** As contrapartes de um swap formam um conjunto fechado de oito classes: o token de entrada; o token de saída; as pools que a rota designa (no máximo 15); o Hub; o Solver, só através de `swapBestExactIn` e só como view; WETH e o PoolManager, só para pernas V4 e nativas; Permit2, só através da sua porta; as tesourarias e o destinatário. Não há uma nona: o executor não aceita nenhum alvo de chamada fornecido pelo chamador (SOK-ARBITRARY-CALL) e despacha a interação com os venues a partir de um conjunto fechado de formas selecionadas por um tipo guardado no registo. Cada leitura protegida está limitada a 100,000 gas. A contagem exata de instruções de um swap é registada em vez de afirmada: 4,382 instruções do Router para um swap V2 honesto no binário de release, com o opcode verificado em cada passo (§15.10).

**Quem detém poder.** Nove funções de controlo no Router e seis no Hub, todas enumeradas em §14.6–§14.7 com o que podem e não podem alcançar; nenhuma pode mover capital, a taxa, a divisão ou os pisos; todas terminam em `renounceControl`, e o que sobrevive é o nível de curador de quatro funções, que só pode crescer, mais os lugares de operador existentes. Não há `selfdestruct`, nem proxy, nem inicializador depois do `initialize` único do Hub, e os únicos `delegatecall` no artefacto são os do próprio compilador para a biblioteca pública Core.

**O que tem de existir para uma troca liquidar.** O orçamento do §3.1: nenhum serviço de encaminhamento, nenhum oráculo, nenhuma rede de solvers, nenhum keeper, nenhum proxy — cinco zeros onde o desenho dominante tem “obrigatório”, “comum” ou “varia”.

**A diferença contada.** Face a um desenho que obtém a sua rota off-chain e executa uma lista genérica de chamadas, ou que guarda inventário:

| Superfície | Este desenho | Executor resolvido off-chain | Venue ou router que guarda inventário |
|---|---|---|---|
| campos que o chamador pode escrever e que chegam a uma guarda | 23, dos quais 14 confirmados face a uma observação e 0 designam um alvo de chamada | uma lista de pares `(target, calldata)`: ilimitada, e cada alvo é uma chamada que o contrato faz pela palavra do chamador | — |
| saldo de tokens em repouso no executor | 0 (`INV-1`) | tipicamente 0 | o próprio inventário |
| contratos que escrevem storage durante um swap | 1 (`Hub.recordSwap`, uma escrita por perna executada, só no caminho de sucesso) | varia | a contabilidade do venue |
| quem calcula a rota | a chain (`findBestRoutePlan`, `view`) ou o chamador, medida de novo dentro do quadro em qualquer dos casos | um servidor; o contrato verifica, não escolhe | — |
| oráculos, keepers, proxies, caminhos de atualização | 0 | geralmente ≥ 1 de cada | geralmente um proxy |
| funções privilegiadas que podem alcançar o capital | 0 | um administrador do proxy pode substituir a lógica | varia |
| bytes implantados que um auditor tem de ler | 84,986, cinco contratos, todos abaixo do EIP-170 | o contrato de liquidação, mais um servidor cujo tamanho em linhas auditáveis é impossível de conhecer | — |

A comparação é contada, não argumentada: a diferença é uma rota limitada, tipada e confirmada contra uma lista ilimitada; zero contra inventário; uma escrita contra muitas; e uma rota que a chain derivou — ou que o chamador derivou e a chain voltou a medir — contra uma rota que um servidor derivou e a chain apenas verificou.

## §17 Desempenho medido

*Em termos simples:* tudo nesta secção foi medido em forks de chains reais — venues reais, reservas reais depositadas por desconhecidos, um único bytecode — e é rotulado exatamente como tal. *Em termos precisos:* um número só aparece aqui se um harness de teste público no repositório o reproduzir; o harness, a chain e a data são impressos ao lado. Uma medição em fork é evidência sobre comportamento, não um registo de implantação; o registo de implantação é o §19. As medições do §12 e do §15 são de 2026-09-05; a campanha desta secção foi realizada em agosto de 2026 e os seus harnesses estão em `test/fork/`.

### §17.1 Identidade entre chains

O mesmo bytecode foi exercitado em forks de Ethereum, Arbitrum, Optimism e Base, adaptando-se à combinação de venues de cada chain — Aerodrome e Pancake ao lado do V4 na Base, Camelot na Arbitrum, Velodrome na Optimism — sem qualquer alteração de código por chain. As quatro chains foram escolhidas porque, em conjunto, exercitam todas as famílias de venues que o registo admite, pelo que um caso especial por chain, se existisse, teria tido quatro oportunidades de vir à tona. Em cada chain foram medidas duas identidades contra a verdade de referência: para a derivação CREATE2, cada endereço de pool calculado por 𝒟 contra o endereço que a própria factory da chain indica para o mesmo par e os mesmos parâmetros, com `hasCode` a confirmar bytecode em cada endereço derivado; para a Passagem Exata, o próprio swap do venue chamado sobre o estado ao vivo e os seus deltas transportados no payload do revert, por chain, sobrevivendo às convenções de callback de cada família, incluindo as da Algebra. Ambas as identidades se verificam nas quatro chains, e a coluna de diferenças de que a tabela precisaria está vazia.

### §17.2 Fidelidade pré-visualização → entrega em quatro chains

A tese admite uma medição direta: cotar um swap, executá-lo, comparar. O harness de fork `FidelityMatrix` cota, executa e liquida pares reais na Arbitrum, Base, Optimism e Robinhood Chain em blocos fixados e imprime a pré-visualização contra a entrega para cada par em que toca; tem um alarme permanente a 50 bps, pelo que uma regressão de fidelidade se anuncia sozinha. Medido em 2026-08-24:

| Chain | Pré-visualização → entrega | Registado em paralelo |
|---|---|---|
| Arbitrum | 0–1 bps em cada par executado | a rota do Solver coincide com uma grelha exaustiva de divisão em duas vias em passos de 10 % |
| Base | 0–1 bps | a menos de 0.13 bps do máximo da grelha; execuções reais de 222,000–326,000 gas, tudo incluído |
| Optimism | 0–1 bps | a primeira execução encaminhada por V4 medida em fork por este motor na Optimism |
| Robinhood Chain | 0–1 bps | exato face à grelha; as primeiras execuções medidas na chain |

A matriz executa de ponta a ponta pernas de produto constante, concentradas, V4 — nativo incluído — e Solidly. A banda é de um ponto base em cada par executado, com um alarme de 50 bps por trás; a comparação Solver-versus-grelha do §17.1 é o único resultado que coincide à unidade, e é apresentado como tal. Dois resultados comportamentais vêm a par: os intermediários de ponte são selecionados de forma adaptativa por par como o maximizador da Meta-Equação, e um par deliberadamente isolado não devolve qualquer rota em vez de devolver uma fabricada.

### §17.3 O censo de factories

O registo de um venue é uma afirmação, e a afirmação tem o seu próprio instrumento. O harness de censo (`FactoryCensus`) herda a ligação de implantação de produção — implanta através do mesmo script que as chains recebem, atrás de uma barreira de igualdade que se recusa a correr se houver deriva entre o harness e a implantação. Vive com esse script na árvore de implantação privada e não está no repositório público, pelo que a tabela abaixo é reportada, não reproduzível a partir deste checkout; a varredura pública que partilha as suas fixtures e a sua barreira anti-vacuidade é `test/fork/TokenSweep.t.sol`. Reporta, para cada factory registada em cada chain sobre um corpus fixo de tokens, três colunas: registada, tem uma pool para o par, ganhou o par (forneceu uma perna da rota vencedora). As colunas partilham um denominador, os pares de hop, com um balde explícito de não resolvidos que mediu zero nas quatro chains: cada perna que o motor encaminhou é atribuída a uma factory com nome.

| Arbitrum, 88 pares de hop | Tem uma pool | Ganhou o par |
|---|---|---|
| Uniswap V4 (nativo + encapsulado) | 67 | 48 |
| Uniswap V3 | 86 | 33 |
| Pancake V3 | 77 | 13 |
| Camelot V3 | 66 | 10 |

Um par credita todos os venues que forneceram uma perna da sua rota vencedora, pelo que a coluna pode exceder o número de pares — atribuição, não partição. Na Arbitrum, a família V4 ganha mais pares do que qualquer outro venue registado, incluindo a factory canónica do V3 — confirmação, vista de fora, da ordem de sondagem que dá prioridade ao nativo do §5.1. O censo é também um instrumento de poda: uma factory que se regista, tem pools e não ganha nada ao longo de centenas de pares medidos é candidata a retirada, avaliada pela atribuição e não pela reputação, e cada varredura traz uma barreira anti-vacuidade — um par reportado como tendo profundidade tem também de cotar um valor diferente de zero.

### §17.4 Gas

Cada valor é rastreável até um harness com nome, com frio e quente reportados separadamente.

| Medição | Valor | Fonte |
|---|---|---|
| resolução a frio (primeira descoberta, 4 factories) | 169,093 gas | `test/fork/DiscoveryColdWarm.t.sol`; `REPORTS.md` |
| resolução a quente (Monoslots em cache, descoberta omitida) | 132,691 gas | mesma execução |
| poupança a quente | −36,402 gas (−21 %) | diferença |
| custo marginal por perna adicional | ≈ 28,700 gas | `LifecycleMetrics` (agosto de 2026) |
| segundo hop via ponte | ≈ 59,000 gas | `LifecycleMetrics` (agosto de 2026) |
| `previewPlan` na Base ao vivo, frio / quente / frio após TTL | 1,524,221 / 1,414,633 / 1,359,925 gas | `test/fork/QuoterGasFork.t.sol` (§12.3) |

![FIG-18 — O que custa uma cotação através da ABI: `previewPlan` e `previewAndEncode` em mocks (descoberta vs registo fresco, média e dispersão sobre quarenta tamanhos) e na Base ao vivo (frio, quente, frio após o TTL).](https://blazephoenix.xyz/whitepaper/figs/pt/fig-18.png)

Três leituras estruturais verificam-se sem qualquer medição, porque decorrem da arquitetura. A poupança a quente escala com a amplitude do registo, não com o tamanho da troca: aquilo que o caminho a frio paga é a varredura de factories, e a leitura em cache que substitui a varredura é sempre um único `SLOAD`. As pernas são a unidade de custo marginal, e é por isso que existe a barreira de divisão (§10.4). E os hops são a dimensão cara: uma rota com ponte tem de ganhar o suficiente nas pools para se pagar na bomba. Os chamadores escolhem o seu ponto nesta superfície troca a troca — resolver dentro do quadro e pagar a pesquisa, ou fornecer uma rota e pagar só a execução — e a barreira de frescura do §9.4 reserva a varredura para os pares que o protocolo ainda não conhece. O custo de uma cotação ao vivo é de 1.4–1.5 milhões de gas de computação *view*, que ninguém paga on-chain.

### §17.5 O executor face à concorrência

Uma tabela de gas sem uma referência externa é autoelogio, por isso a camada de execução foi comparada no mesmo fork, no mesmo bloco, com calldata real de produção: o `MetaAggregationRouterV2` da KyberSwap (`0x6131B5fae19EA4f9D964eAc0408E4408b66337b5`), num fork da Base fixado no bloco em que cada rota foi construída, em 2026-08-22, com a Paraswap cotada em paralelo como segundo termo de comparação: as próprias rotas codificadas da Kyber, pedidas à sua API pública e reproduzidas contra o seu contrato implantado, com as nossas rotas executadas ao lado e as entregas de ambos os lados medidas como deltas de saldo. O harness valida-se primeiro a si próprio: a entrega medida do concorrente coincide ao wei com a promessa da sua API, pelo que um revert de qualquer dos lados não se pode fazer passar por resultado. Por perna, o executor mediu-se entre 2.4× e 10.9× mais eficiente em gas do que a referência — no par mais claro, 322,172 gas para quatro pernas contra 879,553 para uma, 2.7× por transação — por um harness (`BenchExec.t.sol`) que vive com o calldata capturado na árvore privada, pelo que os números são reportados, não reproduzíveis a partir deste checkout, que é compilado com `optimizer_runs = 999999` — pelo que a diferença é de desenho, não de definições do compilador; o router deles interpreta uma lista genérica de chamadas decidida por um servidor, o nosso executa uma estrutura tipada, e a interpretação tem custo. No par mais claro, a rota de uma perna deles custou 879,553 gas; quatro das nossas pernas custaram 322,172. Ao longo de nove pares medidos, a porta que resolve por completo e a porta de calldata entregaram saídas idênticas. As barras de erro do método fazem parte do resultado: as cotações foram fixadas no bloco para o qual foram construídas, e as estimativas de gas do lado da API foram descartadas depois de a execução real ter medido uma delas 148 % abaixo.

### §17.6 A taxa de câmbio byte–gas ρ*

Que porta deve um chamador usar — levar uma rota em calldata, ou deixar a chain resolver? O custo de uma transação é afim e separável — $21{,}000 + \mathrm{bytes} \cdot p_{\mathrm{byte}} + \mathrm{gas} \cdot p_{\mathrm{gas}}$ — pelo que todo o compromisso entre calldata e execução se reduz a um escalar: **ρ\***, o gas de execução que um byte de calldata compra. Medido com `test/EquationBench.t.sol` no perfil de release, ρ* vai de 66.9 gas por byte em rotas de uma perna até 105.5 em rotas de quatro e cinco pernas, transação completa. Contra ele está o preço por byte ao vivo de cada chain, lido dos próprios predeploys de taxas da chain — o oráculo de preço do gas da OP-Stack, o `ArbGasInfo` da Arbitrum — sem chave e sem feed de terceiros.

| Chain, preços lidos ao vivo 2026-08 | $p_{\mathrm{byte}}$ (gas/byte) | Peso dos dados num swap | Porta barata |
|---|---|---|---|
| Base | 7.2 | 0.9 % | rota em calldata |
| Arbitrum | 12.8 | 3.4 % | rota em calldata |
| Optimism | 33.9 | 14.0 % | rota em calldata |
| Rollup ZK que paga a disponibilidade de dados ao preço de calldata | 243,256 | 99.9 % | resolução dentro do quadro — 14× mais barata de ponta a ponta |

Onde $p_{\mathrm{byte}} < \rho^{*}$ a porta de calldata é a barata; onde $p_{\mathrm{byte}} > \rho^{*}$ é-o a resolução dentro do quadro. Nas chains OP-Stack e Arbitrum o termo de dados é 0.9–14 % do custo de um swap, pelo que é na execução que se gasta o dinheiro — que é onde se acumula a eficiência do executor acima descrita. As quatro portas do Router não são uma funcionalidade de conveniência; são o modelo de custo afim, transformado em interface.

## §18 O DEX, reduzido ao osso

Dezassete secções de mecanismo reduzem-se a uma página. Se não leres mais nada, lê isto.

**Uma tarefa.** Recebe dois tokens, um montante, o teu mínimo, um destinatário e um prazo. Devolve a maior saída que a liquidez pública da chain consegue entregar — ou recusa, com um código que diz porquê. Não há terceiro desfecho: na matriz de venues hostis, vinte de vinte fixtures de patologia de venue e porta liquidam dentro dos pisos ou recusam com um seletor nosso (§15.5).

**Cinco contratos, uma matemática.**

| Contrato | O que é, numa linha |
|---|---|
| **Core** | A biblioteca sem estado: a forma fechada de cada venue, a derivação 𝒟, o piso Φ, o score de vitalidade Ψ. Definida uma vez, importada pelos outros quatro. |
| **Hub** | O registo que aprende liquidez negociando-a — e prova cada par antes de o guardar. Não dá preço a nada. |
| **Solver** | Constrói a rota e a divisão a partir da saída marginal e da profundidade *medidas*. Apenas `view`. |
| **Router** | O único contrato que move fundos. Mede cada delta de saldo, impõe o piso, não guarda nada em repouso. |
| **Quoter** | A pré-visualização gratuita — o mesmo avaliador com que o Router liquida, pelo que pré-visualização e entrega coincidem. |

**Seis tipos de venue, quatro famílias.** Uniswap V2, V3 e V4 (ETH nativo incluído), pools de taxa dinâmica Algebra e pares Solidly estáveis e voláteis — cada um com preço dado por uma forma fechada no Core, um despachante Ω para todos eles (§4). Curve e Balancer foram excisados, e os seus números de tipo retirados para sempre (§4.1).

**Quatro portas, um executor.** `swapExactIn`, `swapExactInWithPermit2` e `swapExactInNative` recebem uma rota em calldata; `swapBestExactIn` resolve e executa atomicamente on-chain. As quatro chegam ao mesmo `_execute`, aos mesmos pisos e à mesma taxa (§11.1).

**Três pisos sob cada troca.** Um piso por perna, um agregado por hop e o piso de rota Φ re-derivado do impacto medido no quadro de execução — e depois o *teu* `userMinOut` sobre o que efetivamente chega ao destinatário. A entrega é o maior entre o piso do protocolo e o teu (§11.5).

**Uma taxa, compilada.** 0.28 %, cobrada uma vez sobre a primeira moeda-ponte que o Router detém, arredondada para cima para nunca ser zero, e nada que cresça com a diferença entre cotação e entrega (§13).

**Aquilo em que se recusa a confiar.** Liquidez anunciada. Taxas declaradas. Profundidade em calldata. O relato da própria pool sobre os tokens que negocia. Cada um deles é medido a partir da pool ou derivado por aritmética antes de poder chegar ao estado partilhado (§7, §9, §16.4).

**O que custa.** Gas: derivar a rota dentro do quadro é mais caro do que liquidar uma resposta calculada noutro lado, e o §17.6 diz-te, por chain, que porta é a mais barata. Imutabilidade: um defeito é divulgado e recompensado com bounty, nunca corrigido (§21).

## §19 Estado da implantação

Este documento descreve o repositório, e o repositório é canónico: onde este texto e o código-fonte divergirem, prevalece o código-fonte. Existem duas gerações e nunca são confundidas.

**O V1 é o que está ao vivo on-chain.** É uma base de código diferente e anterior, arquivada no seu próprio repositório — não um commit anterior deste. Medido por RPC em 2026-09-04, o router V1 implantado é o mesmo contrato de 14,624 bytes na Base, Ethereum, Optimism e Arbitrum. `test/fork/DeployedParity.t.sol` e `test/fork/DeployedCodehashPin.t.sol` fixam o que é o V1, em cada rede que o SDK nomeia — o codehash de cada contrato implantado, registado em `test/fork/deployed-codehash.json` — para que uma alteração ao que está implantado seja notada, e afirmam as propriedades que se verificam independentemente da geração: nenhum `SELFDESTRUCT`, nenhum `CALLCODE`, nenhuma autoridade por `tx.origin`, um bloqueio de reentrância transitório, um tamanho de runtime fixo, ligações ativas e controlo ainda não renunciado.

**Este repositório é o V2, e o V2 não está implantado.** A árvore medida neste documento compila um Router de 23,781 bytes e tem funções externas que o V1 não tem — entre elas a porta de valor nativo, a costura wrap/unwrap, o caminho de resgate e a porta Permit2. Os contratos V2 são implantados em forks de liquidez ao vivo e exercitados de ponta a ponta em cada execução em fork (§15.1, §17). Nada no §15 ou no §17 protege os contratos V1 implantados; cada afirmação neste documento é uma afirmação sobre o V2 tal como está em `8949a9d`.

Duas políticas protegem, em conformidade, os leitores. Este documento não contém endereços de contratos — os endereços sobrevivem aos documentos que os citam, e a superfície de endereços ao vivo é mantida onde pode ser atualizada e verificada por máquina: os registos do repositório e a página de verificação e o manifesto do site. E um registo de implantação tem um formato especificado — chain, endereço, commit de implantação e hash do bytecode de runtime, escrito no momento do broadcast, com um passo de verificação que re-deriva o hash a partir de uma build limpa — para que, quando o V2 for implantado, cada afirmação de endereço seja aritmética, não confiança.

## §20 Token — BZPX

Mil milhões de BZPX, fixos para sempre, como um ERC-20 simples: 18 casas decimais, sem caminho de cunhagem, sem taxa na transferência, sem rebasing, sem hooks de transferência, sem pausa nem lista negra — seis invariantes de implantação, verificados contra o bytecode do token no momento da ligação. A oferta totalmente diluída é conhecida desde a génese; a escassez é uma propriedade do contrato, não uma política.

| Alocação | Tokens | Parte | Nota |
|---|---|---|---|
| Liquidez de mercado | 520,000,000 | 52.0 % | a oferta em circulação através da qual o agregador encaminha |
| Emissão de staking | 180,000,000 | 18.0 % | reservada; o desenho de emissão do V4 está no §25 |
| Airdrop e Bounties | 130,000,000 | 13.0 % | um só fundo: o antigo airdrop de 50,000,000, o antigo fundo de investigação de 50,000,000 do §21 e 30,000,000 retirados da liquidez de mercado |
| Equipa e operações | 103,000,000 | 10.3 % | a única tranche bloqueada de insiders; vesting linear de 30 meses |
| Parceiros e ecossistema | 60,000,000 | 6.0 % | integrações, parcerias com venues |
| Marketing | 7,000,000 | 0.7 % | divulgação do lançamento |

**O que mudou em setembro de 2026.** O airdrop e o fundo de investigação de segurança eram duas linhas que pagavam às mesmas pessoas pela mesma coisa — ler o protocolo a fundo e usá-lo a sério. Passaram a ser uma única linha de 130,000,000 BZPX: 50,000,000 do airdrop, 50,000,000 do fundo de investigação e 30,000,000 retirados da liquidez de mercado, que passa de 550,000,000 para 520,000,000. Nada foi retirado da linha de mais ninguém, e a oferta continua a ser exatamente mil milhões.

O registo on-chain do contrato do token, uma vez publicado, é a versão canónica desta tabela. À data da redação, o token não tem liquidez provisionada nem evento de geração de token; um volume on-chain de zero é o estado esperado nesta fase, não um sinal sobre o código.

## §21 Programa de investigação e registo de segurança

Antes de este projeto ter um programa de investigação digno desse nome, investigadores independentes leram o código-fonte com olhar hostil — sem que ninguém lhes pedisse, sem nada prometido — e divulgaram em privado o que viram. O código que este documento descreve é o código que sobreviveu à sua leitura. O que cada um deles reportou, e o que foi feito disso, está onde esses registos pertencem: no `SECURITY.md` e no `SECURITY_HALL_OF_FAME.md` do repositório, junto ao código, onde cada entrada pode ser verificada nos dois sentidos. Esta secção regista quem são, quanto paga a leitura hostil e a forma do que ela encontrou.

**Os investigadores.** NetGakarot · duxun · AmanDara1 · amitbhakar · auditor_1b3f2c · siam siddik · Thomas · llen · destinyae · superagent · Mohd Huzaifa · Raditya · bai bo · Josh W · Borutobro · mohaseenkatika · mohaseenbasha · Karan Rathod · Seavia Resources · acit aja · Brian Wahyu · M2000 Slash · Binod Bk · CHARIR ABDELHAMID · e um investigador que preferiu permanecer anónimo. Foram creditados vinte e cinco investigadores; nenhum relatório atingiu a classe Crítica. A atribuição nunca é arredondada para baixo: os nomes são publicados exatamente como foram dados.

**O fundo: Airdrop e Bounties, 130,000,000 BZPX — 13 % da oferta fixa** (§20). As recompensas de segurança saem dele segundo os escalões abaixo, que não se alteraram.

| Gravidade | Recompensa |
|---|---|
| Crítica — roubo direto ou congelamento permanente de fundos de utilizadores; um estado de insolvência alcançável | 2,500,000 – 7,500,000 BZPX |
| Alta — roubo em condições específicas; uma redistribuição que paga sistematicamente à parte errada | 625,000 – 2,500,000 BZPX |
| Média — griefing, negação de serviço temporária, resíduo recuperável | 125,000 – 625,000 BZPX |
| Baixa — impacto demonstrado abaixo dos anteriores | até 125,000 BZPX |

As recompensas são pagas em BZPX — quantidade e calendário prometidos, valor de mercado não — com os pagamentos a começar depois de outubro de 2026 e os relatórios triados desde já. Uma cláusula é deliberada: um relatório não precisa de quebrar uma lei de conservação para ser Crítico — uma redistribuição que paga sistematicamente à parte errada enquanto as contas batem certo é avaliada como um roubo, porque essa é a classe que só os leitores hostis apanham.

**O que o registo contém, por classe.** Cada achado confirmado tornou-se uma propriedade com nome, um teste de regressão que falha contra o código anterior à correção e um mutante que o teste tem de matar; as classes, uma frase cada, por referência ao registo:

- *Dois produtores de uma mesma quantidade* — um planeador e um executor, uma pré-visualização e uma entrega, a responder a uma pergunta em dois quadros (a agregação de impacto do piso, a ponte indicada pela pré-visualização contra o hop em que a taxa se ancora, o orçamento de pernas entre dois contratos, o bit de ponte congelado contra o predicado ao vivo): fechada colapsando para um único produtor ou por um teste de paridade com nome, e enumerada como registo com uma regra de CI.
- *Uma quantidade fornecida pelo chamador onde existia uma medição* — a base da taxa lida de `route.totalOut`, a taxa e os hooks do registo escritos a partir de calldata, profundidade declarada em vez de medida, um volume publicado que reportava a declaração: fechada medindo, e pela classificação de campos do §16.4.
- *Ausência lida como permissão* — um hop final que não podia ser cotado dentro do quadro a deixar o piso inerte, uma barreira de cobertura que um chamador podia desligar escrevendo zero, uma lista de taxas vazia que cotava uma família inteira a zero: fechada recorrendo ao valor atestado ou medido, nunca a nada.
- *Uma fixação no objeto errado* — a origem de derivação de uma factory que um proxy podia mover enquanto o seu codehash se mantinha, o runtime de um hook fixado onde a sua implementação podia mover-se: fechada atestando a resposta onde o código não pode ser fixado, e declarando o residual no local onde não pode ser fechado.
- *Falhar aberto numa cotação* — a proteção de domínio da curva estável que ela própria sofria overflow com dust, encontrada pela via de N versões: fechada com um teste escrito primeiro a vermelho, com a reparação menor do que o código que substituiu.
- *Uma correção aplicada a um de dois canais simétricos* — a assinatura de defeito que esta base de código nomeia em primeiro lugar, encontrada repetidamente; cada fecho procura agora o irmão antes de ser integrado.

O convite é o propósito da secção, e é permanente: leitores independentes são convidados, em público, e pagos, numa moeda cuja quantidade é fixa. Reporta em privado, através do canal de divulgação no `SECURITY.md` do repositório.

## §22 Em que tens de confiar, e em que não precisas

Todos os protocolos afirmam dispensar confiança; quase nenhum consegue enumerar as suas exceções. Eis a lista completa, cada poder apresentado com a linha que o limita.

- **O registo de venues, a lista de pontes e a lista de permissões de hooks V4** — curados; o pior caso de uma listagem hostil é limitado pelo mais estrito entre o teu mínimo e o piso Iron-Law Φ; ao capital não consegue chegar (§9.6, §14.6).
- **A chave de controlo do Router, antes da renúncia** — pode redirecionar o destino da taxa, pausar swaps, reapontar os contratos WETH e Permit2 que as suas portas nativa e Permit2 chamam, e recuperar tokens enviados por engano atrás de um atraso público de 48 horas; não pode mudar a percentagem da taxa, a divisão nem os pisos (constantes de compilação, sem setters) nem chegar ao capital (sem proxy, sem caminho de atualização, sem `selfdestruct`, nada guardado em repouso).
- **A chave de controlo do Hub, antes da renúncia** — pode reapontar a visão que o Hub tem do Router, do Solver e do Quoter, reapontar o manager V4, pausar a aprendizagem do registo e atribuir lugares de operador; não pode atribuir um preço errado a uma execução, porque nada que dê preço a uma troca lê o registo.
- **As tesourarias** — fixadas na construção, e a divisão 30 / 70 não tem setter.
- **Os contratos canónicos de que as portas dependem** — o Permit2 da Uniswap para a porta Permit2, o WETH da chain para a porta nativa, o PoolManager para as pernas V4: cada um só é chamado através da sua porta ou da sua perna, e o Router dá preço a cada perna a partir do seu próprio delta de saldo medido, pelo que uma contraparte desonesta faz colapsar a saída e o teu limite recusa o swap.
- **O token e a correspondência** — que o BZPX satisfaz os seus seis invariantes de implantação, e que os endereços que chamas correspondem a este texto: verificável assim que os registos do §19 forem publicados, pelo procedimento que o §19 especifica.

Aquilo em que não precisas de confiar: em ninguém para dar preço à tua troca — a rota é derivada no quadro de execução a partir do estado público, ou re-medida lá se a forneceste; em ninguém para a encaminhar com equidade — o piso é re-derivado on-chain a partir da saída medida e a taxa não tem termo que cresça com a diferença entre cotação e entrega; em ninguém para contar a taxa — o Router recusa liquidar sem a pagar; e em ninguém para continuar a servir-te — se todos os servidores que este projeto opera desaparecessem esta noite, os contratos cotariam, encaminhariam e liquidariam amanhã exatamente como hoje.

E se guardares um só hábito deste documento, que seja o mínimo que defines nas tuas próprias trocas. Todos os limites do agregador recaem sobre esse número; é a única proteção do sistema cuja qualidade não depende da competência de ninguém a não ser da tua.

## §23 Trabalho relacionado

**Encaminhamento.** Angeris, Evans, Chitra e Boyd formulam o encaminhamento entre market makers de função constante como um programa convexo cujo ótimo iguala os preços marginais entre venues; Diamandis, Resnick, Chitra e Angeris dão para ele um algoritmo eficiente de decomposição dual. Este desenho fica deliberadamente aquém desse ótimo on-chain: o Alocador de Divisão é proporcional à profundidade numa só passagem (§10.4), o que não exige iteração nem modelo de curvatura por venue e é robusto onde um solver iterativo é uma fatura de gas e uma superfície de ataque; a via metamórfica mede a distância que a escolha custa — a divisão nunca paga menos do que a melhor pool única (MR-R1) e a matriz de fidelidade coloca a rota do Solver a menos de 0.13 bps de uma grelha exaustiva na Base. A forma fechada exata que iguala os retornos marginais para a família de produto constante são duas somas e uma raiz quadrada por venue e é candidata a uma versão posterior; o objetivo é plano perto do seu ótimo, e é por isso que a regra robusta é lançada primeiro. Os desenhos de solver off-chain movem a otimização para um servidor e reduzem o contrato a um verificador; o Orçamento de Dependências do §3.1 é a declaração, neste documento, do que isso custa. Trabalho recente estende o modelo com gas: *Optimal Routing across Constant Function Market Makers with Gas Fees* mostra o gas a alargar as regiões sem troca e a interagir de forma não trivial com a fragmentação, e *Routing Frictions and Executable Liquidity in Fragmented Markets* separa a liquidez anunciada da executável — a distinção que este desenho mede dentro do quadro em vez de a modelar.

**Agregação robusta.** O centro de credibilidade do §10.3 é uma mediana ponderada pela profundidade, cujo ponto de rutura é metade do peso. Müller, Moumeni e Messaoudi, *Cost of Manipulation in AMM-Based Oracles* (FC 2026), provam o limite correspondente para oráculos que agregam preços de AMM: com pesos iguais o ataque mais barato move as pools mais rasas, enquanto com pesos de liquidez controlar metade do peso exige pelo menos metade da profundidade total de cotação. Ormer propõe um oráculo on-chain que estima a mediana em vez da média TWAP, e *From Means to Medians* estuda que benchmarks são mais difíceis de manipular. E25 aplica o mesmo princípio ao encaminhamento: uma pool só merece crédito na medida do capital em risco que a sustenta.

**Venues.** O Uniswap v2 dá a referência de produto constante e a convenção de 30 bps que o ramo V2 assume por omissão; o Uniswap v3, o modelo de liquidez concentrada, `slot0` e o ponto fixo Q64.96 que a forma fechada do §4.2 segue; o Uniswap v4, o singleton, a contabilidade flash e a codificação de permissões de hook no endereço em que assentam o §5 e o §14.2 — o desenho aqui é, tanto quanto sabemos, o primeiro a derivar, provar, dar preço, filtrar e liquidar pools V4 inteiramente dentro do quadro. O StableSwap de Egorov define o invariante amplificado da família Curve que este protocolo excisou em vez de a suportar com base num pressuposto de confiança não medido (§4.1); a curva estável Solidly do §6 não tem artigo com revisão por pares e é citada pelas suas implementações implantadas.

**MEV.** Daian et al. deram nome ao adversário da ordenação e mostraram a sua escala; Zhou et al. mediram ataques sandwich em exchanges descentralizadas e formalizaram a sua rentabilidade. Este documento não reivindica qualquer eliminação — a ordenação é decidida antes de o código do contrato correr — e, em vez disso, mede o limite: a curva de sandwich do §14.3, do lado do atacante, com o limiar de recusa e a ida e volta negativa do atacante para lá dele.

**Verificação.** As hiperpropriedades de Clarkson e Schneider dão nome à classe a que pertencem os achados de redistribuição do §21 — propriedades de conjuntos de traços, não de um traço — e explicam por que razão uma lei de conservação se pode verificar enquanto se paga à parte errada. A interpretação abstrata de Cousot e Cousot é o enquadramento da forma fechada de tick único: uma abstração da matemática do venue que é exata dentro de um intervalo e correta num sentido fora dele, com o piso como verificação de concretização. Chen, Cheung e Yiu introduziram o teste metamórfico, o segundo juiz do §15.7 onde não existe oráculo independente da fórmula. DeMillo, Lipton e Sayward introduziram a análise de mutação, em cuja hipótese de acoplamento assenta a guarda curada do §15.2. A programação de N versões de Avizienis é a antecessora do §15.8, aplicada à geração de código em vez de a equipas independentes. O teste combinatório de Kuhn, Kacker e Lei dá às matrizes de cobertura do §15.4 a sua construção e a sua afirmação: cada interação de ordem t entre fatores de regime exercitada por construção, com o denominador impresso. O resultado de Littlewood e Strigini sobre a validação de fiabilidade ultra-elevada é a razão pela qual nenhuma probabilidade de correção é declarada em parte alguma deste documento.

**Normas.** O transient storage EIP-1153 transporta o contexto de perna da Doutrina do Callback Único, o livro-razão das taxas e o bloqueio de reentrância; o EIP-170 é a parede de 24,576 bytes da qual o Router e o Hub estão a poucas centenas de bytes; o EIP-1014 é a aritmética CREATE2 de 𝒟; o EIP-2612 e o Permit2 da Uniswap definem a transferência baseada em assinatura da segunda porta; o ERC-7201 organiza em namespaces o storage do Hub; as contas delegadas EIP-7702 chamam as mesmas portas que qualquer contrato.

## §24 Conclusão

Propusemo-nos construir um agregador sobre uma disciplina — medir, não acreditar — e mantê-la em cada ponto onde um número poderia, em vez disso, ter sido aceite sob palavra de alguém: a rota, o preço, o piso, a base da taxa, o conjunto de venues, o par que uma pool afirma negociar, até o próprio modelo de custos do protocolo.

O resultado é um sistema pequeno com uma forma forte. A fragmentação da liquidez revelou-se um problema de linguagem, não de matemática: por baixo da proliferação de venues está uma pequena família de invariantes, e um protocolo que exprime cada um deles uma vez — um despachante, uma derivação, um piso, um campo de vitalidade — consegue dar preço ao panorama sem casos especiais por venue, derivar a rota dentro da transação que a executa e voltar a verificar a sua própria promessa contra a saída medida antes de um token te chegar. O registo medido é o resumo mais curto do que isso compra: uma cotação sem deriva que liquida exatamente na sua previsão 64 vezes em 64, em mocks e na Base ao vivo; um piso que limita um sandwich numa troca de 1 % a cerca de 2.7 % dela e recusa para lá disso; uma pré-visualização e uma entrega separadas por 0–1 pontos base em quatro chains; e um aparato que publica, com denominadores, como poderia ser manipulado e o que não consegue ver.

O que custa é igualmente claro. Gas: derivar uma rota dentro do quadro é mais caro do que liquidar uma resposta calculada noutro lado — o preço de uma garantia que podes verificar em vez de uma que tens de aceitar sob palavra de alguém — e a taxa de câmbio byte–gas diz-te, por chain, que porta torna esse preço mínimo. Imutabilidade: os defeitos são divulgados e recompensados com bounty, não corrigidos — o preço de um contrato que auditas uma vez, e o §21 é o que esse preço compra.

A tese, reformulada: aquilo que escolhe é aquilo que negocia. Uma cotação e a sua execução são o mesmo cálculo, pelo que a lacuna onde antes vivia a honestidade de um operador é fechada por aritmética; um registo que aprende liquidez negociando-a, e prova cada par que guarda; uma taxa, um piso e uma superfície de entrada que ninguém — nem os autores — pode mover, porque estão compilados. O protocolo não pede que confiem nele. Pede para ser verificado, e trabalha para tornar a verificação barata, pública e permanente.

## §25 Staking V4: desenho

O Staking V4 é a base de código atual; o endereço é publicado no lançamento.

Este capítulo descreve o motor de staking tal como está o seu código-fonte: `src/BlazePhoenixStaking.sol` no repositório `Blaze-Phoenix-Staking`, `main` em `cc614f9` (2026-10-14), que declara `VERSION = "4.0.0"` (L169). Cada número de linha deste capítulo (L*n*) refere-se a esse ficheiro nesse commit; onde este texto e o código-fonte divergirem, prevalece o código-fonte. O capítulo não contém endereços, datas de implantação nem rendimentos: cada número nele é uma constante compilada no contrato, ou deriva de uma, e a derivação está impressa ao seu lado.

O motor está sujeito à disciplina do resto deste documento. Detém um único token, BZPX, e cada direito sobre esse BZPX é um termo do livro-razão cuja soma o contrato volta a verificar em torno de cada mudança de estado (E35). Um staker bloqueia BZPX durante um número de dias à sua escolha e recebe dois fluxos — uma emissão programada (E27–E29) e os juros que os mutuários pagam (E31–E34) — cada um ponderado por um boost que cresce com o compromisso (E30). Um staker pode pedir BZPX emprestado contra o stake (E41). Quando ocorre uma perda, esta segue uma única ordem fixa (E37), e o contrato reporta, como view pública, se detém o que deve (E36).

### §25.1 Arquitetura e papéis

Um único contrato, `BlazePhoenixStaking`, que herda de `AccessControl`, `Pausable` e `ReentrancyGuard` (L167). O token, a tesouraria e a janela de emissão (`emissionStart`, `emissionEnd`) são imutáveis (L266–269); o construtor recusa um endereço de token que não contenha código (L477). Não há oráculo, nem caminho de atualização, nem função de alteração de parâmetros: cada constante abaixo está compilada no contrato.

| Papel | Detido por | Pode | Linha |
|---|---|---|---|
| `DEFAULT_ADMIN_ROLE` | o implantador, na construção | conceder e revogar papéis (não existe nenhuma chamada a `_setRoleAdmin`, pelo que administra todos os papéis) | L485 |
| `ADMIN_ROLE` | o implantador, na construção | `fundEmission` (financiamento acumulado ≤ `TOTAL_REWARDS`); `withdrawReserve` (apenas para a tesouraria imutável, no máximo `protocolReserve`, fechada sob uma violação grave); `sweepUndistributedEmission` (apenas depois de `emissionEnd`); `unpause`; `cancelEmergency` (apenas com um livro solvente) | L486, L516, L533, L563, L580, L618 |
| `GUARDIAN_ROLE` | ninguém na construção; concedido por um administrador de papéis | `pause`; `declareEmergency` — nenhum dos dois move fundos | L171, L578, L608 |
| qualquer pessoa | — | `liquidate`; `tripBreaker` (reverte a menos que o livro esteja em violação grave); `absorbBadDebt`; `lockStep` | L1066, L597, L639, L1291 |

Nenhum papel pode mover o capital de um staker, e o único destino para onde qualquer papel pode enviar receita é a tesouraria imutável.

| Constante | Valor | Significado | Linha |
|---|---|---|---|
| `TOTAL_REWARDS` | 180,000,000e18 | orçamento de emissão, e o teto do `fundEmission` acumulado | L192 |
| `HALVING_PERIOD` | 2 × 365 dias | duração de um período de emissão | L193 |
| `EMISSION_PERIODS` | 8 | períodos antes de o programa encerrar (`EMISSION_LENGTH` = 16 anos) | L194–195 |
| `INITIAL_REWARD_PER_SEC` | (`TOTAL_REWARDS` / 2) / `HALVING_PERIOD` | taxa do período 0, $R_{0}$ | L196 |
| `MAX_STAKE_PER_WALLET` | 30,000,000e18 | teto de stake por posição | L198 |
| `MIN_EMISSION_WEIGHT` | 1,000e18 | abaixo deste peso total, ambos os fluxos são reduzidos pro rata | L208 |
| `MAX_LTV` | 50 | teto de empréstimo, % do stake líquido | L210 |
| `LIQ_THRESHOLD` | 95 | liquidável com dívida ≥ 95 % do stake | L211 |
| `LIQ_BONUS_BPS` | 500 | excedente de liquidação para o chamador, bps da dívida | L212 |
| `RESERVE_FACTOR_BPS` | 300 | parte de cada fatia de juros retida em `protocolReserve` | L213 |
| `MIN_LOCK_DAYS`, `MAX_LOCK_DAYS` | 90, 2,555 | limites do bloqueio em dias | L221–222 |
| `BOOST_BASE`, `BOOST_LINEAR`, `BOOST_QUAD` | 10,000, 750, 250 | polinómio de boost, bps | L224–226 |
| `MIN_DEPOSIT_BLOCKS` | 10 | blocos que um depósito tem de envelhecer antes de um levantamento, de um resgate de rendimento puro ou de uma alteração do bloqueio | L228 |
| `RATE_R0`, `RATE_RK`, `RATE_UK`, `RATE_S1`, `RATE_S2` | 100, 500, 0.8e18, 500, 72,500 | curva de juros com quebra, bps anuais | L231–235 |
| `MAX_PROTOCOL_UTIL_WAD` | 0.75e18 | teto de utilização do livro para um novo empréstimo | L242 |
| `CONSERVATION_DUST` | 1e10 | tolerância da guarda de conservação, em wei | L247 |
| `MAINT_BASE`, `MAINT_DENSITY`, `MAINT_GAP_UNIT`, `MAINT_MAX_SCAN`, `MAINT_MAX_LOCK_ACTIONS` | 1, 50, 15 minutos, 10, 4 | orçamento da manutenção autónoma (E42) | L252–255, L263 |

### §25.2 O fluxo: stake, unstake, resgate, empréstimo

Cada ponto de entrada do utilizador executa uma única sequência, na ordem que `deposit` fixa: registar um instantâneo da identidade de conservação; recusar se o livro estiver em violação grave; avançar o índice de juros e a janela de emissão (`_updateGlobal`, L1428); liquidar ambos os fluxos ao peso que a posição detinha; atribuir os juros que a posição deve (`_accrueInterestFor`, L1627); limpar um bloqueio decorrido; executar a ação; recalcular os pesos da posição através do escritor único (`_resync` → `_applyBoost` → `_checkpoint`, L1726–1756); correr a janela de manutenção autónoma (E42); e verificar de novo a identidade de conservação (E35). As portas diferem apenas nas barreiras que acrescentam.

| Ponto de entrada | Em pausa | Emergência | Violação grave | Condições adicionais |
|---|---|---|---|---|
| `deposit(amount, lockDays)` — stake | fechado | fechado | fechado (L760) | $90 \le$ `lockDays` $\le \min(2{,}555,\ \text{days left to } \mathtt{emissionEnd})$; stake da posição ≤ `MAX_STAKE_PER_WALLET`; antes de `emissionEnd` (L743–760) |
| `lock(lockDays)` | fechado | fechado | — | `MIN_DEPOSIT_BLOCKS` desde o último depósito (L964–971) |
| `withdraw(amount)` — unstake | aberto | fechado | fechado (L902) | sem dívida; bloqueio decorrido; `MIN_DEPOSIT_BLOCKS` desde o último depósito (L890–895) |
| `claimRewards()` | aberto | fechado | fechado (L932) | liquida a emissão e o rendimento puro (L930) |
| `claimPureYield()` | aberto | fechado | fechado (L948) | sem dívida; `MIN_DEPOSIT_BLOCKS` desde o último depósito (L944–948) |
| `borrow(amount)` | fechado | fechado | fechado (L826) | E41 (L820–840) |
| `repay(amount)` | aberto | fechado | aberto | — (L858) |
| `liquidate(user)` | fechado | fechado | aberto | E39 (L1066) |
| `emergencyWithdraw()` — saída | — | apenas | — | E40 (L658) |
| `absorbBadDebt(amount)` | aberto | aberto | aberto | E38 (L639) |

**Stake.** `deposit` transfere BZPX para a posição e inicia ou prolonga o seu bloqueio; o bloqueio nunca pode estender-se para além do fim do programa de emissão, e o boost que compra (E30) só é pago enquanto o bloqueio estiver em vigor. **Unstake.** `withdraw` devolve o capital assim que a posição nada deva e o seu bloqueio tenha decorrido; continua aberto durante uma pausa do guardião, pelo que uma pausa trava novo risco sem prender ninguém. Numa emergência, a única saída é `emergencyWithdraw`, que paga o capital próprio líquido, reduzido pro rata se o contrato detiver menos do que é devido às posições (E40), e faz a posição perder os seus fluxos não resgatados. **Resgate.** A colheita são os dois resgates: `claimRewards` paga ambos os fluxos, `claimPureYield` faz o mesmo para uma posição sem dívida; não existe uma função de colheita separada. **Empréstimo, reembolso, liquidação.** Um staker pode pedir BZPX emprestado contra o seu próprio stake dentro de dois tetos (E41); os juros são cobrados ao stake, não somados à dívida (E34); `repay` continua aberto durante uma pausa e sob uma violação grave, porque saldar dívida só torna o livro mais seguro. Uma posição cuja dívida atinja 95 % do seu stake pode ser fechada por qualquer pessoa, e quem a fecha recebe o excedente de E39.

![FIG-19 — Os pontos de entrada do staking e a sua sequência única: as barreiras que cada porta acrescenta, depois o instantâneo de conservação, a barreira de violação, a atualização global, a liquidação, a atribuição de juros, a expiração do bloqueio, a ação, a ressincronização pelo escritor único, a manutenção autónoma e a verificação de conservação; a saída de emergência fica à parte.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-19.png)

### §25.3 Contabilidade das recompensas

**Emissão.** Seja $T$ = `TOTAL_REWARDS`, $P$ = `HALVING_PERIOD`, $R_{0}$ = `INITIAL_REWARD_PER_SEC`, $s$ = `emissionStart` e, para um instante $t$, seja $\tau = t - s$ e $p = \lfloor \tau / P \rfloor$. A emissão programada acumulada é uma forma fechada (`_emittedAt`, L1458–1467):

$$
E(t) \;=\; \begin{cases} 0 & t \le s \\ \left(T - (T \gg p)\right) \;+\; (R_{0} \gg p)\,(\tau - pP) & s < t < s + 8P \\ T - (T \gg 8) & t \ge s + 8P \end{cases}
$$
^e27

*Derivação.* Em aritmética exata, a taxa do período $q$ é $T/(2^{q+1}P)$, pelo que um período $q$ completo emite $T/2^{q+1}$ e a emissão anterior ao período $p$ é $\sum_{q<p} T/2^{q+1} = T(1 - 2^{-p})$. $T = 1.8\times 10^{26}$ é divisível por $2^{8}$, pelo que $T \gg p = T/2^{p}$ exatamente para $p \le 8$, e o primeiro termo é essa soma sem qualquer arredondamento. O termo da taxa é arredondado por defeito: $R_{0} \gg p = \lfloor\lfloor T/(2P)\rfloor / 2^{p}\rfloor = \lfloor T/(2^{p+1}P)\rfloor$, abaixo da taxa exata em menos de um wei por segundo. Dentro de um período, $E$ cresce portanto linearmente e fica abaixo da curva exata; em cada mudança de período sobe $T/2^{p+1} - (R_{0} \gg p)\,P$, um salto não negativo e inferior a $P$ wei, que a devolve à série exata. $E$ é monótona não decrescente e encerra em $T - T/2^{8} = \tfrac{255}{256}\,T$: o último $T/256$ nunca é programado e, juntamente com o que as janelas vazias ou não financiadas tenham deixado, só é recuperável para a tesouraria por `sweepUndistributedEmission` após o encerramento (L563). Uma avaliação em inteiros exatos sobre as oito mudanças de período confirma que cada salto é positivo e inferior a $P$.

![FIG-20 — Emissão programada E27 em função do tempo: a taxa reduz-se para metade a cada dois anos e a curva acumulada encerra em 255/256 de TOTAL_REWARDS ao fim de dezasseis anos; programada, não paga — uma janela sem peso não emite nada.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-20.png)

**A janela.** Em cada ponto de entrada, com $W$ = `totalBoostedEffective`, $W_{\min}$ = `MIN_EMISSION_WEIGHT`, $t_{\ell}$ = `lastRewardTime` e $t' = \min(t, \mathtt{emissionEnd})$, a janela decorrida é paga num acumulador por unidade de peso $A$ = `accRewardPerShare` (`_updateGlobal`, L1428–1448):

$$
r \;=\; \min\!\left( \left\lfloor \frac{\left(E(t') - E(t_{\ell})\right)\cdot \min(W, W_{\min})}{W_{\min}} \right\rfloor,\ \mathtt{rewardReserve} \right), \qquad A \;\leftarrow\; A + \left\lfloor \frac{r \cdot 10^{18}}{W} \right\rfloor
$$
^e28

`rewardReserve` desce $r$ e `totalRewardDistributed` sobe $r$. Com $W = 0$, o relógio avança e nada é capturado, pelo que ninguém herda um atraso acumulado; abaixo de $W_{\min}$, a janela é reduzida pro rata, pelo que uma posição de dust não pode ficar sozinha com o calendário; e, como cada janela está limitada à reserva, `fundEmission` liquida o relógio antes de o novo financiamento entrar (L523), pelo que um reforço nunca paga uma janela retroativamente.

**Liquidação das recompensas.** Uma posição com peso de emissão $w_{u}$ e ponto de controlo $c_{u}$ (`rewardDebt`) tem direito a (`_settlePendingRewards`, L1487–1497; o gémeo do rendimento puro, L1499–1517, usa $w^{\mathrm{p}}_{u}$, $A^{\mathrm{p}}$ e `pureYieldDebt`):

$$
\mathrm{due}_{u} \;=\; \left(\left\lfloor \frac{w_{u}\,A}{10^{18}} \right\rfloor - c_{u}\right)^{+}, \qquad c_{u} \;\leftarrow\; \left\lfloor \frac{w_{u}\,A}{10^{18}} \right\rfloor
$$
^e29

e, após cada mudança de peso, o escritor único volta a fixar o ponto de controlo $c_{u} = \lfloor w_{u}A/10^{18}\rfloor$ (`_checkpoint`, L1736), pelo que uma posição só ganha em janelas que encerrem depois de o seu peso estar em vigor.

**Boost.** O peso é o stake da posição multiplicado por um boost que é um polinómio do bloqueio pelo qual ela é *atualmente* paga (`boostByDays`, L496–505; `_effectiveLockDays`, L1687; `_computeBoost`, L1695–1700). Com $\ell$ o bloqueio em dias — zero assim que o momento de desbloqueio tenha passado, quer a posição tenha sido normalizada quer não — limitado a 2,555:

$$
b(\ell) \;=\; 10^{4} + \left\lfloor \frac{750\,\ell}{365} \right\rfloor + \left\lfloor \frac{250\,\ell^{2}}{365^{2}} \right\rfloor \ \text{bps}, \qquad w_{u} = \left\lfloor \frac{(s_{u} - d_{u})^{+}\, b}{10^{4}} \right\rfloor, \qquad w^{\mathrm{p}}_{u} = \begin{cases} \lfloor s_{u}\, b / 10^{4} \rfloor & d_{u} = 0 \\ 0 & d_{u} > 0 \end{cases}
$$
^e30

com $s_{u}$ o stake da posição e $d_{u}$ a sua dívida. Valores exatos: $b(90) = 10{,}199$, $b(365) = 11{,}000$, $b(730) = 12{,}500$, $b(1{,}825) = 20{,}000$, $b(2{,}555) = 27{,}500$ bps. O peso de emissão incide sobre o stake líquido; o peso do rendimento puro só existe para uma posição sem dívida — um mutuário não recebe os juros que paga.

### §25.4 Juros: a curva e o índice

**A curva.** A utilização é $U = \min(\lfloor D \cdot 10^{18} / S \rfloor, 10^{18})$, com $D$ = `totalDebt` e $S$ = `totalStaked` ($U = 10^{18}$ se $S = 0 < D$; a taxa base se ambos forem zero), e a taxa anual em bps tem uma quebra em 80 % (`_interestRate`, L1768–1782):

$$
r(U) \;=\; \begin{cases} 100 + \left\lfloor 500\,U / 10^{18} \right\rfloor & U \le 0.8 \cdot 10^{18} \\ 500 + \left\lfloor 72{,}500\,(U - 0.8\cdot 10^{18}) / 10^{18} \right\rfloor & U > 0.8 \cdot 10^{18} \end{cases}
$$
^e31

Os dois ramos encontram-se na quebra — $100 + 0.8 \times 500 = 500$ — e a curva atinge $500 + 0.2 \times 72{,}500 = 15{,}000$ bps com utilização total. Um empréstimo não pode elevar o livro acima de 75 % (E41), pelo que nenhum empréstimo, por si só, entra no ramo íngreme.

**O índice.** Cada fatia decorrida $\Delta t$ é marcada com a taxa em vigor ao longo dela, antes de qualquer escrita em $D$ ou $S$ (`_interestSlice`, L1589–1619; `_updateInterestIndex`, L1539–1583), com $Y$ = 365 dias:

$$
\delta \;=\; \left\lfloor \frac{\lfloor 10^{18}\, r(U) / 10^{4} \rfloor \cdot \Delta t}{Y} \right\rfloor, \qquad \sigma \;=\; \left\lfloor \frac{D\,\delta}{10^{18}} \right\rfloor, \qquad I \leftarrow I + \delta, \quad S \leftarrow S - \sigma
$$
^e32

Se $\sigma$ excedesse $S$, o avanço do índice é derivado de novo como $\delta = \lfloor S \cdot 10^{18}/D \rfloor$ e $\sigma$ é recalculado a partir dele, pelo que as cobranças por posição nunca somam mais do que o débito global. A aritmética satura em zero em vez de reverter, pelo que os pontos de entrada que correm sobre ela não podem ficar bloqueados, e, numa emergência, o relógio avança sem cobrar (L1547). Uma única função calcula a fatia para a execução e para cada cotação, pelo que as duas não podem arredondar de forma diferente.

**A divisão.** A fatia sai do stake e é dividida no mesmo passo (L1560–1580; `_dampPure`, L1623–1625), com $W_{\mathrm{p}}$ = `totalBoostedPure` e $A^{\mathrm{p}}$ = `accPureYieldPerShare`:

$$
\kappa_{r} = \left\lfloor \frac{300\,\sigma}{10^{4}} \right\rfloor, \quad \pi = \sigma - \kappa_{r}, \quad \eta = \left\lfloor \frac{\pi \cdot \min(W_{\mathrm{p}}, W_{\min})}{W_{\min}} \right\rfloor, \quad A^{\mathrm{p}} \leftarrow A^{\mathrm{p}} + \left\lfloor \frac{\eta \cdot 10^{18}}{W_{\mathrm{p}}} \right\rfloor, \quad \mathtt{protocolReserve} \mathrel{+}= \kappa_{r} + (\pi - \eta)
$$
^e33

pelo que $\sigma = \kappa_{r} + \eta + (\pi - \eta)$ exatamente; sem peso puro, todo o $\pi$ vai para a reserva. A redução é a mesma da emissão (E28), com a mesma constante.

**Atribuição.** O lado global foi liquidado quando os juros se acumularam; a parte própria de uma posição é-lhe atribuída da próxima vez que for tocada (`_accrueInterestFor`, L1627–1671), com $I_{u}$ o seu ponto de controlo do índice:

$$
i_{u} \;=\; \left\lfloor \frac{d_{u}\,(I - I_{u})}{10^{18}} \right\rfloor; \qquad i_{u} > s_{u} \;\Rightarrow\; \lambda = i_{u} - s_{u} \ \text{enters E37},\ S \mathrel{+}= \lambda,\ i_{u} \leftarrow s_{u}; \qquad s_{u} \leftarrow s_{u} - i_{u}, \quad I_{u} \leftarrow I
$$
^e34

Os juros são pagos a partir do stake; a dívida em si não cresce. Uma posição sem dívida apenas volta a fixar o ponto de controlo, pelo que nunca herda crescimento do índice de um período em que nada devia. Os juros que uma posição não consegue pagar foram, ainda assim, distribuídos por E33; somá-los de volta a $S$ mantém $S = \sum_{u} s_{u}$, e a perda é registada por E37 no momento em que é conhecida.

### §25.5 A reserva, a solvência e a cascata de perdas

**Conservação.** Com $B$ o saldo de BZPX do contrato, $D$ = `totalDebt`, $\mathit{BD}$ = `totalBadDebt`, $S$ = `totalStaked`, $\mathit{RR}$ = `rewardReserve`, $\mathit{PR}$ = `protocolReserve` e $\Pi$ = `totalRewardDistributed − totalRewardsPaid` (distribuído, ainda não pago), toda a função que usa o modificador `conserves` regista um instantâneo de ambos os lados antes do seu corpo e reverte depois dele, a menos que (L419–438; `_conservationSnapshot`, `_conservationCheck`, L449–457):

$$
\left|\, \Delta(B + D + \mathit{BD}) \;-\; \Delta(S + \mathit{RR} + \mathit{PR} + \Pi) \,\right| \;\le\; \varepsilon, \qquad \varepsilon = \mathtt{CONSERVATION\_DUST} = 10^{10}\ \text{wei}
$$
^e35

Cada termo é uma única variável de estado não negativa, somada sem limite inferior, pelo que a identidade é linear em todos os regimes — incluindo a aflição terminal, em que as ferramentas de recuperação (`repay`, `liquidate`, `absorbBadDebt`) têm de continuar a funcionar — e só se compara a variação ao longo de uma chamada, pelo que o histórico não se pode acumular num falso alarme.

**Solvência.** O que o contrato deve, e o teste público de se o detém (`_owed`, L1794–1798; `_hardBreach`, L1808–1810; `isSolvent`, L1824):

$$
\mathrm{owed} \;=\; (S + \mathit{RR} + \mathit{PR} - D)^{+} \;+\; \Pi, \qquad \mathrm{hardBreach} \iff B + \varepsilon < \mathrm{owed}, \qquad \mathtt{isSolvent}() = \neg\,\mathrm{hardBreach}
$$
^e36

*Derivação da ligação à dívida incobrável.* Onde $S + \mathit{RR} + \mathit{PR} \ge D$, E35 dá $\Delta(B - \mathrm{owed} + \mathit{BD}) = 0$ (até $\varepsilon$) em cada chamada protegida, pelo que $B - \mathrm{owed} = c - \mathit{BD}$, com $c$ o saldo detido para além do livro-razão. A dívida incobrável registada é, portanto, exatamente o termo que empurra o livro para uma violação grave, e o livro passa a ler-se como insolvente quando $\mathit{BD} > c + \varepsilon$. Sob uma violação grave, as portas que pagariam ao par ou acrescentariam dinheiro novo a um fundo insuficiente revertem — `deposit`, `borrow`, `withdraw`, `claimRewards`, `claimPureYield` e a liquidação do rendimento puro dentro delas, `withdrawReserve`, `cancelEmergency` (L760, L826, L902, L932, L948, L1510, L539, L620) — enquanto `repay`, `liquidate` e `absorbBadDebt` permanecem abertas, e qualquer pessoa pode chamar `tripBreaker` para passar o contrato a emergência (L597).

**A cascata.** Uma perda $\lambda$ surge em apenas três locais: uma liquidação cuja dívida excede o stake (L1101–1106, L1128), uma saída de emergência em défice (L704–709) e juros que uma posição não consegue pagar (L1657–1663). Os três aplicam a mesma ordem:

$$
\kappa \;=\; \min(\lambda,\ \mathit{PR}), \qquad \mathit{PR} \leftarrow \mathit{PR} - \kappa, \qquad \mathit{BD} \leftarrow \mathit{BD} + (\lambda - \kappa)
$$
^e37

A reserva — constituída a partir do fator de reserva de cada fatia de juros (E33) e dos bónus de autoliquidação — absorve primeiro; só o resto não coberto passa a dívida incobrável registada. A recapitalização é uma porta pública que toma primeiro a reserva, depois, no máximo, o que o chamador oferecer e nunca mais do que o que ainda está por cobrir (`absorbBadDebt`, L639–649), com $a$ o montante do chamador:

$$
\rho \;=\; \min(\mathit{BD},\ \mathit{PR}), \qquad \gamma \;=\; \min(a,\ \mathit{BD} - \rho), \qquad \mathit{PR} \leftarrow \mathit{PR} - \rho, \qquad \mathit{BD} \leftarrow \mathit{BD} - \rho - \gamma, \qquad B \leftarrow B + \gamma
$$
^e38

Reverte quando $\rho + \gamma = 0$, não move nada para fora e não paga nada ao chamador; E35 verifica-se por construção ($\Delta \mathrm{LHS} = \gamma - \rho - \gamma = -\rho = \Delta \mathrm{RHS}$). Assim que $\mathit{BD}$ volte a estar dentro do dust, `isSolvent()` lê-se verdadeiro e o administrador pode cancelar a emergência.

**Liquidação.** Uma posição é liquidável se e só se $d_{u} > 0$ e ($s_{u} = 0$ ou $100\,d_{u} \ge 95\,s_{u}$) (`_isLiquidatable`, L1133–1137). Fechá-la (`_executeLiquidation`, L1079–1131):

$$
\mathrm{seized} \;=\; \min\!\left(d_{u} + \left\lfloor \frac{500\,d_{u}}{10^{4}} \right\rfloor,\ s_{u}\right), \qquad \mathrm{bonus} \;=\; (\mathrm{seized} - d_{u})^{+}, \qquad \lambda \;=\; (d_{u} - s_{u})^{+} \ \text{to E37}
$$
^e39

O bónus vai para o chamador, exceto quando um mutuário fecha a sua própria posição, caso em que fica em `protocolReserve`. Os fluxos ganhos pela posição são pagos antes de esta ser fechada, e qualquer stake que sobre permanece como uma posição sem dívida que mantém o seu bloqueio.

**Saída de emergência.** Com $\mathrm{pot} = B$ e $E_{+}$ = `totalPositiveEquity` $= \sum_{u} \max(s_{u} - d_{u}, 0)$ tal como acompanhado, a saída paga (`emergencyWithdraw`, L658–725; o escalonamento, L689–696):

$$
x_{0} \;=\; (s_{u} - d_{u})^{+}, \qquad E' \;=\; E_{+} - e_{u} + x_{0}, \qquad x \;=\; \min\!\left( \begin{cases} \lfloor x_{0}\,\mathrm{pot} / E' \rfloor & \mathrm{pot} < E' \\ x_{0} & \text{otherwise} \end{cases},\ \mathrm{pot} \right)
$$
^e40

onde $e_{u}$ é o termo acompanhado de quem sai, substituído pelo seu capital próprio exato após a acumulação. Num livro solvente o escalonamento nunca atua e o capital próprio líquido é pago por inteiro; num livro deficitário, cada saída toma a mesma fração do seu direito, e uma saída em défice regista a sua insuficiência através de E37 (L704–709).

![FIG-21 — A cascata de perdas E37–E38: protocolReserve absorve primeiro, o resto é registado como totalBadDebt e lido por isSolvent(), e absorbBadDebt recapitaliza a partir da reserva e depois a partir do chamador, nunca além do que está por cobrir; proporções ilustrativas, sem montantes de tokens.](https://blazephoenix.xyz/whitepaper/figs/pt/fig-21.png)

**Tetos de empréstimo.** Um empréstimo de $a$ tem de satisfazer ambos (`borrow`, L834–840; `_ltvCap`, L1908–1909):

$$
d_{u} + a \;\le\; \left\lfloor \frac{50\,(s_{u} - d_{u})^{+}}{100} \right\rfloor, \qquad \left\lfloor \frac{(D + a)\cdot 10^{18}}{S} \right\rfloor \;\le\; 0.75 \cdot 10^{18}
$$
^e41

o primeiro sobre o stake líquido da posição, o segundo sobre o livro inteiro, mantido abaixo da quebra de 80 % de E31.

**Manutenção.** Cada transação de utilizador, a menos que o contrato esteja em pausa ou em emergência, percorre também uma janela do registo de mutuários (liquidando o que está em défice) e do registo de bloqueios (normalizando os bloqueios expirados), cada uma de dimensão (`_windowBudget`, L1148–1157; `_autoMaintain`, L1170–1178):

$$
c(n) \;=\; \min\!\left(1 + \left\lfloor \frac{n}{50} \right\rfloor + \left\lfloor \frac{t - t_{m}}{15\ \mathrm{min}} \right\rfloor,\ 10,\ n\right)
$$
^e42

com $n$ a dimensão do registo e $t_{m}$ a última varredura; no máximo quatro normalizações de bloqueio correm por transação (L263). O calendário é uma função pura do estado on-chain — sem keeper, sem governação — e o seu gas é limitado em todos os casos.

**Invariantes.** O desenho acrescenta nove invariantes, INV-23 a INV-31 (Apêndice B): a identidade de conservação, o teto de emissão, a ordem das perdas, as portas fechadas sob uma violação, o limite da recapitalização, o escritor único dos pesos, os tetos de empréstimo, a saída de emergência limitada e a regra de envelhecimento do depósito.

### §25.6 Reforço na V4

Três alterações integradas moldaram o código-fonte da V4 depois do desenho que está implantado na Base; cada uma é descrita aqui ao nível do desenho que produziu.

- **#22 (`b44e238`, 2026-10-11).** Os juros são marcados por fatia por uma única função partilhada pela execução e por cada cotação (E32), pelo que uma pré-visualização e uma transação calculam a mesma cobrança, à taxa em vigor ao longo da fatia. O canal de rendimento puro é reduzido pelo mesmo piso de peso que a emissão (E33), para que um denominador residual não possa capturar o fluxo. Um mutuário que feche a sua própria posição não recebe bónus de liquidação. Foram acrescentadas views de risco só de leitura (`healthFactor`, `daysToLiquidation`, `maxBorrowOf`).
- **#26 (`7fc0c2a`, 2026-10-13).** Uma única ordem de perdas para os três locais de perda: primeiro a reserva, depois a dívida incobrável registada (E37); uma porta pública de recapitalização (E38); as portas que movem valor fechadas sob uma violação grave (E36); um construtor que recusa um endereço de token sem código; a verificação de conservação emitida uma só vez como dois auxiliares internos, em vez de inserida em cada local protegido, com a identidade inalterada; e um conjunto de testes de garantia.
- **#25 (`cc614f9`, 2026-10-14).** Apenas documentação: linhas de resumo curtas nos guias e nos cabeçalhos dos testes. Nenhum código-fonte do contrato foi alterado.

### §25.7 Evidência de testes

Contados em `origin/main` em `cc614f9`, a partir da árvore de código-fonte, não de uma execução: 37 ficheiros `*.t.sol` (`git ls-tree -r --name-only origin/main | grep -c '\.t\.sol$'`), que declaram 256 funções `test*` e 14 `invariant*` (`git grep -E '^\s*function (test|invariant)' origin/main -- '*.t.sol'`, repartidas por prefixo). O README do repositório (linha 84) indica um harness Node de nove suites a par deles. Estas são contagens do que está declarado; este documento não reporta uma taxa de aprovação para a suite de staking.

---

## Histórico de revisões

### Versão 2.3.0 (2026-10-14)

2.3.0 — acrescenta o capítulo de desenho do Staking V4 (§25), com as equações E27–E42, os invariantes INV-23–INV-31 e as figuras FIG-19–FIG-21; substitui a afirmação abaixo de que o motor de staking deixou de ser descrito neste documento. No resto, mudam apenas os rótulos de versão, os intervalos de enumeração, as introduções dos apêndices e as linhas de DOI; o restante é o texto da 2.3.

### Versão 2.3 (2026-09-24)

A versão 2.3 dá continuidade à linha 2.2; a numeração 3.0, usada brevemente num rascunho deste texto, é retirada, tal como antes dela o foi a numeração 3.0 de 2026-09-01. O que mudou em relação à 2.2: as dezoito inovações recebem nome, são numeradas de I-1 a I-18 e enunciadas com a sua matemática no início do documento, com um placar do registo medido; cada valor é medido de novo contra `main` em `8916545`; o motor de staking deixa de ser descrito aqui (é a sua própria especificação que o descreve); a secção do token regista a pool única Airdrop & Bounties de 130,000,000 BZPX; e a errata da 2.2, abaixo, é incorporada no texto que corrigiu.

### Errata à 2.2 (2026-09-07)

Aplicada após uma leitura hostil do texto de 2026-09-06 contra `main 8949a9d`; a linha de versão manteve-se 2.2. Cada item indica o que o texto dizia e o que diz o checkout.

1. §4.2 — o limitador de fronteira `sqrtBoundary` está definido no Core, mas ainda não está ligado à classificação nem à promessa no quadro; o texto dizia que era aplicado do lado da promessa. Item em aberto: ligá-lo (`Router._v4LegQuote`, ramo de classificação do Core), com um teste escrito primeiro a vermelho que entrega abaixo da cotação líquida, para lá da margem de E21, quando uma perna V4 sai do seu intervalo.
2. §10.4 — o limitador de capacidade exclui as pernas V4 (o Solver salta a leitura do saldo para os tipos 4 e 8); o texto dizia que todas as pernas concentradas eram limitadas. Item em aberto: um limite físico para o singleton.
3. §5.4 — uma chave V4 de taxa estática ignora a taxa de protocolo do gestor (zero em todas as chains servidas hoje); o texto dizia que a taxa da chave era inequívoca.
4. §9.3 — a margem de expulsão desce até cerca de 25 % (titular 51, recém-chegada 64), não 3 %; o valor anterior violava E13 e foi copiado de um comentário do código-fonte.
5. §15 e o resumo — 43 funções `invariant_*` (o comando impresso devolve 43), 217 ficheiros `.t.sol`.
6. §14.1 — `HubE(6)` não existe; o esgotamento da factory é `HubE(4)`, o esgotamento de slots é `_canInsert`.
7. §14.2 — “basta qualquer uma das camadas” retirado: as camadas limitam a alteração de deltas; o resíduo de substituição de taxa da §5.4 é limitado pelo piso.
8. §11.4, INV-21 — a regra de forma da rota é a ordem canónica em toda a rota (`sawHooked`), não “com hook apenas no último hop”.
9. §11.3, E24 — a folga do piso agregado por hop é dividida por BPS: 20 % da perna atestada média.
10. §17.3 e Apêndice C — o harness `FactoryCensus` está na árvore privada de implantação; a tabela é reportada, não reproduzível a partir deste checkout.
11. §17.5 — a referência de gas passa a ser identificada (KyberSwap `MetaAggregationRouterV2`, fork da Base, 2026-08-22, Paraswap como segundo comparador) e a razão por transação (2.7×) é impressa ao lado da razão por perna; o harness e o calldata capturado são privados, pelo que os números são reportados, não reproduzíveis a partir deste checkout.
12. §17.2 — “a primeira agregação encaminhada por V4 da chain” retirado; “exata” substituído pela banda medida (0–1 bps).
13. INV-8, INV-10, INV-15, INV-20, INV-22 — citações de imposição corrigidas para os testes e os códigos que as sustentam; INV-22 nomeia os quatro contratos implantados.
14. §1 — o levantamento dos agregadores fica limitado aos sete nomeados, tal como documentado em 2026-09-07.
15. Referências 16 e 20 — a EIP-1153 é de A. Akhunov e M. Salem; a EIP-7702, de V. Buterin, S. Wilson, A. Dietrichs e M. Garnett.
16. §2.3, §15.11, §21 — as contagens de calibração de instrumentos e de padrões de defeito são substituídas pela própria regra de calibração.
- §14.2, Camada 2 (2026-09-07, admissão de hooks): a lista de permissões faz a curadoria da porta automática e a fixação do codehash suspende, em todas as portas, um hook listado cujo código mudou. Um hook cujos bits de endereço não trazem permissão de swap nunca corre num swap e não precisa nem de lista nem de fixação. Um hook que corre no swap e que ninguém listou é aceite na porta explícita como escolha assinada do chamador, limitado, como qualquer venue, pela promessa no quadro, pela barreira de atestação e por `userMinOut`; nunca é proposto pela porta automática. Registar uma pool com hook admite e fixa o seu hook, pelo que uma pool com hook custa um passo do operador. As três camadas mantêm-se; “fechado por omissão” descreve a porta automática.

### Errata à 2.2 (2026-09-24)

Aplicada após a nona vaga de bounties; a linha de versão manteve-se 2.2.

1. §4.2, e item 1 da errata de 2026-09-07 — fechado. Uma pool V4 é cotada percorrendo o seu próprio livro: o seu preço, a liquidez, o bitmap de ticks e os ticks, lidos através de `extsload`, com a própria aritmética de passo do PoolManager, tanto para a classificação como para a promessa (`Core.v4WalkOut`). O limitador de fronteira `sqrtBoundary` é retirado. A afirmação de que o despachante não replica a aritmética de cruzamento de ticks vale agora apenas para a família V3.
2. §10.4, e item 2 da errata de 2026-09-07 — fechado para o fim a que servia: o percurso conta apenas a liquidez que o livro detém nos ticks que cruza, pelo que uma perna V4 fica limitada ao que a sua própria pool detém (`test_AOneTickRangeWithNothingBeyondPaysWhatItHolds`).
3. Item 3 da errata de 2026-09-07 — fechado: uma chave de taxa estática compõe a taxa de protocolo do gestor com a taxa de LP da chave no sentido do swap (`Core.effV4Fee`; `test_StaticKey_ProtocolFee_ReachesThePromise`).
4. §4 — cada leitura que o caminho de cotação faz de uma pool tem o gas limitado e copia um número fixo de palavras; as duas que eram chamadas de alto nível (o `getAmountOut` do par Solidly, e `factory()` seguido de `getFee`) perguntam através de `Core._askWord` (`test/APoolsAnswerIsBoundedByTheReader.t.sol`).

## Apêndice A · As equações primitivas

Cada afirmação quantitativa deste documento reduz-se a uma das seguintes. Cada uma é implementada uma só vez, no contrato indicado, e importada em todos os outros sítios. A numeração E1–E22 mantém-se estável desde a edição anterior; E23–E26 são novas e acrescentadas no fim. E27–E42 (2.3.0) pertencem ao motor de staking, definidas em `src/BlazePhoenixStaking.sol` do repositório de staking em `cc614f9` (§25); “Staking” na quarta coluna designa esse contrato, com os seus números de linha.

| # | Nome | Equação | Definida em | § |
|---|---|---|---|---|
| E1 | Meta-Equação | $R^{\star} = \arg\max_{R}\ \mathrm{net}(R)\cdot\prod_{\ell}\hat{\Psi}(p_{\ell})\cdot\mathbf{1}[\mathrm{net}(R)\ge\Phi(R)]\cdot\Xi(R)$ | pipeline do Solver | §3 |
| E2 | Saída de produto constante | $y = \lfloor x(\mathrm{BPS}-f)\,r_{\mathrm{out}} / (r_{\mathrm{in}}\,\mathrm{BPS} + x(\mathrm{BPS}-f)) \rfloor$ | Core `outV2` | §4.2 |
| E3 | Saída de liquidez concentrada (dentro do tick) | $\sqrt{P}' = L\sqrt{P}/(L + x_{f}\sqrt{P}/Q_{96})$, $y = L(\sqrt{P}-\sqrt{P}')/Q_{96}$; forma dual para o outro sentido | Core `outV3` | §4.2 |
| E4 | Slot base de storage da V4 | $\mathrm{slot} = \mathrm{keccak256}(\mathrm{abi.encode}(\mathrm{poolId}, 6))$; $\sqrt{P}$ nos bits [0,160), taxa de LP em [208,232) da palavra 0; $L$ na palavra 3 | Core `v4SqrtAndLiq` | §5 |
| E5 | Invariante estável do Solidly | $k(x,y) = x^{3}y + xy^{3}$ | Core `_solK` | §6 |
| E6 | Passo de Newton do Solidly | semente $y_{0} = Y$; passo ascendente $\max(1, \lfloor (K-k)/f' \rfloor)$; passo descendente $\max(1, \lfloor (k-K)/f' \rfloor)$, substituído por $\lfloor y/2 \rfloor$ quando cruzaria o zero; saída em $\lvert y_{n+1}-y_{n}\rvert \le 1$ com um acréscimo de uma unidade contra o tomador; limite 64 → semente → cotação 0 | Core `_solY` | §6 |
| E7 | Normalização decimal | $X = r_{\mathrm{in}}10^{18-d_{\mathrm{in}}}$, $Y = r_{\mathrm{out}}10^{18-d_{\mathrm{out}}}$, reposta à escala original após a resolução | Core `_solidlyStable` | §6 |
| E8 | Derivação CREATE2 | $\mathrm{pool} = \mathrm{addr}_{20}(\mathrm{keccak256}(\mathtt{0xff} \Vert \mathrm{origin} \Vert \mathrm{salt} \Vert \mathrm{initCodeHash}))$ | Core `create2Address`, `deriveAddress` | §7 |
| E9 | Empacotamento do Monoslot | $s = a \,\vert\, f\!\ll\!8 \,\vert\, k\!\ll\!32 \,\vert\, r\!\ll\!40 \,\vert\, (c\wedge\mathtt{0xFFF})\!\ll\!48 \,\vert\, b\!\ll\!60 \,\vert\, \dots \,\vert\, B_{\mathrm{last}}\!\ll\!224$ | Core `encodeSlot` | §8 |
| E10 | Campo de Vitalidade | $\Psi = V \cdot 2^{b} \cdot (1 + 0.25\,\mathbf{1}_{\mathrm{bridge}}) \cdot (1 + 0.05\,\mathbf{1}_{\mathrm{conc}})$ | Core `psi` | §9.2 |
| E11 | Decaimento da atividade | $V = \mathrm{swapCount} \gg \lfloor (t - t_{\mathrm{last}})/24{,}576 \rfloor$; 0 quando o deslocamento excede 31 | Core `_decayedSwapCount` | §9.2 |
| E12 | Balde de profundidade | $b = \min(15, \lfloor \log_{10}(d/10^{15}) \rfloor)$ | Core `depthBucket` | §9.2 |
| E13 | Margem de expulsão | $2^{b(d_{\mathrm{new}})} > \Psi_{\mathrm{worst}} + \lfloor \Psi_{\mathrm{worst}}/4 \rfloor$ | Hub `_canInsert` | §9.3 |
| E14 | Barreira de divisão | manter a divisão sse $\mathrm{out}_{\mathrm{split}} \ge \mathrm{out}_{\mathrm{single}}\cdot(1 + 25/10^{6})$, sendo $\mathrm{out}_{\mathrm{single}}$ o melhor entre o candidato mais profundo e o de melhor taxa de câmbio, em tamanho total | Solver `_buildHop` | §10.4 |
| E15 | Piso Iron-Law | $\mathtt{floorBps} = \max(9{,}600 - \mathtt{legShv} - \min(\delta, 10^{4}) - \sigma_{\ln}/10^{14},\ 8{,}000)$ | Core `ironFloorBpsShv` | §11.5 |
| E16 | Mínimo efetivo | $\mathtt{effMin} = \max(\mathtt{userMinOut},\ \mathtt{route.singleOutFloor},\ \lceil \mathtt{finalHopQuote}\cdot\mathtt{floorBps}/10^{4}\rceil)$; o segundo termo é descartado e o terceiro reescalado pela razão líquida medida quando se deteta fee-on-transfer | Router `_execute` | §11.5 |
| E17 | Taxa de protocolo | $\mathrm{fee} = \lceil 28 \cdot \mathrm{base} / 10^{4} \rceil$, base = o input medido do hop da taxa (ancorado), o output bruto (rota direta para uma moeda-ponte) ou o input medido de cada hop (exaustão); $t_{1} = \lfloor 3{,}000\cdot\mathrm{fee}/10^{4} \rfloor$, $t_{2} = \mathrm{fee} - t_{1}$ | Router `_chargeHopFee`, `_payFee` | §13 |
| E18 | Barreira de hooks | $(\mathrm{uint160}(\mathrm{hook}) \,\&\, \mathtt{0x3FFF}) \,\&\, ((1\ll 3)\mid(1\ll 2)) \ne 0 \Rightarrow$ perna recusada, sem qualquer chamada | Core `hookAltersDeltas`; Router | §14.2 |
| E19 | Barreira de taxa dinâmica | $f_{\mathrm{eff}} = f_{\mathrm{key}}$ se estática; não cotável se o sentinela vier com uma taxa de protocolo diferente de zero; caso contrário, a taxa de LP em vigor lida de `slot0` / `globalState` / `fee()` da pool | Core `effV4Fee`, `quoteV3Fee` | §5.4 |
| E20 | Teto da taxa V2 | $f_{\mathrm{eff}} = f_{\mathrm{decl}}$ se $0 < f_{\mathrm{decl}} \le 100$ bps, caso contrário 30 | Core `effV2Fee`; a mesma regra para a taxa declarada de recurso do Solidly | §4.2 |
| E21 | Margem de segurança da pré-visualização | $s = \min(\max(0, n-2) + 5a,\ 10)$ bps | Quoter `_pack` | §12.1 |
| E22 | Escolha da superfície | levar a rota em calldata sse $p_{\mathrm{byte}} < \rho^{*}$; $\rho^{*}$ medido em 66.9–105.5 gas/byte consoante a forma da rota | `test/EquationBench.t.sol` | §17.6 |
| E23 | Desconto da perna por concentração | $\mathtt{legShv} = \sum_{\mathrm{hops}} \lfloor 200\,((\sum a)^{2} - \sum a^{2})/\sum a^{2} \rfloor$ | Core `legShaveBps` | §11.5 |
| E24 | Piso agregado por hop | $\sum \mathrm{got} + \lfloor (\mathrm{BPS} - 8{,}000)\cdot \lfloor \sum \mathrm{attested}/n \rfloor / \mathrm{BPS} \rfloor \ge \sum \mathrm{attested}$ | Router `_execute` | §11.3 |
| E25 | Centro de credibilidade | a mediana ponderada pela profundidade: ordenar $(r_{i}, d_{i})$ por $r_{i}$ e devolver o primeiro $r_{i}$ em que $\sum_{j \le i} d_{j} \ge \lceil \sum d / 2 \rceil$; banda $[0.95, 1.05] \times$ centro | Solver `_depthWeightedMedian` | §10.3 |
| E26 | Predicado do regime de taxa | $\mathrm{feeHop} = \min\{h : \mathrm{isBridge}(\mathrm{hops}[h].\mathrm{tokenIn})\}$; cobrar em $h$ sse $\neg\mathrm{feeOnOut} \wedge (\mathrm{feeHop} = \infty \vee h = \mathrm{feeHop})$; $\mathrm{feeOnOut} \iff$ um hop e $\mathrm{isBridge}(\mathrm{tokenOut})$ | Router `_execute` | §13.1 |
| E27 | Forma fechada da emissão | $E(t) = (T - (T \gg p)) + (R_{0} \gg p)(t - s - pP)$, $p = \lfloor (t - s)/P \rfloor$; $0$ até $s$; $T - (T \gg 8)$ a partir de $s + 8P$ | Staking `_emittedAt` (L1458–1467) | §25.3 |
| E28 | Janela de emissão | $r = \min(\lfloor (E(t') - E(t_{\ell}))\min(W, W_{\min})/W_{\min} \rfloor,\ \mathit{RR})$; $A \mathrel{+}= \lfloor r \cdot 10^{18}/W \rfloor$ | Staking `_updateGlobal` (L1428–1448) | §25.3 |
| E29 | Liquidação das recompensas | $\mathrm{due}_{u} = (\lfloor w_{u}A/10^{18} \rfloor - c_{u})^{+}$, depois $c_{u} \leftarrow \lfloor w_{u}A/10^{18} \rfloor$ | Staking `_settlePendingRewards`, `_settlePendingPureYield` (L1487–1517) | §25.3 |
| E30 | Boost de bloqueio e pesos | $b(\ell) = 10^{4} + \lfloor 750\ell/365 \rfloor + \lfloor 250\ell^{2}/365^{2} \rfloor$ bps, sendo $\ell$ o bloqueio em vigor; $w_{u} = \lfloor (s_{u} - d_{u})^{+} b/10^{4} \rfloor$; $w^{\mathrm{p}}_{u} = \lfloor s_{u} b/10^{4} \rfloor$ sse $d_{u} = 0$ | Staking `boostByDays`, `_computeBoost` (L496–505, L1695–1700) | §25.3 |
| E31 | Curva de juros | $r = 100 + \lfloor 500U/10^{18} \rfloor$ para $U \le 0.8 \cdot 10^{18}$, caso contrário $500 + \lfloor 72{,}500(U - 0.8 \cdot 10^{18})/10^{18} \rfloor$ bps por ano | Staking `_interestRate` (L1768–1782) | §25.4 |
| E32 | Índice de juros e fatia | $\delta = \lfloor \lfloor 10^{18} r/10^{4} \rfloor \Delta t / Y \rfloor$, $\sigma = \lfloor D\delta/10^{18} \rfloor$; se $\sigma > S$, $\delta = \lfloor S \cdot 10^{18}/D \rfloor$ e $\sigma$ é recalculado | Staking `_interestSlice`, `_updateInterestIndex` (L1539–1619) | §25.4 |
| E33 | Repartição da fatia | $\kappa_{r} = \lfloor 300\sigma/10^{4} \rfloor$ para a reserva; $\eta = \lfloor (\sigma - \kappa_{r})\min(W_{\mathrm{p}}, W_{\min})/W_{\min} \rfloor$ para os stakers puros; o resto para a reserva | Staking `_updateInterestIndex`, `_dampPure` (L1560–1580, L1623–1625) | §25.4 |
| E34 | Atribuição de juros | $i_{u} = \lfloor d_{u}(I - I_{u})/10^{18} \rfloor$, debitado a $s_{u}$; qualquer excedente sobre $s_{u}$ é uma perda para E37 | Staking `_accrueInterestFor` (L1627–1671) | §25.4 |
| E35 | Guarda de conservação | $\lvert \Delta(B + D + \mathit{BD}) - \Delta(S + \mathit{RR} + \mathit{PR} + \Pi) \rvert \le 10^{10}$ | Staking `conserves` (L419–457) | §25.5 |
| E36 | Devido e solvência | $\mathrm{owed} = (S + \mathit{RR} + \mathit{PR} - D)^{+} + \Pi$; rutura grave sse $B + 10^{10} < \mathrm{owed}$ | Staking `_owed`, `_hardBreach`, `isSolvent` (L1794–1824) | §25.5 |
| E37 | Cascata de perdas | $\kappa = \min(\lambda, \mathit{PR})$; $\mathit{PR} \mathrel{-}= \kappa$; $\mathit{BD} \mathrel{+}= \lambda - \kappa$ | Staking L1101–1106, L704–709, L1657–1663 | §25.5 |
| E38 | Recapitalização | $\rho = \min(\mathit{BD}, \mathit{PR})$, $\gamma = \min(a, \mathit{BD} - \rho)$; $\mathit{BD} \mathrel{-}= \rho + \gamma$ | Staking `absorbBadDebt` (L639–649) | §25.5 |
| E39 | Liquidação forçada | liquidável sse $d_{u} > 0 \wedge (s_{u} = 0 \vee 100 d_{u} \ge 95 s_{u})$; $\mathrm{seized} = \min(d_{u} + \lfloor 500 d_{u}/10^{4} \rfloor, s_{u})$; perda $(d_{u} - s_{u})^{+}$ | Staking `_executeLiquidation`, `_isLiquidatable` (L1079–1137) | §25.5 |
| E40 | Corte de emergência | $x_{0} = (s_{u} - d_{u})^{+}$, $E' = E_{+} - e_{u} + x_{0}$; $x = \lfloor x_{0}\,\mathrm{pot}/E' \rfloor$ se $\mathrm{pot} < E'$, caso contrário $x_{0}$; $x \le \mathrm{pot}$ | Staking `emergencyWithdraw` (L689–696) | §25.5 |
| E41 | Tetos de empréstimo | $d_{u} + a \le \lfloor 50(s_{u} - d_{u})^{+}/100 \rfloor$ e $\lfloor (D + a) 10^{18}/S \rfloor \le 0.75 \cdot 10^{18}$ | Staking `borrow`, `_ltvCap` (L834–840, L1908–1909) | §25.5 |
| E42 | Orçamento de manutenção | $c(n) = \min(1 + \lfloor n/50 \rfloor + \lfloor (t - t_{m})/900\ \mathrm{s} \rfloor,\ 10,\ n)$ por registo | Staking `_windowBudget` (L1148–1157) | §25.5 |

## Apêndice B · Os invariantes

Estas são as propriedades que valem em todos os estados alcançáveis: cada uma é imposta pela forma do código no ponto indicado, e uma transação que violasse alguma delas não é executada. INV-1–INV-18 mantêm os seus números da edição anterior, com a coluna de imposição trazida para o código; INV-19–INV-22 são novos. INV-23–INV-31 (2.3.0) pertencem ao motor de staking (§25), impostos em `src/BlazePhoenixStaking.sol` do repositório de staking em `cc614f9`.

| # | Invariante | Imposição |
|---|---|---|
| INV-1 | O Router não detém fundos entre transações; o seu saldo em repouso é zero. | Varrimentos e pagamento com base de referência (§11); `invariant_RouterHoldsNothing`, `HoldsNothingBeyondTheSeed` |
| INV-2 | Todo o swap é atómico: não existe nenhum estado em que parte de uma troca tenha sido liquidada. | Semântica de transação da EVM; um só quadro |
| INV-3 | Sem oracle: nenhum feed de preços externo é entrada da admissão, da ordenação, da divisão, do piso ou das taxas. | Não existe nenhuma chamada a feeds nos cinco contratos |
| INV-4 | A taxa, a divisão da taxa e as constantes do piso não têm setters no bytecode implantado. | Constantes de tempo de compilação no Core e no Router (§13) |
| INV-5 | Os campos da rota fornecidos pelo chamador podem reforçar a proteção, nunca afrouxá-la. | Máximo de três vias de E16; a barreira de cobertura eleva uma atestação, nunca a baixa (§11) |
| INV-6 | Um swap com mínimo zero não é executado. | `RouterE(10)` em todas as portas |
| INV-7 | Ψ ordena e trunca candidatos; nenhuma cotação, piso ou alocação o lê. | Fluxo de dados: nada a jusante da classificação consome Ψ (§9.6) |
| INV-8 | O registo de um par contém no máximo dezasseis pools, e a expulsão mantém as mais aptas pelo Ψ completo com a margem de E13. | Hub `_canInsert`; `invariant_neverExceedsMaxSlots` (o limite); `test_RecordSwap_EvictsWeakestWhenFullAndNewcomerClearsMargin` (a expulsão) |
| INV-9 | Nenhum endereço sem bytecode de runtime entra numa rota. | `hasCode` em cada derivação (§7) |
| INV-10 | O callback universal paga apenas a pool comprometida para a perna corrente, apenas enquanto uma perna está em curso, e nunca mais do que o orçamento registado da perna. | Contexto transitório da perna; `RouterE(6)` para a pool, `RouterE(8)` para o orçamento (§11.4) |
| INV-11 | Um hook V4 cujo endereço declara permissões que alteram deltas é rejeitado antes de qualquer token se mover, sem ser chamado. | E18; `RouterE(9)`; Solver `_topKPools` |
| INV-12 | Nenhum produto de preços pode transbordar: toda a multiplicação perigosa passa por `mulDiv` de 512 bits, e um estado que não possa ser limitado cota zero. | Core (§4.2, §6) |
| INV-13 | O arredondamento corre contra a promessa em excesso: as cotações e os pagamentos arredondam para baixo, os pisos de proteção e a taxa arredondam para cima. | Core `mulDiv` / `mulDivUp` em cada ponto |
| INV-14 | Onde um limite não pode ser provado, o cálculo devolve zero e o venue é abandonado — nunca um palpite, nunca uma reversão agendável dentro de uma cotação. | Postura de falha fechada em todo o Core; `_solKFits` (§6) |
| INV-15 | A base da taxa é a pull medida, limitada pelo input comprometido da rota — nunca um output declarado; `route.totalOut` não é lido por nada. | `_chargeHopFee`; `test_FeeBase_IgnoresLiedAboutTotalOut` |
| INV-16 | A renúncia é de sentido único: a flag é escrita como `true` num só ponto e como `false` em nenhum; depois dela, resta apenas o nível de curador que só cresce, e uma factory ou um hook movidos não podem ser rearmados. | `renounceControl` no Hub e no Router (§14.7) |
| INV-17 | Uma taxa de recurso declarada de produto constante ou de Solidly só é acreditada dentro de um teto de 100 bps; fora dele, os 30 bps canónicos precificam a pool. | E20 |
| INV-18 | Nenhum hop leva mais de quatro pernas e nenhuma rota mais de onze no plano do Solver; o Router aceita no máximo três hops e cinco pernas por hop. | Orçamentos do Solver; Router `_execute` → `RouterE(3)` |
| INV-19 | Uma pool só entra no registo se provar que negoceia o par: `token0()`/`token1()` para os tipos em forma de par, nova derivação do id da pool para a V4; uma pool consultada prova o mesmo antes de a descoberta a listar. | Hub `recordSwap`, `_probe`; `invariant_ActiveEntriesTradeThePair` |
| INV-20 | Uma liquidação paga a taxa de protocolo exatamente uma vez numa rota ancorada e uma vez por hop numa rota de exaustão; uma liquidação que não pagou nada não existe. | Livro-razão de taxas, `RouterE(15)`/`RouterE(16)`; `invariant_SettledSwapEmitsExactlyOneFee` (ancorada); `test/FeeSeals.t.sol`, `test/ExhaustionRegimePreviewParity.t.sol` (exaustão) |
| INV-21 | Os hops encadeiam-se — o input de cada hop é o output do hop anterior — e nenhuma perna sem hook é executada depois de uma com hook, neste ou em qualquer hop posterior (`sawHooked` vale em toda a rota). | Router `_execute` → `RouterE(3)`; `sawHooked` |
| INV-22 | Os quatro contratos implantados — Hub, Solver, Router, Quoter — são entregues sob o limite de 24,000 bytes do projeto no perfil de lançamento, a biblioteca Core é medida em separado (6,477 bytes de 24,576), e a suite corre nesse perfil. | `DeployedSizeGate`; `profile_parity.py` |
| INV-23 | Em todo o ponto de entrada do staking que leve `conserves`, o saldo mais a dívida mais a dívida incobrável registada variam na mesma quantia que o stake mais as duas reservas mais as recompensas distribuídas mas não pagas, dentro de 1e10 wei (E35). | Staking `conserves`, L419–457 → `Staking__InvariantBreached` |
| INV-24 | A emissão agendada nunca excede `TOTAL_REWARDS − (TOTAL_REWARDS >> 8)`; o financiamento acumulado nunca excede `TOTAL_REWARDS`; nenhuma janela de emissão paga mais do que `rewardReserve` detém. | `_emittedAt` L1458–1467; `fundEmission` L518 → `Staking__CapExceeded`; `_updateGlobal` L1442 |
| INV-25 | Toda a perda realizada — um défice de liquidação, uma saída de emergência com perda, juros incobráveis — recorre primeiro a `protocolReserve`; apenas o resto não coberto é acrescentado a `totalBadDebt` (E37). | Staking L1101–1106, L704–709, L1657–1663 |
| INV-26 | Enquanto o saldo mais 1e10 estiver abaixo de `owed`, não se executa nenhum depósito, empréstimo, levantamento, reclamação de recompensas ou de pure-yield, levantamento da reserva ou cancelamento de emergência (E36). | `_hardBreach` guarda L760, L826, L902, L932, L948, L1510, L539, L620 → `Staking__InvariantBreached` |
| INV-27 | `absorbBadDebt` não tira nenhum BZPX, não paga nada ao chamador e baixa `totalBadDebt` no máximo até ao seu valor atual: primeiro a reserva, com a quantia do chamador limitada ao resto não coberto (E38). | `absorbBadDebt` L639–649 |
| INV-28 | Os totais do peso de emissão, do peso de pure-yield e do capital próprio positivo são escritos apenas por `_applyBoost`, que substitui o termo registado de uma posição pelo seu termo recalculado; um bloqueio só ganha boost enquanto estiver em vigor (E30). | `_applyBoost` L1726–1734; `_effectiveLockDays` L1687–1690 |
| INV-29 | Um empréstimo só é executado se a nova dívida for no máximo metade do stake líquido da posição antes dele e se a utilização do livro depois dele for no máximo 75 % (E41). | `borrow` L834 → `Staking__LTVExceeded`; L838–840 → `Staking__UtilTooHigh` |
| INV-30 | Uma saída de emergência paga no máximo o capital próprio líquido da posição e no máximo o saldo do contrato, reduzido proporcionalmente por pot/E′ quando o saldo fica aquém do capital próprio registado (E40). | `emergencyWithdraw` L689–696 |
| INV-31 | Nenhum levantamento, reclamação de pure-yield ou alteração de bloqueio é executado nos `MIN_DEPOSIT_BLOCKS` = 10 blocos seguintes ao último depósito da posição. | L894, L947, L971 → `Staking__FlashLoanProtection` |

## Apêndice C · Comandos de reprodução

Cada número deste documento que provém do repositório é reproduzido por um dos seguintes, a partir de um checkout limpo de `Blaze-Phoenix-Dex` em `8949a9d`, com Foundry e Python 3 instalados; as suites de fork precisam de uma chave RPC de arquivo em `DRPC_KEY`.

```bash
forge test --no-match-path 'test/fork/**'                        # the suite, release settings (§15.1)
forge test --match-path 'test/fork/**'                           # the fork lane, five chains (§15.1, §17)
FOUNDRY_PROFILE=release forge build --sizes --skip test --skip script   # sizes against EIP-170 (§16.3)
python3 .github/scripts/mutants.py                                # the curated mutation guard, 268/268 (§15.2)
python3 .github/scripts/check_targets.py                          # every mutant still points at one line
python3 .github/scripts/assurance/covering_array.py --check       # both covering arrays current (§15.4)
forge test --match-contract RegimeCoverageTest -vv                # strength 2, 63 rows
forge test --match-contract RegimeCoverageT3Test -vv              # strength 3, 168 rows
forge test --match-path test/regime/HostileVenueMatrix.t.sol      # ten pathologies × two doors (§15.5)
forge test --match-path test/regime/SandwichCurve.t.sol -vv       # the sandwich curve (§14.3)
forge test --match-path test/regime/CanonicalOracles.t.sol        # the quote maths against the specifications (§15.6)
forge test --match-path 'test/*MetamorphicRelations.t.sol'        # 14 + 5 relations (§15.7)
FOUNDRY_PROFILE=nver1 forge build --skip '*.t.sol' && FOUNDRY_PROFILE=nver2 forge build --skip '*.t.sol'
NVERSION_LANE=1 forge test --match-path 'test/nversion/*'         # the three binaries agree (§15.8)
forge test --match-test invariant_ --fuzz-seed 0xb1a2ef00          # the stateful campaigns (§15.3)
forge test --match-path test/FeeSeals.t.sol                       # the fee rule, both regimes (§13.4)
forge test --match-path test/QuoteDelayStatistics.t.sol -vv       # how a quote ages, 240 samples (§12.2)
forge test --match-path test/QuoterGasStatistics.t.sol -vv        # what a quote costs (§12.3)
forge test --match-path test/fork/QuoteDelayFork.t.sol -vv        # live Base, 1,000 USDC → WETH (§12.2)
forge test --match-path test/fork/FidelityMatrix.t.sol -vv        # preview → delivery, four chains (§17.2)
forge test --match-path test/fork/DiscoveryColdWarm.t.sol -vv     # cold and warm solve (§17.4)
forge test --match-path test/EquationBench.t.sol -vv              # ρ* (§17.6)
forge test --match-path 'test/fork/Deployed*.t.sol'               # what V1 is, pinned by codehash (§19)
python3 .github/scripts/assurance/projection_distance.py          # 86 / 99 (§15.9)
python3 .github/scripts/assurance/metrics.py                      # every assurance number, with its denominator
bash .github/scripts/shared-quantities.sh                         # the register agrees with the tree
```

Os hashes do Exemplo resolvido 4 são reproduzidos por qualquer implementação de keccak-256 sobre `abi.encode(currency0, currency1, fee, tickSpacing, hooks)`; as figuras do documento foram produzidas com um Keccak-f[1600] em Python puro, verificado contra os vetores de teste da cadeia vazia e de `"abc"` e contra o seletor `extsload(bytes32)` que o Core fixa no código.

## Glossário

**Os operadores.**

| Símbolo | Nome | Numa linha |
|---|---|---|
| Ω | Despachante Óctuplo | cota cada perna — em forma fechada onde a forma fechada é exata, perguntando ao venue onde o próprio bytecode do venue é a única fonte honesta; “Óctuplo” por herança histórica, seis tipos ativos hoje |
| 𝒟 | Derivação Determinística | calcula endereços de pools por aritmética CREATE2 onde a implantação é reproduzível, pergunta e depois prova o par onde não é, deriva e prova ids de pool para o singleton V4; `hasCode` descarta o que não tem bytecode |
| Φ | Piso Iron-Law | o piso de retenção do próprio protocolo: 96 % de base, afrouxando com o impacto medido e a concentração medida, limitado com firmeza a 80 %, aplicado à cotação no quadro do último hop |
| Ψ | Campo de Vitalidade | qualidade do venue calculada apenas a partir do Monoslot; ordena e trunca o conjunto de candidatos — pode esconder um venue, nunca o cotar mal |
| Ξ | projector anti-burla | remove da maximização, antes da classificação, qualquer rota que toque num hook que altere deltas ou inadmissível, sem chamar o hook |

**Os termos.** **Regime ancorado** — a taxa cobrada uma só vez, sobre a primeira moeda-ponte que o Router detém (ou sobre o output de uma rota direta para uma moeda-ponte). **Banda de credibilidade** — ±5 % em torno da mediana, ponderada pela profundidade, das taxas marginais dos candidatos; inerte num conjunto de um só candidato. **Barreira de cobertura** — o limite atestado de uma perna elevado até à cotação medida quando a atestação cobre menos de metade dela. **Passagem Exata** — a pré-visualização exata por pool do Quoter: o próprio swap do venue executado e revertido por extração da reversão; líquida da taxa desde 2026-09-03. **Regime de exaustão** — nenhuma moeda-ponte como input de qualquer hop: cada hop paga 28 bps sobre o seu próprio input medido; imune, por construção, a um prefixo sem valor. **Livro-razão de taxas** — uma contagem transitória dos pagamentos de taxa por liquidação, que recusa zero e recusa dois numa rota ancorada. **Desenho Metrológico** — construir o contrato como um instrumento: colapsar a diversidade em coordenadas, medir toda a coordenada que se possa medir, tornar monótono o resto. **Meta-Equação** — todo o agregador como uma única maximização, um produto, de modo que um único fator em falha anula a rota. **Monoslot** — todo o estado de encaminhamento de uma pool numa só palavra de 256 bits, sem preço lá dentro. **Doutrina do Callback Único** — um só `fallback` responde ao callback de flash accounting de todos os venues em forma de V3, protegido de três maneiras. **Porta de Sentido Único** — a renúncia como bytecode: o nível de controlo morre, o nível de curador que só cresce permanece. **Prova do par** — uma pool prova o seu `token0`/`token1` (ou o seu id recalculado) antes de o registo a guardar ou de a descoberta a listar. **Distância de projeção** — a que distância o objeto observado de uma recusa está do objeto que decide. **Registo Auto-Regenerável** — o protocolo aprende a liquidez negociando-a: dezasseis slots por par, expulsão ordenada por aptidão, decaimento por aritmética. **Regra do Excedente** — a parte do protocolo é 28 bps de uma única base medida e nada que escale com a diferença entre cotação e entrega. **Terceira via** — qualquer resultado de uma fixture que não seja nem uma liquidação dentro dos pisos sem nada que fique no Router, nem uma recusa com um seletor nosso.

## Referências

1. G. Angeris, A. Evans, T. Chitra, S. Boyd. *Optimal Routing for Constant Function Market Makers.* arXiv:2204.05238, 2022 (ACM EC '22). — O encaminhamento sobre CFMMs como programa convexo; o ótimo de que o alocador proporcional da §10.4 fica aquém.
2. T. Diamandis, M. Resnick, T. Chitra, G. Angeris. *An Efficient Algorithm for Optimal Routing Through Constant Function Market Makers.* arXiv:2302.04938, 2023 (Financial Cryptography 2023). — O algoritmo de decomposição dual para o mesmo problema (§23).
3. H. Adams, N. Zinsmeister, D. Robinson. *Uniswap v2 Core.* 2020. https://uniswap.org/whitepaper.pdf — A referência do produto constante e os 30 bps por omissão da §4.2.
4. H. Adams, N. Zinsmeister, M. Salem, R. Keefer, D. Robinson. *Uniswap v3 Core.* 2021. https://uniswap.org/whitepaper-v3.pdf — Liquidez concentrada, `slot0`, vírgula fixa Q64.96 (§4.2, §15.6).
5. Uniswap Labs (H. Adams et al.). *Uniswap v4 Core.* 2024. https://uniswap.org/whitepaper-v4.pdf — O PoolManager singleton, o flash accounting e a codificação das permissões de hook no endereço (§5, §14.2).
6. M. Egorov. *StableSwap — Efficient Mechanism for Stablecoin Liquidity.* 2019. https://curve.fi/files/stableswap-paper.pdf — O invariante amplificado da família excisada na §4.1.
7. P. Daian, S. Goldfeder, T. Kell, Y. Li, X. Zhao, I. Bentov, L. Breidenbach, A. Juels. *Flash Boys 2.0: Frontrunning in Decentralized Exchanges, Miner Extractable Value, and Consensus Instability.* IEEE S&P 2020. DOI 10.1109/SP40000.2020.00040. — O adversário da ordenação que a §14.3 limita em vez de pretender eliminar.
8. L. Zhou, K. Qin, C. F. Torres, D. V. Le, A. Gervais. *High-Frequency Trading on Decentralized On-Chain Exchanges.* IEEE S&P 2021. DOI 10.1109/SP40001.2021.00027. — Ataques sandwich medidos e formalizados (§14.3).
9. P. Cousot, R. Cousot. *Abstract Interpretation: A Unified Lattice Model for Static Analysis of Programs by Construction or Approximation of Fixpoints.* POPL 1977. DOI 10.1145/512950.512973. — O enquadramento da forma fechada de um só tick como abstração sólida (§23).
10. M. R. Clarkson, F. B. Schneider. *Hyperproperties.* Journal of Computer Security 18(6), 2010. DOI 10.3233/JCS-2009-0393. — Propriedades de conjuntos de traços; a classe a que pertencem os achados de redistribuição (§21, §23).
11. T. Y. Chen, S. C. Cheung, S. M. Yiu. *Metamorphic Testing: A New Approach for Generating Next Test Cases.* HKUST-CS98-01, 1998; arXiv:2002.12543. — O segundo juiz da §15.7.
12. R. A. DeMillo, R. J. Lipton, F. G. Sayward. *Hints on Test Data Selection: Help for the Practicing Programmer.* IEEE Computer 11(4), 1978. DOI 10.1109/C-M.1978.218136. — A análise de mutação e a hipótese de acoplamento (§15.2).
13. A. Avizienis. *The N-Version Approach to Fault-Tolerant Software.* IEEE TSE SE-11(12), 1985. DOI 10.1109/TSE.1985.231893. — O antepassado da §15.8.
14. D. R. Kuhn, R. N. Kacker, Y. Lei. *Practical Combinatorial Testing.* NIST SP 800-142, 2010. DOI 10.6028/NIST.SP.800-142. — Covering arrays e cobertura de interação t-a-t (§15.4).
15. B. Littlewood, L. Strigini. *Validation of Ultrahigh Dependability for Software-Based Systems.* Communications of the ACM 36(11), 1993. DOI 10.1145/163359.163373. — Porque não se enuncia nenhuma probabilidade de correção (§15.11).
16. A. Akhunov, M. Salem. *EIP-1153: Transient Storage Opcodes.* https://eips.ethereum.org/EIPS/eip-1153 — O contexto da perna, o livro-razão de taxas e o bloqueio de reentrada (§11.4, §13.2).
17. V. Buterin. *EIP-170: Contract Code Size Limit.* https://eips.ethereum.org/EIPS/eip-170 — O muro dos 24,576 bytes (§16.3).
18. V. Buterin. *EIP-1014: Skinny CREATE2.* https://eips.ethereum.org/EIPS/eip-1014 — A aritmética de endereços de 𝒟 (§7).
19. M. Lundfall et al. *EIP-2612: Permit Extension for EIP-20 Signed Approvals.* https://eips.ethereum.org/EIPS/eip-2612 · Uniswap Labs. *Permit2.* https://github.com/Uniswap/permit2 — A porta Permit2 (§11.1).
20. V. Buterin, S. Wilson, A. Dietrichs, M. Garnett. *EIP-7702: Set Code for EOAs.* https://eips.ethereum.org/EIPS/eip-7702 — As contas delegadas chamam as mesmas portas (§11.1).
21. *ERC-7201: Namespaced Storage Layout.* https://eips.ethereum.org/EIPS/eip-7201 — O namespace de storage do Hub (§16.1).
22. MariaDB Corporation Ab. *Business Source License 1.1.* https://mariadb.com/bsl11/ — A licença do código.
23. Fable & Mitra. *BlazePhoenix-Dex: an on-chain DEX aggregator with measured routing.* Repositório, `main` 8949a9d, 2026-09-05. https://github.com/blazephoenixxyz-crypto/Blaze-Phoenix-Dex — A fonte canónica de cada afirmação deste documento; o Apêndice C reproduz os números a partir dela.
24. S. Müller, N. Moumeni, A. Messaoudi. *Cost of Manipulation in AMM-Based Oracles.* arXiv:2606.03548, 2026 (Financial Cryptography 2026, DeFi workshop). — O limite da mediana ponderada pela liquidez por trás de E25 (§10.3, §23).
25. *Ormer: A Manipulation-resistant and Gas-efficient Blockchain Pricing Oracle for DeFi.* arXiv:2410.07893. — Um oracle on-chain que estima a mediana (§23).
26. *From Means to Medians: Optimal Benchmark Design.* arXiv:2506.22142. — Quais os benchmarks mais difíceis de manipular (§23).
27. *Optimal Routing across Constant Function Market Makers with Gas Fees.* arXiv:2603.02844. — Encaminhamento com gas (§23).
28. *Routing Frictions and Executable Liquidity in Fragmented Markets.* arXiv:2609.19013. — Liquidez anunciada versus executável (§23).

## Como citar

Mitra. *BlazePhoenix Technical Whitepaper: an on-chain liquidity aggregator whose quote and execution are one computation.* Versão 2.3.0, 2026-10-14. Zenodo. DOI [10.5281/zenodo.23084091](https://doi.org/10.5281/zenodo.23084091) (a v2.3 depositada). Todas as versões: [10.5281/zenodo.23084090](https://doi.org/10.5281/zenodo.23084090). DOI de conceito da primeira série de depósitos (v2.2): [10.5281/zenodo.22526574](https://doi.org/10.5281/zenodo.22526574). BibTeX e outros formatos: https://blazephoenix.xyz/research/whitepaper
