Implantação

O protocolo é implantado em duas chains, numa ordem que não é negociável.

As carteiras

Três papéis distintos, nunca a mesma chave.

Carteira O que pode fazer
Owner do protocolo Fazer o upgrade de todos os módulos, exceto os tokens, o lock de liquidez e o deployer dos vaults espelho; conectar a factory; registrar baskets; definir os endereços write-once; mudar os parâmetros do protocolo; definir as listas de exclusão do airdrop e registrar o OFT de cada ação; retirar ativos numa emergência, de imediato; retirar o que um módulo detém por engano (rescue); iniciar ou cancelar o modo de encerramento, e recuperar a liquidez depois de transcorridos os seus 30 dias
Keeper Acionar conversões, lotes da bridge e o airdrop: abrir ciclos, enviar ações, alocar as ações guardadas à parte. Desde 2026-10-05, também pagar o que o hook e o lock guardam para um destinatário e coletar as taxas de LP, chamadas abertas a qualquer pessoa
Deployer Implantar os contratos. É o owner da factory até que o owner do protocolo aceite a propriedade, e administra o hub remoto até que o primeiro lote da bridge designe ali o owner do protocolo

Os scripts obtêm o seu signatário da linha de comando do forge ou de uma DEPLOYER_PRIVATE_KEY bruta no ambiente. DeployEthereumRail, DeployProtocol, DeployRemote e DeployBridge aceitam qualquer um dos dois; LaunchProtocol, RegisterBaskets e CreateMarket só leem DEPLOYER_PRIVATE_KEY.

Toda transmissão (broadcast) é feita com --slow --skip-simulation, desde o décimo loop de auditoria. Sem eles, o forge dá a cada transação o gas que a sua própria simulação contou, aos preços anteriores à atualização Glamsterdam do Ethereum, e uma criação de contrato precisa de quatro a sete vezes mais depois dela: cada criação ficaria sem gas. Com eles, o forge usa a estimativa do nó para cada transação, depois de minerada a anterior. Os números de gas de um dry run também não servem de orçamento: com a Glamsterdam, o DeployProtocol precisa de cerca de 240 milhões de gas, e o lançamento de cada mercado de 15 a 24 milhões.

A ordem

Três restrições a determinam. Todo módulo do Ethereum recebe o endereço da factory na construção, então a factory vem primeiro, e o seu owner conecta o resto a ela depois. O router e o oráculo do trilho no Ethereum, como o hub da bridge, estão vinculados à factory, então vêm depois do protocolo. Os dois hubs fixam um ao outro por endereço previsto.

  1. DeployProtocol: a factory primeiro, depois o hook, minerado para todas as 14 permissões v4, o lock, o registrador de posições, os deployers, a implementação dos vaults, a lens, o swap router e o contrato do airdrop, AirdropDistributor, todos conectados à factory. A propriedade passa então para o owner do protocolo, que precisa aceitá-la
  2. DeployEthereumRail, com o endereço da factory: o oráculo e o router ETH → USDC no Ethereum, que o owner define na factory
  3. DeployBridge --sig "predict()": imprime os endereços que o hub da bridge e o seu adaptador vão receber
  4. DeployRemote na Robinhood Chain: primeiro o hub remoto, fixado nesses endereços previstos, depois o router de ações, o oráculo e a implementação dos vaults espelho, que o admin do hub conecta a ele, com a rota do airdrop e os adaptadores de ações quando eles forem informados (abaixo). Desde 2026-10-06, ele define em toda execução as duas políticas de gas do hub remoto para as entregas do airdrop no Ethereum, antes da rota do airdrop (abaixo), e as duas salvaguardas do oráculo, e se recusa a iniciar sem uma decisão sobre a verificação do sequenciador: SEQUENCER_UPTIME_FEED, o feed de disponibilidade do sequenciador L2 da Chainlink na Robinhood Chain, ou SEQUENCER_CHECK_OFF=true, a verificação desligada por escolha, nunca os dois, com SEQUENCER_GRACE_PERIOD (3.600 segundos por padrão) só ao lado de um feed. A Chainlink não publica nenhum feed assim para a Robinhood Chain, então uma execução na mainnet hoje define SEQUENCER_CHECK_OFF=true, e o owner do StockFun define o feed depois (setSequencerUptimeFeed) se algum for publicado. O script então liga a pausa do oráculo de cada ação (setOraclePauseCheck), depois do hub, do router e do oráculo, para que nenhum endereço previsto mude
  5. DeployBridge: o hub da bridge e o seu adaptador, nos endereços previstos; o owner designa o adaptador no hub, uma única vez (setAdapter). Desde 2026-10-05, o script para antes de implantar qualquer coisa quando a factory já designa um hub (desde 2026-10-06, é a sua primeira verificação, antes dos endereços previstos) e, quando o seu signatário é o owner da factory, mapeia as ações antes de designar o hub
  6. setBridgeHub — antes do primeiro mercado. Desde 2026-10-05, ele recusa um hub que não consegue transportar um basket já registrado (UnmappedBridgeStock)
  7. addStockMapping no hub da bridge, para cada ação de um basket
  8. Registrar os baskets: PlanBridgeBaskets imprime as chamadas do owner. Desde 2026-10-06, um basket contém no máximo cinco ações: veja Baskets
  9. LaunchProtocol: $STOCKFUN, cujo supply inteiro vai para a sua posição travada, o seu vault, o BuybackBurner e setBuybackWallet. Ele precisa do contrato do airdrop designado antes, o que o DeployProtocol faz: desde 2026-10-05, ele coloca o operador do lançamento na lista de exclusão do $STOCKFUN antes da cunhagem, no endereço que o token vai ocupar. Desde 2026-10-06, uma execução que parou antes de o mercado do protocolo ser designado é retomada com o token e o vault que deixou (--sig "resume(address,address)"), verificados primeiro, em vez de cunhar um segundo $STOCKFUN; depois que o mercado do protocolo é designado, o script não roda mais, e as etapas restantes são feitas à mão
  10. registerStockOft no contrato do airdrop, pelo owner, para o OFT de cada ação no Ethereum

