> For the complete documentation index, see [llms.txt](https://docs.rome.builders/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rome.builders/pt-br/apps-na-rome/bloom/building.md).

# Construindo no Bloom

Este guia responde a uma pergunta: **como um desenvolvedor faz isso por conta própria?** Pegue um contrato de ativo do mundo real em Solidity, coloque-o em funcionamento em uma chain Rome como um token permissionado, abra-o para carteiras Solana e também para carteiras EVM, sem ponte e sem um segundo token, e conecte sua própria decisão de KYC/compliance.

O público é um desenvolvedor avaliando ou adotando a abordagem. Bloom é o exemplo prático ao longo de tudo — seu ativo em produção **ARCV ("Mineral Vault I")** no Hadrian (`200010`) é uma instância real de cada etapa abaixo, e seu recibo de deploy (`deployments/200010.tokens/ARCV.json`) registra exatamente os três contratos e as oito transações que este método produz.

Nada aqui modifica os contratos do ativo. Bloom executa a framework Arc da Plume **sem modificações** (a árvore vendorizada em `contracts/`, idêntica byte a byte a `plumenetwork/contracts` no pin em `NOTICE`); o único contrato do lado Rome é `ArcTokenFactoryV2`, que adiciona uma função. O trabalho está em *como* você faz o deploy e *como* dirige os contratos — não em alterá-los.

> **O método, em resumo.** Um token permissionado é **três** contratos implantados. Ele é implantado **em partes** — um contrato por transação — porque uma chamada de factory em uma única transação excede o limite de contas por transação de Rome. Seus proxies precisam vir de **artefatos com proveniência travada** ou o registro on-chain falha em modo fechado. O compliance é um **booleano por endereço**, escrito por quem quer que seu processo de KYC autorize. E o mesmo deploy pode ser acessado de uma carteira Solana por meio de um **sender sintético** derivado on-chain — sem ponte, sem token embrulhado, sem uma segunda allowlist.

## Pré-requisitos

> **Antes de começar.** As ferramentas de emissão usadas neste guia ainda não foram publicadas. Isso inclui os scripts (`deploy-infra.ts`, `create-token.ts` e o restante), as árvores de `contracts/` e `rome-contracts/` e os recibos de deploy que ele nomeia. Os emissores obtêm essas ferramentas ao fazer onboarding com a Rome. Até lá, leia o guia como uma descrição do método e do que cada script faz.

As ferramentas de referência ficam em um diretório `scripts/` (fornecido no onboarding; instale as dependências com `npm install`). Cada comando resolve os fatos da chain a partir do registry em vez de codificá-los no código, então redirecionar para outra chain Rome é uma mudança de ambiente, não de código:

```bash
export PRIVATE_KEY=…       # chave de deploy/emissor financiada na chain de destino
export CHAIN_ID=200010     # seleciona a chain
export REGISTRY_ROOT=…     # um checkout do registry da chain Rome
# Os fluxos da rota Solana também precisam de:
export SOLANA_KEYPAIR=…    # caminho para um JSON de keypair Solana financiado (o pagador da taxa)
```

O gas nas chains Rome é denominado em USDC; a sequência completa de deploy custa na faixa de 10–15 unidades nativas na devnet. As chaves vêm apenas do ambiente — nunca do repositório. Compile os contratos uma vez antes de fazer o deploy, porque os artefatos **devem** vir de `rome-contracts/out` (veja a etapa 3):

```bash
cd contracts       && forge build --via-ir     # a suíte Arc vendorizada
cd rome-contracts  && forge build --via-ir     # ArcTokenFactoryV2 + o proxy canônico
```

***

## Etapa 1 — Entenda o que um token permissionado *é* aqui

Um token Bloom permissionado não é um contrato. Ele é **três contratos implantados**, além de quatro contratos compartilhados que a ops implanta uma vez por chain e que todo emissor reutiliza.

**Os três contratos por token** — um ativo possui exatamente estes:

| Contrato                     | Fonte                                                       | O que é                                                                                                                          |
| ---------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `ArcTokenProxy`              | `contracts/src/proxy/ArcTokenProxy.sol`                     | O próprio token — um proxy UUPS apontando para a `ArcToken` implementação compartilhada. Saldos, detentores e papéis vivem aqui. |
| `WhitelistRestrictions`      | `contracts/src/restrictions/WhitelistRestrictions.sol`      | O módulo de allowlist. Um booleano por endereço; aplicado em toda transferência enquanto o ativo estiver bloqueado.              |
| `YieldBlacklistRestrictions` | `contracts/src/restrictions/YieldBlacklistRestrictions.sol` | O módulo de rendimento. Exclui endereços das distribuições de rendimento sem mexer em sua participação.                          |

**Os quatro contratos compartilhados, um por chain** (implantados por `deploy-infra.ts`):

| Contrato                   | Função                                                                            |
| -------------------------- | --------------------------------------------------------------------------------- |
| `RestrictionsRouter`       | Registro de tipo de módulo — a ligação da chain, definida uma única vez pela ops. |
| `ArcTokenFactoryV2`        | Registro + o codehash canônico do proxy (etapas 2–3).                             |
| `ArcToken` (implementação) | A lógica de ativo compartilhada e reutilizável para a qual todo token faz proxy.  |
| `ArcTokenPurchase`         | Uma única vitrine, compartilhada por todos os tokens e emissores (etapa 4).       |
| wUSDC                      | A perna financeira — moeda de rendimento e moeda de compra/venda.                 |

A restrição de transferência e a restrição de rendimento são **módulos deliberadamente separados**: um detentor pode ser impedido de receber renda enquanto mantém o ativo, que é assim que sanções e ordens judiciais realmente funcionam.

Esse fato dos "três contratos" é essencial para a verificação. `verify-deployments.ts` e `register-asset.ts` ambos esperam que um token se resolva em três contratos implantados — verificar um token manualmente uma vez deixou passar sete deles em uma chain (todos os módulos de rendimento e três módulos de whitelist).

O ciclo de vida tem três fases e uma porta sem volta:

```
rascunho     proxy ao vivo, nenhum módulo vinculado — nada bloqueia uma transferência
  ↓
sem bloqueio   módulo vinculado, transfersAllowed = true   (WhitelistRestrictions.initialize define isso)
  ↓  emita a oferta, construa a allowlist               [reversível]
bloqueado     setTransfersAllowed(false)                [PORTA DE SENTIDO ÚNICO — a oferta se torna definitiva]
```

O bloqueio é de mão única para a oferta porque mint e burn passam `address(0)` como contraparte, e `address(0)` nunca pode entrar na allowlist — então, uma vez bloqueado, nenhuma nova oferta pode jamais ser mintada. Essa é a garantia que um ativo permissionado oferece aos seus detentores.

***

## Etapa 2 — Faça o deploy em partes, nunca em uma única transação

A Arc traz uma única chamada `createToken` que faz o deploy do proxy e dos dois módulos e os conecta em uma única chamada. **Em Rome você não pode usá-la.** Essa transação precisa de **77 bloqueios de contas Solana**, e o limite por transação de Rome é **62 bloqueios**. Isso nunca cabe — nem com ajustes, nem com uma passada de otimizador.

Então o deploy é **em partes**: cada contrato em sua própria transação, e o token ganha status equivalente ao de uma factory por meio de `ArcTokenFactoryV2.registerToken` em vez do `createToken`monolítico. Este é o assistente de criação, e é o que o console do emissor faz passo a passo:

![o assistente de criação](https://735130481-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F671PKS8ZQSNqtoC8PGvz%2Fuploads%2Fgit-blob-94683a3a49ac2418aed8cc66dbf47fad940814f7%2Fcreate-wizard.png?alt=media)

A implementação de referência é `arc/plan/create.ts` (`createSequence()`), que o app renderiza como seis cards (`bloom/lib/createCards.ts`) ao longo de **oito transações**, na ordem exata que os contratos impõem:

| # | Transação                           | Chamada de contrato                                                            |
| - | ----------------------------------- | ------------------------------------------------------------------------------ |
| 1 | Faça o deploy do ativo              | `new ArcTokenProxy(impl, initData)` onde `initData = ArcToken.initialize(...)` |
| 2 | Implante o módulo da allowlist      | `new WhitelistRestrictions()`                                                  |
| 3 | Defina você como administrador dele | `whitelist.initialize(issuer)`                                                 |
| 4 | Aplique-o nas transferências        | `token.setRestrictionModule(TRANSFER, whitelist)`                              |
| 5 | Implante o módulo de rendimento     | `new YieldBlacklistRestrictions()`                                             |
| 6 | Defina você como administrador dele | `yieldBlacklist.initialize(issuer)`                                            |
| 7 | Aplique-o no rendimento             | `token.setRestrictionModule(YIELD, yieldBlacklist)`                            |
| 8 | Registre na factory                 | `factoryV2.registerToken(token, impl)`                                         |

O formato em script é um comando:

```bash
# uma vez por chain (ops, não por token) — faz o deploy dos quatro contratos compartilhados
npx tsx deploy-infra.ts

# por token — o assistente, reproduzido como script
NAME="Mineral Vault I" SYMBOL=ARCV SUPPLY=1000000 DECIMALS=6 npx tsx create-token.ts
```

O emissor (`PRIVATE_KEY`) assina cada transação e termina com a posse dos papéis do token (`ArcToken.initialize` concedidos a `msg.sender` — veja a etapa 7). O registro (tx 8) é o que desbloqueia a `enableToken` e qualquer atualização mediada pela factory.

> **Não "otimize" isso de volta para um monólito.** Agrupar essas chamadas em uma única transação para economizar idas e voltas reintroduz exatamente o estouro de 62 bloqueios que o caminho em partes existe para evitar. O mesmo limite é o motivo pelo qual a distribuição de rendimento percorre um detentor por transação (etapa 8). Se uma chamada falhar com `Muitas contas: N > 62`, uma transação está tocando contas demais — divida, não tente ajustar.

***

## Etapa 3 — Faça o deploy dos proxies somente a partir dos artefatos com proveniência travada

`registerToken` é a fronteira de segurança que permite que deploys em partes sejam seguros. Ele só aceitará um token cujo **codehash de runtime corresponda ao canônico `ArcTokenProxy`** incorporado na factory no momento do deploy:

```solidity
// rome-contracts/src/ArcTokenFactoryV2.sol
bytes32 private immutable CANONICAL_PROXY_CODEHASH =
    keccak256(type(ArcTokenProxy).runtimeCode);

function registerToken(address token, address implementation) external {
    if (token.codehash != CANONICAL_PROXY_CODEHASH) revert ProxyCodehashUnknown();
    // …a implementação precisa estar na allowlist da factory, e msg.sender deve deter o
    //    ADMIN_ROLE do token, e o token não pode já estar registrado.
}
```

Como esse codehash é um **imutável**, um proxy construído a partir de qualquer outro artefato falha em modo fechado com `ProxyCodehashUnknown`. Duas regras se seguem, e ambas são impostas pelo CI e pelas regras rígidas em `CLAUDE.md`:

1. **Os proxies do token DEVEM ser implantados a partir de `rome-contracts/out`** — nunca a partir de `contracts/out`, nunca a partir de uma build diferente. Essa é a compilação que o codehash canônico da factory fixa.
2. **`bytecode_hash = "none"` e `cbor_metadata = false`** em `rome-contracts/foundry.toml` são fundamentais. Com metadados habilitados, o `ArcTokenProxy` em runtime *embutido* na factory (`type().runtimeCode`) carrega um sufixo CBOR/IPFS diferente do `out/` artefato do qual o assistente faz o deploy — então, em cadeia, `registerToken` reverte enquanto **todo teste Foundry no código-fonte passa** (o Foundry incorpora as duas cópias, então não consegue ver a divergência). `rome-contracts/test/ArtifactProvenance.t.sol` fixa essa propriedade; a execução financiada foi o que a detectou originalmente.

> **Uma suíte verde no código-fonte não prova a proveniência.** Antes de publicar uma imagem, e após QUALQUER mudança na configuração do compilador, prove a propriedade em relação à *factory implantada* (somente leitura, sem chaves):
>
> ```bash
> cd scripts && CHAIN_ID=<id> npx tsx verify-artifact-provenance.ts
> ```
>
> Ele calcula o hash do seu `ArcTokenProxy` artefato local e afirma que esse hash aparece literalmente dentro do bytecode da factory implantada.

Se as configurações do compilador precisarem mudar, **faça a rotação da factory** — faça o deploy de uma nova, cujo imutável fixe o novo codehash, e refaça a ligação — em vez de remendar a verificação manualmente:

```bash
cd scripts && CHAIN_ID=<id> npx tsx rotate-factory.ts
```

A rotação mantém o endereço antigo no recibo; tokens registrados na factory antiga precisam se registrar novamente na nova.

***

## Etapa 4 — Abra uma venda por meio da vitrine compartilhada

Vender é um ato separado de criar, e isso roda na única `ArcTokenPurchase` vitrine compartilhada. Três coisas precisam ser verdadeiras antes que uma venda seja aberta, e `ArcTokenPurchase.enableToken` verifica cada uma em cadeia:

```solidity
// contracts/src/ArcTokenPurchase.sol
function enableToken(address _tokenContract, uint256 _numberOfTokens, uint256 _tokenPrice)
    external onlyTokenAdmin(_tokenContract)                       // (a) você detém o ADMIN_ROLE do token
{
    // (b) o token precisa ser conhecido pela factory — isso foi o que registerToken (etapa 2) comprou:
    if (ArcTokenFactory(ps.tokenFactory).getTokenImplementation(_tokenContract) == address(0))
        revert TokenNotCreatedByFactory();
    // (c) a vitrine já precisa deter o estoque da venda:
    if (ArcToken(_tokenContract).balanceOf(address(this)) < _numberOfTokens)
        revert ContractMissingRequiredTokens();
    // …preço e quantidade precisam ser positivos.
}
```

Há um quarto requisito implícito imposto por um ativo bloqueado: porque **toda transferência passa pela barreira da allowlist**, mover o estoque para a vitrine só tem sucesso se o endereço da vitrine também estiver na allowlist do seu token. Então a sequência completa para abrir uma venda é:

1. **Coloque a vitrine na allowlist** no módulo de whitelist do seu token (`batchAddToWhitelist([storefront])` — veja a etapa 5). Sem isso, a transferência do estoque em (2) reverte `TransferRestricted()` uma vez bloqueado.
2. **Transfira o estoque** para o endereço da vitrine (a partir do recibo de infra de `arcTokenPurchase`).
3. **`enableToken(token, amount, price)`** — os compradores agora pagam wUSDC e recebem o RWA.

A divisão dos saques vale a pena conhecer em uma *vitrine* compartilhada, e ela não é simétrica (`arc/roles.ts` é a autoridade):

| Ação                                                       | Autoridade                        | Detida por                               |
| ---------------------------------------------------------- | --------------------------------- | ---------------------------------------- |
| `enableToken` / `disableToken` / `withdrawUnsoldArcTokens` | o `ADMIN_ROLE` (`onlyTokenAdmin`) | você, o emissor                          |
| `withdrawPurchaseTokens` (os proventos em wUSDC)           | da `DEFAULT_ADMIN_ROLE`           | quem quer que tenha implantado a vitrine |

Em uma chain auto-hospedada, você é ambos. Em uma vitrine compartilhada, o pool de receitas é o ganho de cada emissor, então o saque é no nível da plataforma — projete sua liquidação em torno disso em vez de assumir controle unilateral.

***

## Etapa 5 — Conecte seu próprio KYC / compliance

Esta é a seção que um cliente lê antes de dizer sim, então é código, não prosa. **O compliance é aplicado pelo próprio contrato do token** — não por uma triagem fora da cadeia, um filtro do sequenciador ou uma política de mercado. As regras viajam com o token para qualquer caminho de execução, em ambas as rotas de carteira. O que a chain registra é o **resultado** resultado da sua decisão de KYC, como um único booleano:

```solidity
// contracts/src/restrictions/WhitelistRestrictions.sol — o estado on-chain, por completo
struct WhitelistStorage {
    mapping(address => bool) isWhitelisted;   // ← um booleano por endereço. Sem PII, nunca.
    bool transfersAllowed;                    // false = bloqueado; somente endereços na allowlist transferem
    EnumerableSet.AddressSet whitelistedAddresses;
}
```

### A interface na qual seu processo escreve

A decisão de aprovar/negar do seu fornecedor de KYC se transforma exatamente em uma destas chamadas:

```solidity
interface IWhitelistRestrictions {
    function addToWhitelist(address account) external;                  // onlyRole(MANAGER_ROLE)
    function batchAddToWhitelist(address[] calldata accounts) external; // onlyRole(MANAGER_ROLE)
    function removeFromWhitelist(address account) external;             // onlyRole(MANAGER_ROLE)
    function isWhitelisted(address account) external view returns (bool);
    function setTransfersAllowed(bool allowed) external;                // onlyRole(ADMIN_ROLE)
}
```

### Quem pode escrever

> **A autoridade que uma aprovação precisa é `MANAGER_ROLE` no&#x20;*****o módulo*****&#x20;— não `ADMIN_ROLE` no token.** `addToWhitelist` / `batchAddToWhitelist` / `removeFromWhitelist` são todas `onlyRole(MANAGER_ROLE)`, e esse papel fica na `WhitelistRestrictions` instância. Autenticar `ADMIN_ROLE` no token e depois escrever no módulo é um defeito real pelo qual esta base de código já pagou. Não ofereça `WHITELIST_ADMIN_ROLE` isso como correção para uma recusa — ele é concedido no initialize e **não é checado em nenhum lugar na suíte** (`arc/roles.ts` afirma que é o único papel que não bloqueia nada).

`WhitelistRestrictions.initialize(issuer)` (tx 3 do assistente) concede ao emissor `DEFAULT_ADMIN_ROLE`, `ADMIN_ROLE`, `MANAGER_ROLE`, `WHITELIST_ADMIN_ROLE`, e `UPGRADER_ROLE` nesse módulo. Então o emissor detém `MANAGER_ROLE` de fábrica e também pode delegá-lo: como o emissor detém `DEFAULT_ADMIN_ROLE`, uma lista de contas de `grantRole(MANAGER_ROLE, serviceAccount)` entrega a escrita a um signer de back-end.

### Uma decisão se tornando uma escrita em cadeia

Aponte o webhook do seu fornecedor para um signer que detenha `MANAGER_ROLE`, e, em uma aprovação, agrupe os endereços:

```typescript
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';

// `signer` deve deter MANAGER_ROLE no módulo de whitelist DESTE token.
const wallet = createWalletClient({ account, transport: http(chain.rpcUrl) });

// o fornecedor disse "aprovado" para estes endereços:
await wallet.writeContract({
  address: whitelistModule,                 // resolvido A PARTIR do token via getRestrictionModule
  abi: whitelistAbi,
  functionName: 'batchAddToWhitelist',
  args: [approvedAddresses],
});
```

Resolver `whitelistModule` do próprio token (`ArcToken.getRestrictionModule(TRANSFER_RESTRICTION_TYPE)`), nunca de uma projeção em cache — apontar uma escrita para o módulo errado foi como "approve on any asset" que uma vez escreveu na allowlist de um token.

### A variante assinada pela carteira (demo de autoatendimento)

Para uma implantação de teste sem permissão em que os visitantes se autoadmitam, conceda `MANAGER_ROLE` a um `TestApprover` (`rome-contracts/src/TestApprover.sol`) cujo `o módulo` é **imutável**. Em seguida `approve(address)` pode ser chamada por qualquer pessoa, da própria carteira, pagando seu próprio gas — ela chama `addToWhitelist` somente se o endereço ainda não estiver listado:

```solidity
function approve(address account) external {
    IWhitelistRestrictions target = IWhitelistRestrictions(module);   // imutável — um módulo, para sempre
    if (!target.isWhitelisted(account)) target.addToWhitelist(account);
    emit Approved(account, msg.sender);
}
```

Esta é a "sign-in gate" — ela mostra a um visitante o mecanismo real (uma aprovação se tornando uma entrada de allowlist on-chain que o token então impõe) sem custodiar nada. **Nunca conceda `MANAGER_ROLE` a um `TestApprover` em um token de produção** — isso torna a allowlist desse token sem permissão.

### Quando a trava entra em ação, e a troca de provedores

A trava só restringe quando o ativo está **travado** (`setTransfersAllowed(false)`, `ADMIN_ROLE` no módulo). Enquanto não estiver travado, as transferências ficam abertas — construa sua allowlist primeiro, depois trave. Uma vez travado, uma transferência em que qualquer lado esteja fora da lista reverte com o erro tipado `TransferRestricted()` (`0xe827105e`).

> **Trocar de provedor de KYC depois não exige nenhuma mudança on-chain.** O módulo de allowlist, sua interface e o booleano que ele armazena são agnósticos ao provedor. Para trocar de fornecedor, aponte uma fonte de decisão diferente para o mesmo `MANAGER_ROLE` signer — sem redeploy, sem migração, sem mudança de estado. A chain nunca soube qual fornecedor fez a chamada, apenas o resultado.

***

## Etapa 6 — Abra o mesmo ativo para carteiras Solana

Os mesmos três contratos podem ser acessados a partir de uma carteira Solana **sem bridge e sem segundo token**. Um usuário nativo Solana não tem nenhuma chave EVM em lugar nenhum; em vez disso, sua identidade EVM é *sintética*derivada on-chain a partir do signer Solana real da transação:

```
synthetic EVM address = keccak256(solana_pubkey)[12..32]
```

O programa Rome EVM deriva isso do próprio signer (`do_tx_unsigned::derive_sender`), então não pode ser falsificado e nenhuma chave privada secp256k1 para isso existe — **a assinatura Solana é a única coisa que pode acionar esse endereço**. A derivação de referência é `arc/materialise/solana/identity.ts` (`syntheticAddress`), compatível em bytes com a regra on-chain:

```typescript
export function syntheticAddress(pubkey: SolanaPubkeyInput): `0x${string}` {
  return `0x${keccak256(pubkeyBytes(pubkey)).slice(-40)}`;
}
```

**O que um builder faz para dar suporte à lane** — observe que *nada disso é uma mudança no contrato*:

1. **Coloque o usuário Solana na whitelist pelo endereço sintético dele.** Para a camada de compliance, um endereço sintético é um endereço comum: cole a pubkey Solana do usuário, derive o sintético e `batchAddToWhitelist([synthetic])`. Uma única allowlist abrange os dois mundos de carteira.
2. **Provisione o PDA de assinatura uma vez, antes da primeira chamada que mova valor.** O PDA de autoridade externa que assina por um sintético deve existir primeiro, e criá-lo é uma `create_pda` chamada. Qualquer lado pode enviá-lo: a própria carteira Solana do usuário pela lane (a do SDK `buildCreatePdaCall`, após `isSyntheticProvisioned` retornar false), ou o emissor a partir de uma chave EVM. A ferramenta de emissor da Bloom o envia hoje como parte do onboarding de um titular; o app ainda não faz isso na primeira ação do usuário, então provisione antes da primeira compra do titular. Como, com as chamadas do SDK, isso está em [App de duas lanes](/pt-br/guias-do-desenvolvedor/dual-lane-app.md#one-time-activate-provision-the-synthetic).
3. **Envie pela biblioteca da lane, não manualmente.** `submitDoTxUnsigned` (`arc/materialise/solana/submit.ts`) pede ao proxy da chain para compor a transação, e ele lida com o que uma construída à mão faz errado. Toda chamada de contrato na lane é uma **transação Solana v1 composta pelo proxy** (`rome_composeUnsignedAtomicV1`) sem tabela de lookup de endereço, e a biblioteca da lane falha de forma fechada em vez de voltar para um formato mais antigo. A movimentação de caixa na etapa 5 é uma transação Solana separada que o app constrói sozinho, não uma chamada de contrato composta.
   * **A descoberta de contas e o orçamento de compute são tarefa do proxy.** Ele emula a chamada, decide a gravabilidade de cada conta (a chamada de `value` faz parte do que ele emula, então passe isso), e define o orçamento de compute e de heap na transação que ele retorna. Nada no seu código monta instruções de compute-budget ou adiciona a conta do fee-pool.
   * **Duas assinaturas por chamada, ambas a partir da chave Solana.** A carteira primeiro assina uma mensagem de autorização legível (*Autorização Rome* mais o hash do payload EIP-1559 unsigned; Wallet Standard `solana:signMessage`), que o proxy verifica antes de compor a chamada. Depois, ela assina a transação v1 que o proxy retorna (`solana:signTransaction` no formato bruto da rede). A biblioteca da lane trata isso como `signAuthHash` e `signV1Wire`, nunca como um único método mesclado. Verifique se sua carteira assina transações v1 antes de construir sobre ela: a Solflare faz isso no devnet hoje e a Phantom ainda não.
   * **O app envia a transação assinada para um RPC Solana por conta própria.** O proxy compõe; ele não transmite uma chamada atômica.
   * **Valide antes de pedir uma assinatura.** A biblioteca da lane analisa a mensagem composta e recusa uma mensagem malformada antes do prompt da transação.
4. **Coloque a concessão do wrapper de uso único antes do primeiro gasto de wUSDC.** wUSDC move os tokens de um usuário como delegado SPL desse usuário, então um endereço sintético que nunca recebeu concessão gera erro SPL na sua primeira transferência de wUSDC. Leia `0x4` no wrapper e, quando for falso, anteponha `isEnabled(user)` no precompile Helper como a primeira etapa da execução. É uma chamada comum em qualquer lane, uma vez por carteira. Veja `approve_spl(wrapper, 2^64-1, mint)` Mova o caixa antes de uma chamada que o gaste. [Concessão única por carteira](/pt-br/conceitos-principais/token-interop.md#one-time-grant-per-wallet).
5. **O sintético não mantém nada em repouso. Quando ele mantém menos wUSDC do que a chamada gasta, mova primeiro a diferença da própria conta de token USDC da carteira (uma criação idempotente da conta de token do sintético, depois a instrução activate-token-account do programa Rome, que move os tokens sem executar a EVM). É uma transação Solana assinada com um único prompt, e ela é ignorada quando o sintético já tem o suficiente.** Reencaminhe apenas o que o compositor atômico recusar.
6. **Uma chamada que não cabe em uma única transação Solana (cerca de 1,4M de unidades de compute, 64 contas, 4 KB) é recusada pelo compositor com** o plano atômico externo requer composição iterativa *o plano atômico externo requer composição iterativa*. Exatamente diante dessa recusa, e nunca antes, chame `rome_relayUnsignedV1` com a mesma assinatura de autorização: o proxy compõe e a submete, paga as taxas Solana e responde com um hash de transação EVM (não uma assinatura Solana). O sintético paga o gas nativo da chain em wei, então quando seu saldo fica menor que `gasLimit x maxFeePerGas`, recarregue primeiro com `rome_composeExternalDepositV1` (uma transação v1 assinada pela carteira; o valor deve ser um múltiplo de 10^12 wei), uma vez por carteira na prática. Qualquer outro erro, como um revert, uma falha de rede ou uma assinatura recusada, é relançado, não reencaminhado. Os detalhes estão em [Chamadas retransmitidas e chamadas longas](/pt-br/guias-do-desenvolvedor/call-evm-from-solana.md#relayed-calls-and-long-calls).

O usuário é o **pagador da taxa** e paga lamports (SOL) da sua carteira Solana para uma chamada direta; o sintético que ele controla mantém os ativos e nunca mantém SOL. Após cada envio pela lane, faça polling do nonce EVM antes do próximo — o indexador fica ligeiramente atrás da confirmação Solana, e a próxima chamada, de outra forma, seria construída sobre um nonce que a chain já gastou.

> **Atômico primeiro, relay em caso de recusa.** O padrão para cada chamada é uma transação EVM executada dentro de uma transação Solana, assinada pela carteira do usuário. O relay é a exceção para uma chamada que não cabe, não uma segunda rota a ser escolhida por preferência: uma chamada direta são dois prompts, uma chamada via relay é um, e a chamada via relay é paga em gas Rome em vez de lamports. Uma jornada em várias etapas (aprovar, depois comprar) consiste em várias chamadas completas, cada uma sua própria transação, não uma execução dividida entre transações.

**Por que o RWA não pode vazar para fora do perímetro.** O ativo reside em estado EVM — seus saldos são armazenamento dentro das contas do programa Rome EVM. Existe **nenhum mint SPL** dele e nada nativo da Solana para mover; os primitivos de movimentação de ativos da lane operam em contas de token SPL, que um saldo de armazenamento EVM não possui. Toda movimentação que a assinatura Solana consegue expressar é uma chamada ao contrato de token, que executa a trava da allowlist — o conjunto com financiamento afirma que uma transferência para um endereço não-whitelisted reverte de forma idêntica, seja assinada por uma chave EVM ou por uma chave Solana. A perna de caixa (wUSDC) é a exceção deliberada: ela é lastreada por SPL e *faz* faz sweep para a própria conta de token do usuário.

***

## Etapa 7 — Saiba quem detém a autoridade após o deploy

`ArcToken.initialize` é executado a partir do construtor do proxy (tx 1) e concede funções a `msg.sender` — o driver do assistente, isto é, o emissor. Ele concede **cinco** funções explicitamente:

```solidity
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
_grantRole(MANAGER_ROLE, msg.sender);
_grantRole(YIELD_MANAGER_ROLE, msg.sender);
_grantRole(YIELD_DISTRIBUTOR_ROLE, msg.sender);
```

Duas consequências que um builder não pode deixar passar:

* **`MINTER_ROLE`, `BURNER_ROLE`, e `UPGRADER_ROLE` NÃO são concedidas na inicialização.** A oferta inicial é cunhada dentro de `inicializar` (um `_mint`, nenhuma função necessária), mas um *burn* `mint` ou `posterior` exige que o emissor primeiro conceda a si mesmo a função. Ele pode, porque detém `DEFAULT_ADMIN_ROLE` (o admin de cada função — nada chama `_setRoleAdmin`, então `DEFAULT_ADMIN_ROLE` administra todas elas). Mas isso é um passo extra deliberado, não um poder ambientado.
* **`UPGRADER_ROLE` nunca é concedido à factory.** Upgrades mediados pela factory (`ArcTokenFactoryV2.upgradeToken`) exigem que a **própria factory** detenha `UPGRADER_ROLE` no token — conceder isso a si mesmo não faz nada. Essa concessão é uma porta de mão única que a factory não pode reverter, então é opcional: se você quiser upgrades mediados pela factory, `grantRole(UPGRADER_ROLE, factory)` explicitamente; caso contrário, o emissor faz upgrade do token diretamente.

O modelo completo de 21 autoridades (11 nomes de funções em seis contratos — o mesmo nome é uma autoridade diferente em cada contrato) está codificado em `arc/roles.ts`. Pergunte `rolesRequiredFor(contract, functionName)` em vez de ler o próprio contrato de uma função, porque quatro funções de vitrine e ambas as funções da factory são bloqueadas por uma autoridade que vive em um *contrato diferente.* .

***

## Etapa 8 — Distribua o rendimento

O token paga rendimento em wUSDC (fixado em `inicializar`, alterável via `setYieldToken` menor que `YIELD_MANAGER_ROLE`). A distribuição percorre o conjunto de titulares:

```solidity
function distributeYieldWithLimit(uint256 totalAmount, uint256 startIndex, uint256 maxHolders)
    external onlyRole(YIELD_DISTRIBUTOR_ROLE) nonReentrant
    returns (uint256 nextIndex, uint256 totalHolders, uint256 amountDistributed);
```

Os mecanismos que importam para conduzi-la corretamente:

* **O total completo `totalAmount` é retirado do chamador apenas na `startIndex == 0` janela** (`safeTransferFrom(msg.sender, this, totalAmount)`). Aprove esse total para o token antes da primeira janela; as janelas posteriores pagam a partir do saldo já mantido.
* **`nextIndex` faz wrap para `0` quando a varredura termina.** Faça loop `distributeYieldWithLimit(total, nextIndex, …)` até `nextIndex` voltar `0`.
* **As cotas dos titulares restritos por rendimento permanecem no contrato do token** — eles são ignorados, não redistribuídos.

> **Em Rome o limite prático é `maxHolders = 1` por transação** — o mesmo limite de 62 contas da etapa 2 — então o rendimento é percorrido um titular por transação (medido em \~318 K de gas por titular). Cada titular whitelisted, EVM ou nativo Solana, recebe pro rata; o script de referência é `measure-yield-batch.ts` e a etapa de rendimento do smoke com financiamento o afirma de ponta a ponta.

```bash
# Forma de referência do USAGE.md: percorra um titular por tx até nextIndex voltar para 0
distributeYieldWithLimit(total, offset, 1)
```

***

## Etapa 9 — Verifique o que você implantou

Nada submete fontes automaticamente em lugar nenhum em Rome, então verificação é uma etapa que você executa. Depois de qualquer deploy — infraestrutura ou um novo token — execute o verificador somente leitura, sem chaves e idempotente (contratos já verificados são ignorados, então rodar de novo após emitir um token verifica apenas os novos):

```bash
cd scripts && CHAIN_ID=<id> npx tsx verify-deployments.ts
```

Ele espera os **três** contratos por token (proxy + ambos os módulos) mais a infraestrutura, e relata o que não conseguiu verificar em vez de falhar um deploy. Fazer isso manualmente uma vez deixou passar sete contratos.

Registrar o ativo no registro Rome trata a verificação como um **gate**, não decoração (`register-asset.ts`): um token conquista seu `apps/arc/<chain>.json` registro — carregando `standard: arc-permissioned-erc20` e um `transferRestriction` nomeando sua trava de allowlist — somente quando todos os três contratos dele estiverem verificados no Sourcify. Esse registro lê a chain para seus fatos (um token implantado pelo assistente não tem receipt comitado) e escreve apenas um checkout de registro local; concluir o PR é trabalho de uma pessoa.

```bash
CHAIN_ID=200010 npx tsx register-asset.ts <tokenAddress>        # verifique + prepare o registro
CHAIN_ID=200010 DRY=1 npx tsx register-asset.ts <tokenAddress>  # prévia somente leitura
```

Para uma prova end-to-end de todo o fluxo — criar, whitelistar, travar, vender em ambas as lanes, distribuir rendimento — execute o smoke com financiamento contra qualquer chain:

```bash
PRIVATE_KEY=… CHAIN_ID=… SOLANA_KEYPAIR=… npx tsx smoke.ts
```

***

## Etapa 10 — Saiba o que fica fora da chain

O modelo de confiança é deliberadamente honesto, e um builder deve representá-lo da mesma forma para seus próprios usuários:

* **A flag da allowlist é sua decisão off-chain.** KYC/AML acontece no seu processo — seus fornecedores, suas regras. A chain registra e impõe apenas o *resultado*, `isWhitelisted(addr)`.
* **O único estado on-chain é um booleano por endereço.** Nenhum PII, nenhum documento, nenhuma alegação de identidade, nenhuma atestação on-chain, nenhuma prova criptográfica de a quem um endereço pertence. Este é o modelo da Arc usado na Plume; ele troca as transferências mais pesadas de um padrão de identidade on-chain (por exemplo, ERC-3643) por mecânicas mais leves e confiança mantida pelo emissor.
* **Recuperação é um poder do emissor, não uma saída de emergência.** Uma carteira perdida — EVM ou Solana — é recuperada colocando na whitelist um endereço substituto e, se necessário, usando mint/burn/upgrade sob seu próprio processo legal (Arc não tem um primitivo de transferência forçada embutido). A custódia da chave do emissor faz parte, portanto, da postura de compliance.
* **Sem relayer próprio da Bloom, sem superfície de custódia.** Os usuários mantêm seu próprio gas em ambas as lanes. Um serviço de fee-payer operado pelo app significaria segurar chaves — uma superfície que um produto RWA não deve adicionar. O único relay na lane Solana é o do proxy da chain, para uma chamada grande demais para uma transação, e o usuário ainda a autoriza com sua própria assinatura e paga por ela em seu próprio gas Rome.

***

## Referência: a ferramenta

Cada script é executado a partir do diretório `scripts/` da ferramenta, com `PRIVATE_KEY`, `CHAIN_ID`, e `REGISTRY_ROOT` exportados.

| Script                          | O que faz                                                                             |
| ------------------------------- | ------------------------------------------------------------------------------------- |
| `deploy-infra.ts`               | Uma vez por chain: os quatro contratos compartilhados, conectados para wUSDC.         |
| `create-token.ts`               | O assistente por partes — oito transações, um token.                                  |
| `rotate-factory.ts`             | Implante uma factory nova após uma mudança de compilador/artefato; reconecte.         |
| `verify-artifact-provenance.ts` | Prove que seu artefato de proxy é aceito pela factory implantada (somente leitura).   |
| `verify-deployments.ts`         | Verifique os três contratos por token + infraestrutura no Sourcify (somente leitura). |
| `register-asset.ts`             | Verifique o gate e, em seguida, prepare o registro de compliance.                     |
| `measure-yield-batch.ts`        | Re-meça o teto de rendimento por tx em uma chain.                                     |
| `smoke.ts`                      | O conjunto end-to-end com financiamento em ambas as lanes.                            |
| `sweep-synthetic-native.ts`     | Recupere gas nativo de uma conta sintética (higiene de teste).                        |

O contexto mais profundo está ao lado deste guia: `docs/ARCHITECTURE.md` (o modelo de app em camadas), `docs/LANES.md` (as duas lanes e a custódia), `docs/COMPLIANCE.md` (o modelo de confiança), e `docs/USAGE.md` (o runbook do operador).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.rome.builders/pt-br/apps-na-rome/bloom/building.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
