> 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/guias-do-desenvolvedor/integrate-solana-program.md).

# Integrar um programa Solana

Integre um programa da Solana com a Rome EVM — quem é o signatário da Solana, como o valor chega ao seu programa e retorna, a regra do caminho único, atômico vs. iterativo e provisionamento de contas.

Este guia é para uma equipe de programa da Solana que quer que usuários do Rome EVM usem seu programa — um programa de privacidade, empréstimo ou cofre que deve manter valor para contas EVM. Ele se baseia em [Chamar Solana a partir da EVM](/pt-br/guias-do-desenvolvedor/call-solana-from-evm.md) (a mecânica de precompile) e responde às perguntas que surgem quando um programa real está do outro lado: *quem* assina, *como* os tokens entram e saem, e *quais* limites moldam o design.

O fluxo usado ao longo do guia: uma conta EVM move USDC para dentro do seu programa ("shield" ou "deposit"), seu programa o mantém para esse usuário e, depois, o libera de volta ("unshield" ou "withdraw"). Substitua os verbos pelos seus.

## 1. Todo endereço EVM tem uma identidade Solana

Rome deriva uma conta Solana para cada endereço EVM — usuários e contratos igualmente — chamada de sua **autoridade externa**:

```
external_auth(addr) = find_program_address(["EXTERNAL_AUTHORITY", addr_h160], rome_evm_program_id)
```

Ela controla as contas de tokens associadas desse endereço (é de onde `wUSDC.balanceOf(addr)` lê) e é a chave que assina as CPIs feitas em nome desse endereço. Seu programa vê uma pubkey Solana de 32 bytes; ele nunca vê um H160.

**Quem assina é decidido por quem chama o precompile:**

| O precompile é chamado por                                                         | O signatário Solana                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Um app **contrato**, com uma normal `CALL`                                         | Os **própria do contrato** autoridade externa (`external_auth(contract)`), além de quaisquer sub-PDAs com salt do contrato que ele solicitar                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| Um app **usuário**, em uma transação enviada diretamente ao endereço do precompile | Os **própria do usuário** autoridade externa                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| Um contrato via `DELEGATECALL`                                                     | A autoridade nua é recusada (`DelegatecallOwnerAuthority`). `invoke` sem um signatário, e `invoke_signed` com sub-PDAs com salt, continuam funcionando — mas essas sub-PDAs são namespaceadas pelo endereço do contrato em execução (`["EXTERNAL_AUTHORITY", caller, running_contract, salt]`), então `pda_with_salt` não as deriva. Do HelperProgram, apenas os seletores de criação e funding passam (`create_ata*`, `create_pda*`, `swap_gas_to_lamports`, `init_spl_mint`, `create_and_init_mint`); eles são isentos porque o alvo deles é vinculado ao chamador ou financiado pelo operador, não porque não assinam nada |

A consequência é a regra do ERC-20 que você já conhece: **um contrato não pode mover os ativos de um usuário por conta própria.** Ele age como sua própria identidade, e o usuário lhe concede direitos primeiro. Para tokens que precisam se mover no lado da Solana, essa concessão é uma delegação SPL na conta de token do usuário; o `approve` do wrapper é apenas uma autorização no lado EVM que as próprias transferências do wrapper respeitam. É assim que os próprios wrappers de token de Rome funcionam, e é assim que seu adapter funcionará (seção 3).

Sub-PDAs com salt: `invoke_signed` recebe uma lista de `bytes32` salts, e Rome assina com `["EXTERNAL_AUTHORITY", caller_h160, salt]` para cada uma (bump anexado; o chamador é o contrato em uma chamada direta). `HelperProgram.pda_with_salt(addr, salt)` retorna o endereço a partir do Solidity. Use um salt por usuário (por exemplo, o endereço do usuário) quando seu programa quiser uma conta de proprietário distinta por posição.