Cada módulo upgradável é implantado como dois contratos, a sua implementação e depois o seu proxy. predict() os conta: o proxy do hub da bridge vem no nonce + 1 do deployer, o do seu adaptador no nonce + 3.

O StockFun não pareia nenhum peer da LayerZero: os peers do OFT do USDG pertencem ao seu emissor, e o preflight apenas os verifica.

Desde 2026-10-06, o script local e o de testnet, LocalRun e DeployTestnetBridge, só gravam o seu arquivo de implantação quando de fato enviam as suas transações (broadcast), e o DeployTestnetRail também desde o nono loop de auditoria: os endereços de um dry run não têm código. Na testnet, o DeployTestnetRail recebe as mesmas três entradas do sequenciador, todas opcionais (sem feed, a verificação fica desligada, já que a Chainlink também não lista nenhum para a testnet), e liga a pausa do oráculo de cada ação; os scripts do Ethereum deixam as duas salvaguardas desligadas. Um keeper de testnet roda com KEEPER_REQUIRE_MARKET_OPEN, KEEPER_AIRDROP_AFTER_SESSION e, desde 2026-10-06, KEEPER_CONVERT_ONCE_PER_WINDOW em false, para que converta a cada passagem: veja O keeper. Desde o sétimo loop de auditoria, em 2026-10-06, o keeper verifica a chain de cada RPC contra a sua configuração antes de iniciar: um keeper de testnet define KEEPER_CHAIN_ID=11155111 e, com a bridge, KEEPER_REMOTE_CHAIN_ID=46630, e um keeper de mainnet KEEPER_CHAIN_ID=1 com 4663. Desde o oitavo loop de auditoria, os dois são obrigatórios: o keeper se recusa a iniciar sem KEEPER_CHAIN_ID, ou sem KEEPER_REMOTE_CHAIN_ID ao lado da bridge. O Worker de dados do app verifica a chain dos seus endpoints da mesma forma, e os seus RPCs públicos seguem os seus dois ids de chain, então um Worker de testnet só precisa deles.

A execução em testnet com a LayerZero de 2026-10-06 implantou o protocolo na Sepolia e na testnet da Robinhood Chain (chain 46630) com os scripts de produção, ou wrappers de testnet que mantêm o seu corpo, e os seus próprios tokens, locais de negociação e adaptadores de teste, numa pasta dos contratos só para testnet. Desde o nono loop de auditoria, o preflight também verifica essa execução, a partir dos seus dois arquivos, com SEPOLIA_RPC_URL e ROBINHOOD_TESTNET_RPC_URL. O que a execução provou, e o que não provou, está em Testes e verificação.

O airdrop

Desde 2026-10-04, o contrato do airdrop é implantado com o protocolo. As suas configurações vêm do ambiente:

Script Variável Padrão Papel
DeployProtocol AIRDROP_LZ_ENDPOINT Nenhum: só o trilho local Endpoint da LayerZero no Ethereum, para as ações compradas na Robinhood Chain
DeployProtocol AIRDROP_REMOTE_EID 30416 com um endpoint O id de endpoint LayerZero da Robinhood Chain, a única origem de uma entrega
DeployProtocol AIRDROP_CYCLE_LENGTH 86.400 (24 horas) Duração de uma janela, em segundos, um número inteiro de horas
DeployProtocol AIRDROP_CYCLE_OFFSET 46.800 (13:00 UTC) Onde as janelas terminam, em segundos depois de 00:00 UTC, um número inteiro de horas: antes da abertura americana o ano inteiro
DeployRemote AIRDROP_DISTRIBUTOR Nenhum O contrato do airdrop no Ethereum para o qual os vaults espelho enviam
DeployRemote AIRDROP_RECEIVE_GAS, _MIN, _MAX 650.000, 200.000, 1.500.000 Desde 2026-10-06: o gas do lzReceive de cada entrega no Ethereum, além do que o OFT da ação impõe, quando o keeper pede o padrão, e o piso e o teto do que ele pode pedir
DeployRemote AIRDROP_COMPOSE_GAS, _MIN, _MAX 1.250.000, 600.000, 4.000.000 O gas da chamada de cada entrega no contrato do airdrop, lzCompose, da mesma forma. Até 2026-10-06, um único número, 600.000, definia toda entrega
DeployRemote STOCK_ADAPTERS Nenhum Lista separada por vírgulas, um adaptador LayerZero por entrada de STOCKS, zero para uma ação sem adaptador

Estes são valores iniciais: o owner pode mudar o cronograma (setCycleSchedule) e o endpoint LayerZero (setLayerZero) depois. No DeployRemote, AIRDROP_DISTRIBUTOR e STOCK_ADAPTERS são opcionais: o admin do hub remoto pode defini-las depois (setAirdrop, setStockAdapter). As duas políticas de gas são definidas em toda execução, a partir do ambiente ou dos padrões do hub, antes do distribuidor, cujo gas de compose precisa ficar dentro delas; o admin pode mudá-las depois (setAirdropReceiveGas, setAirdropComposeGas). Um valor acima de uint128 interrompe a execução. Em seguida vêm as etapas do owner:

  • setAirdropDistributor na factory, feito pelo DeployProtocol. O owner pode designar outro depois; os vaults o leem em tempo real, e um distribuidor substituído mantém cada ciclo reivindicável onde está
  • registerStockOft no contrato do airdrop, para o OFT de cada ação no Ethereum, que precisa usar o próprio endpoint LayerZero do contrato
  • setExclusions, só para um token que precise de endereços excluídos além do endereço de burn: nenhum token de mercado precisa por padrão; a lista do $STOCKFUN, com o seu operador do lançamento, é definida pelo LaunchProtocol

Os próprios adaptadores de ações, um por ação — o adaptador de travamento na Robinhood Chain e o seu OFT no Ethereum —, não estão no repositório para a mainnet: eles precisam do pacote oft-evm da LayerZero. O DeployRemote recebe os seus endereços. A execução em testnet com a LayerZero de 2026-10-06 usou adaptadores de teste, o OFTAdapter da LayerZero sobre ações de teste e o OFT da LayerZero para as ações wrapped, na sua pasta só para testnet.

Cada entrega vinda da Robinhood Chain roda no Ethereum em duas chamadas: o lzReceive do OFT da ação, que cunha a ação wrapped para o contrato do airdrop, e depois o lzCompose do contrato do airdrop, que a credita. Desde 2026-10-06, o keeper indica o gas das duas em cada envio, escolhido a partir de simulações no Ethereum (veja O keeper), e o hub remoto limita cada valor à sua política, e zero assume o padrão. Os padrões cobrem com 35 % e 30 % de folga os casos mais pesados medidos na Sepolia depois da atualização Glamsterdam do Ethereum: lá, um lzReceive precisa de 184.702 de gas para um saldo que o contrato do airdrop já detém, e 481.548 para a primeira entrega de uma ação; um compose, 105.075 quando o ciclo já lista a ação, 433.645 quando o ciclo que o keeper abriu ainda não a lista, cerca de 531.600 quando a entrega é também o primeiro crédito do ciclo, e 962.154 quando ela mesma abre o ciclo. A entrega mais pesada construída nos testes, uma abertura contra dezesseis holders excluídos com históricos longos que também leva junto quatro ações guardadas à parte, precisa de cerca de 2,8 milhões aos preços da Glamsterdam, abaixo do teto do compose. Antes da Glamsterdam, medido a frio nos testes, uma entrega num ciclo aberto levava cerca de 85.000, uma que abre um ciclo contra um endereço excluído cerca de 275.000, e a mais pesada cerca de 1.016.000. Uma entrega sem gas suficiente falha sem perder nada: ela fica armazenada no endpoint da LayerZero, com as ações wrapped já no contrato do airdrop quando só o compose falhou, e qualquer pessoa pode executá-la de novo com mais gas. Desde 2026-10-06, o próprio keeper faz isso, dentro do seu próprio limite, e alerta uma segunda falha.