Funding: uma PDA de autoridade externa não precisa existir para ser dona de uma ATA (`create_ata` é idempotente e o pagador de taxas Solana da transação cobre o rent). Ela deve existir e reter lamports apenas quando financiar contas que sua instrução cria. `HelperProgram.create_pda(addr)` a cria como um simples System `CreateAccount`, então chame-a uma vez; ela não é idempotente. `swap_gas_to_lamports(n)` credita a PDA do endereço com `n` lamports do pagador de taxas Solana da transação, e o chamador paga por eles em gas de Rome: o efeito de toda CPI do track legacy sobre o saldo do pagador de taxas é adicionado à taxa da transação e cobrado do usuário ao preço do gas, da mesma forma que o rent para contas que uma CPI cria é cobrado. A etapa de provisioning do lane Solana é descrita em [Chamar EVM a partir da Solana](/pt-br/guias-do-desenvolvedor/call-evm-from-solana.md); um contrato provisiona sua própria PDA em seu construtor ou na primeira chamada.

## 2. Três maneiras de manter a posição de um usuário

**A. Um contrato adapter (recomendado para um adapter reutilizável).** Um contrato Solidity faz a interface com seu programa. O usuário concede à autoridade do adapter uma delegação SPL na sua conta de token; o adapter puxa os tokens para uma conta de token que ele possui, chama seu programa como ele mesmo e identifica a posição do usuário dentro do seu programa por uma sub-PDA por usuário ou por um identificador que ele passa nos dados da instrução. Na saída, ele diz ao seu programa para liberar para a própria conta de token do usuário. O adapter é a única identidade Solana que seu programa precisa conhecer. A concessão é uma delegação SPL, não um ERC-20 `approve`; a seção 3 explica por quê e o que isso custa ao usuário.