A conexão da factory

A factory é inicializada apenas com o seu owner e as suas três carteiras; os seus parâmetros começam nos seus padrões. O owner designa todo o resto depois:

  • setLaunchModules: o hook e o lock, de uma vez por todas; os dois precisam designar esta factory, e o lock, este hook
  • setDeployers: os dois deployers, que podem ser substituídos
  • setVaultImplementation: a implementação por trás dos vaults dos mercados criados depois
  • setHoldingRecorder: o registrador que os novos tokens de mercado notificam
  • setAirdropDistributor: o contrato do airdrop ao qual os vaults entregam as suas ações; ele precisa designar esta factory
  • setTreasuryRouter, setTreasuryOracle, setSwapRouter, setBridgeHub e setProtocolMarket

Nenhum mercado pode ser criado enquanto o lock, uma implementação de vault e um registrador de posições não forem designados.

O hub da bridge e o swap router

setBridgeHub só pode ser definido uma vez. Uma omissão aqui não pode ser desfeita. Desde 2026-10-05, ele recusa um hub que não consegue traduzir todas as ações dos baskets já registrados: mapeie-as antes no hub.

setBridgeHub precisa ser chamado antes da criação do primeiro mercado. Cada TreasuryVault fixa o endereço do hub da bridge na construção. Um vault criado enquanto o endereço é zero fica no trilho local para sempre e nunca envia nada para a Robinhood Chain.

setSwapRouter não é write-once: o owner pode mudá-lo a qualquer momento. Ele não afeta mais nenhum vault: os vaults deixaram de lê-lo quando o buyback do criador foi removido do código, em 2026-09-28. Ele registra o endereço do swap router oficial, que o preflight verifica.

O hook e o seu endereço minerado

O endereço de um hook codifica as suas permissões v4 nos bits menos significativos: ele é encontrado por força bruta sobre o salt do CREATE2. Desde 2026-10-02, o endereço minerado é o do proxy do hook, com todos os 14 bits de permissão ativados. Ele depende do bytecode do proxy e dos argumentos do seu construtor, que carregam o endereço da implementação. Uma nova implantação precisa ser minerada de novo; um upgrade mantém o endereço.

foundry.toml precisa conter bytecode_hash = "none" e evm_version = "cancun", senão o endereço minerado não vai corresponder ao contrato implantado.

Upgrades

Um upgrade é uma chamada do owner do protocolo ao proxy do módulo, que designa a nova implementação; ele tem efeito imediato. Antes de cada upgrade, contracts/script/check-storage-layouts.sh compara o novo layout de storage com o registrado em contracts/storage-layouts/, e falha com qualquer mudança que não seja um acréscimo. Desde 2026-10-05, ele compara cada nível de cada struct, tamanhos incluídos, e recusa qualquer mudança numa struct que seja o elemento de um array de storage: só uma struct que seja o valor de um mapping, ou a última variável de estado, pode crescer, no seu final. --write atualiza os registros depois de uma mudança deliberada.

As políticas de gas do hub remoto vieram com o nono loop de auditoria, em 2026-10-06. Um hub implantado antes delas e que recebeu upgrade lê as duas políticas como zero, e um vault espelho que recebeu upgrade para o código correspondente recusa todo envio ao airdrop e toda cotação (AirdropGasNotSet) até que as duas sejam definidas. A ordem é, portanto: fazer o upgrade do hub remoto, definir as duas políticas (setAirdropReceiveGas, setAirdropComposeGas), depois designar a nova implementação dos vaults espelho e fazer o upgrade de cada vault espelho, e só então iniciar um keeper do nono loop, que pede as políticas ao hub e envia com três argumentos. Um keeper anterior continua enviando com os padrões do hub enquanto isso. Um hub implantado com o novo código define os padrões na inicialização.

Os parâmetros de lote do adaptador do USDG vieram com o décimo loop de auditoria, em 2026-10-06: o gas de compose que cada mercado de um lote da bridge acrescenta, e o máximo de mercados que um lote leva. Um adaptador implantado antes deles e que recebeu upgrade lê os dois como zero e recusa todo lote e toda cotação (BatchGasNotSet) até que eles sejam definidos. O seu upgrade, portanto, os traz na mesma transação (upgradeToAndCall com setBatchGas(400000, 17)), depois o owner baixa o seu antigo gas de compose, 1.200.000, para a base de que todo lote agora precisa (setSettings, 200.000), e só então inicia um keeper do décimo loop, que lê o teto a cada lote. Um keeper anterior continua funcionando com o adaptador que recebeu upgrade enquanto não houver mais de 17 mercados prontos ao mesmo tempo. O adaptador da testnet recebeu upgrade dessa forma em 2026-10-06, e o seu lote seguinte passou com o seu novo gas de compose.

Um upgrade que muda o que o serviço de dados do app lê entra em produção antes desse serviço. Desde 2026-10-06, a Lens traz o estado de cada vault e o que o hook e o lock lhe devem, e o Worker e o app que leem esses campos não conseguem ler uma Lens anterior: faça primeiro o upgrade da Lens. O sétimo loop de auditoria não muda nem a Lens nem o formato do que o Worker publica (esquema 7): o seu Worker e o seu app são implantados em qualquer ordem. O oitavo muda o formato (esquema 8: cada preço de ação diz por que falta, quando o oráculo da Robinhood Chain o retém), não a Lens, e o seu Worker e o seu app continuam sendo implantados em qualquer ordem: um app mais antigo ignora o motivo, e este app lê um Worker mais antigo sem ele. O nono mantém o esquema 8.

O oráculo do trilho Robinhood, como qualquer TreasuryOracle, começa com as suas duas salvaguardas desligadas. Um oráculo substituto designado no hub remoto (setOracle) começa, portanto, com elas desligadas também, e o admin do hub as liga de novo para ele, como faz o script de implantação: a pausa do oráculo de cada ação, e o feed do sequenciador se algum tinha sido definido. Os vaults espelho já inicializados mantêm o oráculo com que foram inicializados.

Parâmetros

Um parâmetro é uma chamada do owner do protocolo ao módulo que o guarda, ou, na Robinhood Chain, do admin do hub remoto; ele tem efeito imediato e emite um evento. Todo módulo começa com os padrões listados em Modelo de confiança. Os adaptadores da bridge começam com o gas da implantação: no trilho do USDG, COMPOSE_GAS, a parte do último passo de um lote de que todo lote precisa, 200.000 por padrão no DeployBridge desde o décimo loop de auditoria (1.200.000 para o passo inteiro até então), mais 400.000 para cada mercado do lote e no máximo 17 mercados por lote (setBatchGas; o gas do maior lote, no máximo 24.000.000), ao lado de um limite de 30 pontos-base na Curve; no trilho canônico, o gas dos dois tickets e, desde 2026-10-05, os bytes sobre os quais o custo do ticket de depósito é calculado (DEPOSIT_CALLDATA_LENGTH no DeployTestnetBridge; zero assume o padrão, 1.024). O hub remoto começa com as duas políticas de gas das entregas do airdrop (acima).

Antes da mainnet

  • Um ensaio completo do modo de emergência: transferência, pausa, fim da pausa
  • Um primeiro airdrop pequeno num vault de verificação, antes de qualquer abertura pública. A execução em testnet com a LayerZero de 2026-10-06 fez o código do StockFun funcionar de ponta a ponta sobre os endpoints, o DVN e o executor de testnet da LayerZero; ela não prova nem o par USDG da Paxos, nem as ações da Robinhood e os seus adaptadores, nem feeds e liquidez reais, nem o gas, as taxas e a finalidade da mainnet
  • Um levantamento atualizado dos feeds de preço na chain remota
  • Verificação dos peers da LayerZero do OFT do USDG e do estado de pausa do USDG, via preflight; desde o oitavo loop de auditoria, o preflight também verifica as salvaguardas do oráculo contra o seu manifesto, que precisa declarar a verificação do sequenciador, hoje desligada
  • O limite de tamanho da rota que o USDG da Paxos usa até a Robinhood Chain, lido na biblioteca de envio da LayerZero (getExecutorConfig), e o teto de mercados de um lote da bridge ajustado de acordo se ele não for de 10.000 bytes: no máximo (tamanho − 392) ÷ 544 mercados (desde o décimo loop de auditoria)
  • Revisão externa — as provas formais existentes não cobrem o trilho cross-chain