**B. O usuário como signatário Solana.** O front-end envia uma transação da conta EVM do usuário **diretamente para o precompile CpiProgram** (`to = 0xff…08`, calldata = o ABI-encoded `invoke` ou `invoke_signed`), então a própria autoridade externa do usuário assina e seu programa identifica a posição por ela. Sem contrato adapter e sem delegação, mas cada ação é uma transação opaca de calldata na wallet, e tudo o que o fluxo precisar além da CPI (a ATA, uma transferência anterior) é uma transação separada. É uma opção para concessões únicas (a `approve_spl` do usuário para um wrapper) e para programas simples, não para fluxos em várias etapas. [Cardo](https://github.com/rome-protocol/cardo) usa essa forma: seu front-end envia a `invoke` diretamente para o precompile a partir da wallet do usuário.

**C. Um router sem custódia.** Um contrato que nunca mantém os tokens do usuário. O usuário concede à autoridade do router uma delegação SPL na sua própria conta de token; o router faz CPIs no seu programa com essa autoridade como autoridade de transferência, então os tokens se movem da conta de token do usuário para a conta do seu programa (ou de volta para a do usuário), e o router não mantém nada entre chamadas. O router deriva toda conta do lado do usuário a partir de `msg.sender`, então a concessão de um usuário não pode ser apontada para a conta de outro usuário, e ele chama um programa fixo com formatos de instrução fixos em vez de agir como um `invoke` passthrough geral. O `RomeDexRouter` em [rome-dex](https://github.com/rome-protocol/rome-dex) é escrito assim; o lane EVM do rome-dex também oferece o `invoke` direto bruto de forma B. Ele precisa da mesma concessão que A, com o mesmo custo de um delegado (seção 3), e sem etapa de pull.

O restante deste guia segue A; C usa a mesma concessão e a mesma regra de assinatura.

## 3. Tokens entrando, tokens saindo

USDC no Rome é uma única mint SPL vista de dois lados: o `wUSDC` wrapper ERC-20 no lado EVM e a ATA da autoridade externa no lado Solana. Para o próprio endereço do usuário, os dois são o mesmo saldo: `wUSDC.balanceOf(user)` lê a ATA do usuário. Não há ponte nem etapa de wrapping no meio.

**O saldo do wrapper de um contrato não é uma conta de token que o contrato controla.** A fábrica implanta `SPL_ERC20_cached` para uma mint comum, e o de Hadrian `wUSDC` é um deles. Esse wrapper não pode assinar por um contrato, então quando `wUSDC.transferFrom(user, adapter, amount)` ou `transfer` envia tokens para um contrato, os tokens SPL se movem para a **própria conta de token de escrow do wrapper** (`escrow_ata()`), e o wrapper registra o valor por contrato em seu armazenamento. `wUSDC.balanceOf(adapter)` retorna esse registro, um ledger de escrow, não o saldo de uma conta de token pertencente a `external_auth(adapter)`. Seu adapter não pode entregar esses tokens ao seu programa em uma CPI; eles só podem sair novamente pelo wrapper. Então um adapter que se financia com `transferFrom` não tem nada que possa gastar no lado Solana.

O caminho que funciona é uma delegação SPL:

* **Concessão.** O usuário envia `approve_spl(adapter, amount, mint)` como uma transação **diretamente para o HelperProgram** (`to = 0xff…09`), onde `mint` é o `mint_id()`do wrapper. A própria autoridade do usuário assina, e o delegate que ela define na conta de token do usuário é a autoridade externa do adapter.
* **Entrando.** A `deposit(amount)` do adapter faz o pull com a sobrecarga de delegate `HelperProgram.transfer_spl(srcAta, dstAta, amount, mint)`, com a ATA do usuário como origem e a própria ATA do adapter (`HelperProgram.ata(address(this), mint)`, criada uma vez com `create_ata`) como destino. A autoridade do adapter assina como delegate. Os tokens estão agora em uma conta de token pertencente a `external_auth(adapter)`, que é a conta que sua CPI nomeia; o signatário e a origem são os do próprio adapter, então nenhuma permissão adicional é necessária. Eles não aparecem em `wUSDC.balanceOf(adapter)`.
* **Saindo.** A instrução de withdraw do seu programa transfere para a ATA do **usuário** , `HelperProgram.ata(user, mint)`. Receber não exige assinatura do usuário, e o saldo fica imediatamente visível como `wUSDC.balanceOf(user)`. Se a ATA ainda não existir, crie-a primeiro com `HelperProgram.create_ata(user, mint)` (idempotente).

**Uma conta de token tem um delegate.** A concessão acima substitui a própria concessão do wrapper sobre essa conta. Até que o usuário conceda ao wrapper novamente, todo `wUSDC` `transfer` ou `transferFrom` saída do seu endereço reverte com o erro SPL `0x4`. Depois de qualquer fluxo que use essa concessão, chame `wUSDC.isEnabled(user)`; quando retornar `false`, peça ao usuário para enviar `approve_spl(wrapper, 2^64-1, mint)` para o HelperProgram novamente, a mesma concessão máxima para a qual o wrapper foi construído (veja [Uma única vez: conceda ao wrapper](/pt-br/guias-do-desenvolvedor/dual-lane-app.md#one-time-grant-the-wrapper)). Uma concessão limitada quebraria as transferências comuns do usuário novamente assim que ficasse baixa, e `wUSDC` isEnabled `permanece` true `enquanto qualquer parte dela permanecer, então o app não saberia que precisa pedir de novo.` .

Para verificar qual wrapper uma mint tem, leia o `wrapper_kind_by_mint(mint)` (o endereço da factory está no `contracts.json` da cadeia em [registro](https://github.com/rome-protocol/rome-registry)). `1` é o wrapper em cache que esta seção descreve. `2` é o wrapper de CPI direta que a factory implanta para uma mint Token-2022 com um transfer hook armado; este guia não o cobre. O `tokens.json` lista o endereço do wrapper e a mint, mas não qual tipo ele é.

## 4. Um track por contrato, e por transação

Rome tem duas famílias de precompiles que alteram o estado da Solana, e **uma transação usa exatamente uma delas** — o runtime recusa uma transação que mistura chamadas mutáveis de ambas, mesmo entre contratos.

| Track      | Precompiles                                                                                         | Os efeitos chegam                                                                                               | Funciona em execução iterativa                                                             |
| ---------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| **Legacy** | `CpiProgram` `0xff…08` (`invoke`, `invoke_signed`), `HelperProgram` `0xff…09`, `Withdraw` `0x42…16` | Imediatamente, como uma CPI real dentro da etapa EVM                                                            | **Não** — uma CPI legacy em uma transação iterativa falha com `CpiProhibitedInIterativeTx` |
| **Cached** | `SplCached` `0xff…05`, `ASplCached` `0xff…06`, `SystemCached` `0xff…04`, `WithdrawCached` `0xff…0b` | Ficam em estágio em uma overlay e são comprometidos como CPIs no fim da transação; um revert do EVM os descarta | Sim                                                                                        |

O que isso significa para uma integração de programa:

* **Chamar as instruções do seu próprio programa é somente do track legacy.** O track cached não tem um `invoke`genérico; ele cobre transferências SPL, criação de ATA, operações do sistema e saque de gas.
* Então a etapa que financia o adapter também precisa ser do track legacy se ela rodar na mesma transação que a CPI. A `transferFrom` do wrapper cached é uma chamada do track cached, então ela não pode compartilhar uma transação com sua CPI (e, como a seção 3 mostra, ela só creditaria um ledger de escrow). Faça o pull com `HelperProgram.transfer_spl(userAta, adapterAta, amount, mint)` em vez disso, depois que o usuário tiver feito do adapter o delegate SPL (`approve_spl`, enviado diretamente pelo usuário ao HelperProgram). O pull e a CPI são ambos do track legacy, então rodam em uma única transação.
* **Mantenha o wrapper fora dessa transação.** Não chame as funções mutáveis do wrapper (`wUSDC.transfer`, `transferFrom`) do adapter na mesma transação que uma CPI legacy. Verifique `isEnabled(user)` e os saldos no front-end com `eth_call`.
* **E a transação da CPI precisa ser atômica.** Esse é o limite sob o qual o design se encaixa.

Leituras ficam fora da regra: `account_info`, `account_data_at`, `account_u64_at`, `account_lamports`, `pdas_batch_derive` e `HelperProgram.user_balance` / `allowance_of` são leituras de contas pré-carregadas (sem CPI), permitidas em qualquer track e em ambos os modos de execução. Coloque seus pré-checks nelas. Uma regra de ordenação: uma vez que uma mutação cached tenha sido acionada em uma transação, leituras do track legacy ficam bloqueadas pelo restante dela — leia primeiro, depois mutue.

## 5. Atomicidade é o orçamento

Uma transação atômica do Rome é uma transação Solana: cerca de **1,4 milhão de unidades de compute**, uma lista de contas de **64 endereços** e um tamanho de wire de **4 KB** (transações Solana v1). O programa Rome e sua CPI compartilham esse orçamento. Uma transferência de wrapper roda em cerca de 170 mil CU no Hadrian e sua instrução adiciona o próprio custo; meça com o `computeUnitsConsumed`do receipt da Solana, não do EVM `gasUsed`.

Quando a emulação decide que uma transação não cabe, Rome a executa **iterativamente** em várias transações Solana, e então uma CPI legacy dentro dela falha. Mantenha cada depósito e saque em um único movimento de token mais uma CPI para o seu programa, e mantenha o Solidity ao redor pequeno. Divida qualquer coisa maior em duas transações do usuário.

Profundidade da CPI: a Solana permite 4 níveis e Rome usa um, então sua instrução roda no nível 2 com dois níveis abaixo dela (seu programa → SPL Token deixa um).

## 6. Provisionamento de contas

Seu programa não recebe suas contas do Solidity em tempo de execução. O proxy **emula** cada transação antes de enviá-la, registra cada conta Solana que as CPIs tocaram e as coloca na transação Solana. Seu adapter nomeia as contas na `invoke_signed` lista de contas; a emulação prova que elas resolvem. Três coisas decorrem disso:

* Toda conta que sua instrução toca deve ser derivável de entradas que o adapter possui (sua própria PDA e sub-PDAs, o ID do seu programa, mints, o endereço do usuário). `SystemProgram.find_program_address` e `CpiProgram.pdas_batch_derive` fazem as derivações em Solidity.
* Uma conta que ainda não existe (uma posição nova, uma ATA nova) ainda precisa ser nomeada na lista de contas; seu endereço é o que chega à transação Solana.
* Tudo o que a transação toca — incluindo as próprias contas de Rome para o usuário, o adapter e o wrapper — precisa ficar abaixo de 64 endereços. Um design que toca dez mercados em uma única chamada não vai caber.

Para o lane da wallet Solana, `rome_emulateCallAccounts` expõe a mesma descoberta para um cliente; o SDK a usa.

Duas contas que uma CPI nunca pode nomear: o pagador de taxas Solana que submete a transação (exceto dentro de uma simples instrução de transferência do System) e o próprio programa Rome. Uma CPI de volta ao programa Rome é recusada.

## 7. Um depósito e um saque, em Solidity

Um esboço minimalista de um adapter no track legacy. O usuário já enviou `approve_spl(adapter, amount, mint)` para o HelperProgram (seção 3). `PRIVACY_PROGRAM` é o ID do seu programa; `encodeDeposit` / `encodeWithdraw` constroem os dados da sua instrução (Borsh, little-endian); os account metas seguem o layout da sua instrução.

```solidity
import {ICrossProgramInvocation, IHelperProgram}
    from "@rome-protocol/rome-solidity/contracts/interface.sol";

contract PrivacyAdapter {
    ICrossProgramInvocation constant Cpi    = ICrossProgramInvocation(0xFF00000000000000000000000000000000000008);
    IHelperProgram          constant Helper = IHelperProgram(0xFF00000000000000000000000000000000000009);
    bytes32 constant SPL_TOKEN = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9; // TokenkegQ...

    bytes32 immutable PRIVACY_PROGRAM;
    bytes32 immutable USDC_MINT;

    constructor(bytes32 program, bytes32 mint) {
        PRIVACY_PROGRAM = program; USDC_MINT = mint;
        Helper.create_pda(address(this));                 // a própria identidade Solana do adapter
        Helper.create_ata(address(this), USDC_MINT);      // e uma conta de USDC que ele possui
    }

    function _salt(address user) internal pure returns (bytes32) { return bytes32(uint256(uint160(user))); }

    function deposit(uint64 amount) external {
        bytes32 self       = Helper.pda(address(this));                   // signatário: a autoridade do adapter
        bytes32 adapterAta = Helper.ata(address(this), USDC_MINT);
        bytes32 position   = Helper.pda_with_salt(address(this), _salt(msg.sender)); // sub-PDA por usuário, também assina

        // Faz o pull da conta de token do usuário. A autoridade do adapter assina como SPL
        // delegate que o usuário concedeu; esta é uma chamada do track legacy, como a CPI abaixo.
        Helper.transfer_spl(Helper.ata(msg.sender, USDC_MINT), adapterAta, amount, USDC_MINT);

        ICrossProgramInvocation.AccountMeta[] memory accs = new ICrossProgramInvocation.AccountMeta[](5);
        accs[0] = ICrossProgramInvocation.AccountMeta(self,       true,  true);
        accs[1] = ICrossProgramInvocation.AccountMeta(position,   true,  true);
        accs[2] = ICrossProgramInvocation.AccountMeta(adapterAta, false, true);                          // origem: pertencente à autoridade do adapter
        accs[3] = ICrossProgramInvocation.AccountMeta(_vaultFor(position), false, true);                 // o cofre do seu programa
        accs[4] = ICrossProgramInvocation.AccountMeta(SPL_TOKEN, false, false);

        bytes32[] memory salts = new bytes32[](1);
        salts[0] = _salt(msg.sender);
        Cpi.invoke_signed(PRIVACY_PROGRAM, accs, encodeDeposit(amount), salts);
    }

    function withdraw(uint64 amount) external {
        bytes32 position = Helper.pda_with_salt(address(this), _salt(msg.sender));
        bytes32 userAta  = Helper.ata(msg.sender, USDC_MINT);            // destino: a própria conta do usuário
        // ... mesma forma: seu programa move `amount` do vault para userAta, assinado por `position`
        Cpi.invoke_signed(PRIVACY_PROGRAM, accs, encodeWithdraw(amount), salts);
    }
}
```

O adapter nunca chama o `wUSDC` contrato. O pull é uma chamada do HelperProgram que gasta a delegação do usuário, e os tokens ficam em uma conta de token que `external_auth(adapter)` possui, é por isso que a CPI pode gastá-los.

Notas sobre o signatário. Rome assina para exatamente dois tipos de conta: a autoridade nua do contrato chamador (`Helper.pda(address(this))`), que assina sem ser listada em `salts`, e uma sub-PDA com salt por entrada em `salts`. Todo salt que você listar deve aparecer na lista de contas como signatário, ou a chamada falha com `a conta signatária calculada a partir da seed fornecida não foi encontrada`. Qualquer outra conta marcada como signatária, incluindo a própria autoridade do usuário, não recebe seed de Rome, e o runtime da Solana recusa a CPI. Os direitos do usuário sobre seus tokens vêm da delegação, nunca do adapter assinando como o usuário.

Delegação sem pull: se seu programa deve gastar diretamente da conta de token do usuário, o usuário envia `HelperProgram.approve_spl_raw_delegate(userAta, yourProgramPda, amount, mint, decimals)` diretamente para o HelperProgram, nomeando a PDA do seu programa como delegate SPL. A bridge de Rome usa isso para Wormhole. A regra de um delegate da seção 3 também se aplica aqui: a concessão substitui a do wrapper.

## 8. Testes

* Faça o deploy em **Hadrian** (testnet, chain 200010) primeiro; os endereços e o RPC estão em [referência de Endereços de Contrato](/pt-br/referencia/contract-addresses.md) e os [registro](https://github.com/rome-protocol/rome-registry).
* `eth_call` e `eth_estimateGas` execute a mesma emulação que o proxy usa para enviar, então uma CPI que falha ali falha na chain pelo mesmo motivo, e os dados do revert carregam o erro subjacente da Solana (`erro de chamada não-EVM: …` no log do programa Solana).
* Leia o lado Solana de uma transação EVM confirmada com `rome_solanaTxForEvmTx(hash)`; o recibo da Solana é onde vivem o CU e os logs do seu programa.
* Uma CPI que funciona em `eth_call` mas é recusada quando enviada geralmente acionou um limite que a emulação relata: o limite de 64 endereços, o orçamento atômico de CU (a transação entrou em modo iterativo) ou a regra de rastreamento.

## 9. Referência

* [Referência de precompilados](/pt-br/referencia/precompiles.md) — cada seletor em cada precompile, com sua classe de dispatch e a regra de delegatecall.
* [Restrições](/pt-br/conceitos-principais/constraints.md) — os limites acima em uma tabela.
* [Interoperabilidade de tokens](/pt-br/conceitos-principais/token-interop.md) — wrappers, mints canônicos, depósito e saque.
* Aplicativos de referência nos repositórios públicos: [cardo](https://github.com/rome-protocol/cardo) (o usuário chama a precompile de CPI diretamente, forma B), [rome-dex](https://github.com/rome-protocol/rome-dex) (direto `invoke` mais um roteador sem custódia, forma C), e [aerarium](https://github.com/rome-protocol/aerarium) (um app de empréstimo Compound III sobre um mercado compartilhado; ele não chama programas Solana a partir de Solidity (sem CPI), então não é um exemplo de um adaptador).


---

# 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/guias-do-desenvolvedor/integrate-solana-program.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.
