> 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/es/guias-para-desarrolladores/integrate-solana-program.md).

# Integrar un programa de Solana

Integra un programa de Solana con Rome EVM: quién es el firmante de Solana, cómo llega el valor a tu programa y vuelve, la regla de un solo recorrido, atómico frente a iterativo y aprovisionamiento de cuentas.

Esta guía está dirigida a un equipo de programa de Solana que quiere que los usuarios de Rome EVM usen su programa — un programa de privacidad, préstamo o bóveda que debería mantener valor para cuentas EVM. Se basa en [Llamar a Solana desde EVM](/es/guias-para-desarrolladores/call-solana-from-evm.md) (la mecánica de los precompilados) y responde a las preguntas que surgen una vez que un programa real está del otro lado: *quién* firma, *cómo* entran y salen los tokens, y *qué* límites moldean el diseño.

El flujo usado a lo largo de todo el texto: una cuenta EVM mueve USDC a tu programa ("shield" o "deposit"), tu programa lo mantiene para ese usuario y luego lo libera de vuelta ("unshield" o "withdraw"). Sustituye los verbos por los tuyos.

## 1. Cada dirección EVM tiene una identidad en Solana

Rome deriva una cuenta de Solana para cada dirección EVM — tanto usuarios como contratos — llamada su **autoridad externa**:

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

Es la propietaria de las cuentas de tokens asociadas a la dirección (es decir, de donde `wUSDC.balanceOf(addr)` lee) y es la clave que firma los CPI hechos en nombre de esa dirección. Tu programa ve una pubkey de Solana de 32 bytes; nunca ve un H160.

**Quién firma lo decide quién llama al precompilado:**

| El precompilado es llamado por                                                             | El firmante de Solana                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Una app **contrato**con un `CALL`                                                          | La **propio del contrato** autoridad externa (`external_auth(contract)`), más cualquier sub-PDA salteada del contrato que solicite                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| Una app **usuario**en una transacción enviada directamente a la dirección del precompilado | La **propia del usuario** autoridad externa                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| Un contrato mediante `DELEGATECALL`                                                        | Se rechaza la autoridad desnuda (`DelegatecallOwnerAuthority`). `invoke` sin firmante, y `invoke_signed` con sub-PDAs salteadas sigue funcionando — pero esas sub-PDAs están en un espacio de nombres de la dirección del contrato que se está ejecutando (`["EXTERNAL_AUTHORITY", caller, running_contract, salt]`), así que `pda_with_salt` no las deriva. De HelperProgram solo pasan los selectores de creación y financiación (`create_ata*`, `create_pda*`, `swap_gas_to_lamports`, `init_spl_mint`, `create_and_init_mint`); están exentos porque su destino queda vinculado al llamador o financiado por el operador, no porque no firmen nada |

La consecuencia es la regla de ERC-20 que ya conoces: **un contrato no puede mover por sí solo los activos de un usuario.** Actúa como su propia identidad, y el usuario le concede derechos primero. Para los tokens que tienen que moverse del lado de Solana, ese permiso es una delegación SPL en la cuenta de tokens del usuario; el `approve` del wrapper es solo una autorización del lado EVM que respetan las transferencias propias del wrapper. Así es como funcionan los wrappers de token de Rome, y así funcionará tu adaptador (sección 3).

Sub-PDAs salteadas: `invoke_signed` toma una lista de `bytes32` salts, y Rome firma con `["EXTERNAL_AUTHORITY", caller_h160, salt]` para cada una (se añade el bump; el llamador es el contrato en una llamada directa). `HelperProgram.pda_with_salt(addr, salt)` devuelve la dirección desde Solidity. Usa un salt por usuario (por ejemplo, la dirección del usuario) cuando tu programa quiera una cuenta propietaria distinta por posición.

Financiación: una PDA de autoridad externa no tiene que existir para ser propietaria de un ATA (`create_ata` es idempotente y el pagador de comisiones de Solana de la transacción cubre la renta). Debe existir y tener lamports solo cuando financie cuentas que tu instrucción crea. `HelperProgram.create_pda(addr)` la crea como un `CreateAccount`de System puro, así que llámala una sola vez; no es idempotente. `swap_gas_to_lamports(n)` abona a la PDA de la dirección `n` lamports desde el pagador de comisiones de Solana de la transacción, y el llamador los paga en gas de Rome: el efecto de cada CPI del track legacy sobre el saldo del pagador de comisiones se añade a la comisión de la transacción y se carga al usuario al precio del gas, de la misma forma en que se cobra la renta por las cuentas que crea un CPI. El paso de aprovisionamiento del carril de Solana se describe en [Llamar a EVM desde Solana](/es/guias-para-desarrolladores/call-evm-from-solana.md); un contrato aprovisiona su propia PDA en su constructor o en la primera llamada.

## 2. Tres formas de mantener la posición de un usuario

**A. Un contrato adaptador (recomendado para un adaptador reutilizable).** Un contrato Solidity único da frente a tu programa. El usuario concede a la autoridad del adaptador una delegación SPL sobre su cuenta de tokens; el adaptador extrae los tokens a una cuenta de tokens que controla, llama a tu programa como sí mismo y indexa la posición del usuario dentro de tu programa mediante una sub-PDA por usuario o mediante un identificador que pasa en los datos de la instrucción. En la salida le indica a tu programa que libere a la cuenta de tokens propia del usuario. El adaptador es la única identidad de Solana que tu programa necesita conocer. La concesión es una delegación SPL, no un ERC-20 `approve`; la sección 3 explica por qué y cuánto le cuesta al usuario.

**B. El usuario como firmante de Solana.** El front end envía una transacción desde la cuenta EVM del usuario **directamente al precompilado CpiProgram** (`to = 0xff…08`, calldata = la ABI codificada `invoke` o `invoke_signed`), así que la propia autoridad externa del usuario firma y tu programa indexa la posición con ella. No hay contrato adaptador ni delegación, pero cada acción es una transacción opaca de calldata en la wallet, y cualquier cosa que el flujo necesite aparte del CPI (el ATA, una transferencia previa) es una transacción separada. Es adecuado para concesiones de una sola vez (un `approve_spl` del usuario a un wrapper) y para programas simples, no para flujos de varios pasos. [Cardo](https://github.com/rome-protocol/cardo) usa esta forma: su front end envía el `invoke` directamente al precompilado desde la wallet del usuario.

**C. Un router sin custodia.** Un contrato que nunca mantiene los tokens del usuario. El usuario concede a la autoridad del router una delegación SPL sobre su propia cuenta de tokens; el router hace CPI a tu programa con esa autoridad como autoridad de transferencia, de modo que los tokens se mueven desde la cuenta de tokens del usuario a la cuenta de tu programa (o de vuelta a la del usuario), y el router no mantiene nada entre llamadas. El router deriva cada cuenta del lado del usuario a partir de `msg.sender`así que el permiso de un usuario no puede apuntarse a la cuenta de otro usuario, y llama a un programa fijo con formas de instrucción fijas en lugar de actuar como un `invoke` passthrough general. El `RomeDexRouter` en [rome-dex](https://github.com/rome-protocol/rome-dex) está escrito así; el carril EVM de rome-dex también ofrece la `invoke` directa cruda de la forma B. Necesita la misma concesión que A, con el mismo coste de un solo delegado (sección 3), y sin paso de extracción.

El resto de esta guía sigue A; C usa la misma concesión y la misma regla de firma.

## 3. Tokens dentro, tokens fuera

USDC en Rome es un único mint SPL visto desde dos lados: el `wUSDC` wrapper ERC-20 del lado EVM y el ATA de la autoridad externa del lado Solana. Para la propia dirección de un usuario, ambos son el mismo saldo: `wUSDC.balanceOf(user)` lee el ATA del usuario. No hay puente ni paso de wrapping en medio.

**El saldo wrapper de un contrato no es una cuenta de tokens que el contrato controle.** La fábrica despliega `SPL_ERC20_cached` para un mint ordinario, y el de Hadrian `wUSDC` es uno. Ese wrapper no puede firmar por un contrato, así que cuando `wUSDC.transferFrom(user, adapter, amount)` o `transfer` envía tokens a un contrato, los tokens SPL se mueven a la **cuenta de tokens de escrow propia del wrapper** (`escrow_ata()`), y el wrapper registra la cantidad por contrato en su almacenamiento. `wUSDC.balanceOf(adapter)` devuelve ese registro, un libro mayor de escrow, no el saldo de una cuenta de tokens propiedad de `external_auth(adapter)`. Tu adaptador no puede entregar esos tokens a tu programa en un CPI; solo pueden salir de nuevo a través del wrapper. Así que un adaptador que se financia a sí mismo con `transferFrom` no tiene nada que pueda gastar del lado de Solana.

La ruta que funciona es una delegación SPL:

* **Concesión.** El usuario envía `approve_spl(adapter, amount, mint)` como una transacción **directamente a HelperProgram** (`to = 0xff…09`), donde `mint` es el `mint_id()`del wrapper. La propia autoridad del usuario firma, y el delegado que fija en la cuenta de tokens del usuario es la autoridad externa del adaptador.
* **Dentro.** El `deposit(amount)` del adaptador extrae con la sobrecarga de delegado `HelperProgram.transfer_spl(srcAta, dstAta, amount, mint)`, con el ATA del usuario como origen y el ATA propio del adaptador (`HelperProgram.ata(address(this), mint)`, creado una vez con `create_ata`) como destino. La autoridad del adaptador firma como delegado. Los tokens ahora están en una cuenta de tokens propiedad de `external_auth(adapter)`que es la cuenta que tu CPI nombra; el firmante y el origen son del propio adaptador, así que no hace falta ningún permiso adicional. No aparecen en `wUSDC.balanceOf(adapter)`.
* **Fuera.** La instrucción withdraw de tu programa transfiere al ATA del **usuario** , `HelperProgram.ata(user, mint)`. La recepción no necesita ninguna firma del usuario, y el saldo es visible de inmediato como `wUSDC.balanceOf(user)`. Si el ATA puede no existir todavía, créalo primero con `HelperProgram.create_ata(user, mint)` (idempotente).

**Una cuenta de tokens tiene un solo delegado.** La concesión anterior reemplaza la propia concesión del wrapper sobre esa cuenta. Hasta que el usuario conceda de nuevo al wrapper, cada `wUSDC` `transfer` o `transferFrom` salida de su dirección revierte con el error SPL `0x4`. Después de cualquier flujo que use esta concesión, llama a `wUSDC.isEnabled(user)`; cuando devuelva `false`, pide al usuario que envíe `approve_spl(wrapper, 2^64-1, mint)` de nuevo al HelperProgram, la misma concesión máxima en torno a la que está construido el wrapper (véase [Una sola vez: concede al wrapper](/es/guias-para-desarrolladores/dual-lane-app.md#one-time-grant-the-wrapper)). Una concesión limitada rompería las `wUSDC` transferencias ordinarias del usuario otra vez una vez que se agote, y `isEnabled` se mantiene `true` mientras quede algo, así que la app no sabría pedirlo de nuevo.

Para comprobar qué wrapper tiene un mint, lee el `wrapper_kind_by_mint(mint)` de la fábrica (la dirección de la fábrica está en el `contracts.json` de la cadena en el [registro](https://github.com/rome-protocol/rome-registry)). `1` es el wrapper almacenado que describe esta sección. `2` es el wrapper de CPI directa que la fábrica despliega para un mint Token-2022 con un transfer hook armado; esta guía no lo cubre. El `tokens.json` enumera la dirección del wrapper y el mint, pero no qué tipo es.

## 4. Un track por contrato y por transacción

Rome tiene dos familias de precompilados que cambian el estado de Solana, y **una transacción usa exactamente una de ellas** — el runtime rechaza una transacción que mezcle llamadas mutantes de ambas, incluso entre contratos.

| Track      | Precompilados                                                                                       | Los efectos llegan                                                                                              | Funciona en ejecución iterativa                                                            |
| ---------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| **Legacy** | `CpiProgram` `0xff…08` (`invoke`, `invoke_signed`), `HelperProgram` `0xff…09`, `Withdraw` `0x42…16` | Inmediatamente, como un CPI real dentro del paso EVM                                                            | **No** — un CPI legacy en una transacción iterativa falla con `CpiProhibitedInIterativeTx` |
| **Cached** | `SplCached` `0xff…05`, `ASplCached` `0xff…06`, `SystemCached` `0xff…04`, `WithdrawCached` `0xff…0b` | Se preparan en una superposición y se confirman como CPI al final de la transacción; un revert EVM los descarta | Sí                                                                                         |

Lo que esto significa para una integración de programa:

* **Llamar a las instrucciones de tu propio programa solo es de track legacy.** El track cached no tiene un `invoke`genérico; cubre transferencias SPL, creación de ATA, operaciones del programa System y retirada de gas.
* Así que el paso que financia al adaptador también debe ser de track legacy si se ejecuta en la misma transacción que el CPI. La `transferFrom` del wrapper cached es una llamada de track cached, así que no puede compartir transacción con tu CPI (y, como muestra la sección 3, solo abonaría un libro mayor de escrow). Extrae con `HelperProgram.transfer_spl(userAta, adapterAta, amount, mint)` en su lugar, después de que el usuario haya convertido al adaptador en el delegado SPL (`approve_spl`), enviada por el usuario directamente a HelperProgram). La extracción y el CPI son ambos de track legacy, así que se ejecutan en una sola transacción.
* **Mantén el wrapper fuera de esa transacción.** No llames a las funciones mutantes del wrapper (`wUSDC.transfer`, `transferFrom`) desde el adaptador en la misma transacción que un CPI legacy. Comprueba `isEnabled(user)` y los saldos desde el front end con `eth_call`.
* **Y la transacción del CPI debe ser atómica.** Ese es el límite bajo el que se sitúa el diseño.

Las lecturas quedan fuera de la regla: `account_info`, `account_data_at`, `account_u64_at`, `account_lamports`, `pdas_batch_derive` y `HelperProgram.user_balance` / `allowance_of` son lecturas de cuentas precargadas (sin CPI), permitidas en cualquiera de los tracks y en ambos modos de ejecución. Pon ahí tus precomprobaciones. Una regla de orden: una vez que una mutación cached se ha disparado en una transacción, las lecturas de track legacy quedan bloqueadas para el resto de ella — primero lee, luego muta.

## 5. Lo atómico es el presupuesto

Una transacción atómica de Rome es una transacción de Solana: aproximadamente **1,4M de unidades de cómputo**, una **lista de cuentas de** 64 direcciones y un **tamaño por cable de 4 KB** (transacciones de Solana v1). El programa de Rome y tu CPI comparten ese presupuesto. Una transferencia del wrapper consume unas 170K CU en Hadrian y tu instrucción añade las suyas; mídelo con `computeUnitsConsumed`del recibo de Solana, no EVM `gasUsed`.

Cuando la emulación decide que una transacción no cabe, Rome la ejecuta **de forma iterativa** a través de varias transacciones de Solana, y un CPI legacy dentro de ella falla entonces. Mantén cada depósito y cada retirada en un solo movimiento de tokens más un CPI a tu programa, y mantén pequeña la Solidity que los rodea. Divide cualquier cosa mayor en dos transacciones de usuario.

Profundidad de CPI: Solana permite 4 niveles y Rome usa uno, así que tu instrucción se ejecuta en el nivel 2 con dos niveles por debajo (tu programa → SPL Token deja uno).

## 6. Aprovisionamiento de cuentas

Tu programa no recibe sus cuentas desde Solidity en tiempo de ejecución. El proxy **emula** cada transacción antes de enviarla, registra cada cuenta de Solana que tocaron los CPI y las coloca en la transacción de Solana. Tu adaptador nombra las cuentas en la `invoke_signed` lista de cuentas; la emulación prueba que se resuelven. De ahí se siguen tres cosas:

* Toda cuenta que toque tu instrucción debe ser derivable a partir de entradas que tenga el adaptador (su propia PDA y sub-PDAs, el ID de tu programa, los mints, la dirección del usuario). `SystemProgram.find_program_address` y `CpiProgram.pdas_batch_derive` hacen las derivaciones en Solidity.
* Una cuenta que todavía no existe (una posición nueva, un ATA nuevo) aun así tiene que estar nombrada en la lista de cuentas; su dirección es lo que llega a la transacción de Solana.
* Todo lo que toca la transacción — incluidas las cuentas propias de Rome para el usuario, el adaptador y el wrapper — debe mantenerse por debajo de 64 direcciones. Un diseño que toque diez mercados en una sola llamada no cabrá.

Para el carril de wallet de Solana, `rome_emulateCallAccounts` expone el mismo descubrimiento a un cliente; el SDK lo usa.

Dos cuentas que un CPI nunca puede nombrar: el pagador de comisiones de Solana que envía la transacción (salvo dentro de una simple instrucción de transferencia de System) y el propio programa de Rome. Se rechaza un CPI de vuelta al programa de Rome.

## 7. Un depósito y una retirada, en Solidity

Un boceto mínimo de un adaptador en el track legacy. El usuario ya ha enviado `approve_spl(adapter, amount, mint)` al HelperProgram (sección 3). `PRIVACY_PROGRAM` es el ID de tu programa; `encodeDeposit` / `encodeWithdraw` construyen los datos de tu instrucción (Borsh, little-endian); los account metas siguen el diseño de tu instrucción.

```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));                 // la propia identidad de Solana del adaptador
        Helper.create_ata(address(this), USDC_MINT);      // y una cuenta USDC que controla
    }

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

    function deposit(uint64 amount) external {
        bytes32 self       = Helper.pda(address(this));                   // firmante: la autoridad del adaptador
        bytes32 adapterAta = Helper.ata(address(this), USDC_MINT);
        bytes32 position   = Helper.pda_with_salt(address(this), _salt(msg.sender)); // sub-PDA por usuario, también firma

        // Extrae desde la cuenta de tokens del usuario. La autoridad del adaptador firma como el SPL
        // delegado que el usuario concedió; esta es una llamada de track legacy, igual que el CPI de abajo.
        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);                          // fuente: controlada por la autoridad del adaptador
        accs[3] = ICrossProgramInvocation.AccountMeta(_vaultFor(position), false, true);                 // la bóveda de tu 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: la propia cuenta del usuario
        // ... misma forma: tu programa mueve `amount` desde la bóveda a userAta, firmado por `position`
        Cpi.invoke_signed(PRIVACY_PROGRAM, accs, encodeWithdraw(amount), salts);
    }
}
```

El adaptador nunca llama al `wUSDC` contrato. La extracción es una llamada de HelperProgram que gasta la delegación del usuario, y los tokens quedan en una cuenta de tokens que `external_auth(adapter)` controla, que es por eso que el CPI puede gastarlos.

Notas sobre el firmante. Rome firma para exactamente dos tipos de cuenta: la autoridad desnuda del contrato llamador (`Helper.pda(address(this))`), que firma sin estar listada en `salts`, y una sub-PDA salteada por cada entrada en `salts`. Cada salt que listes debe aparecer en la lista de cuentas como firmante, o la llamada falla con `no se encontró la cuenta firmante calculada a partir de la semilla proporcionada`. Cualquier otra cuenta marcada como firmante, incluida la propia autoridad del usuario, no obtiene ninguna semilla de Rome, y el runtime de Solana rechaza el CPI. Los derechos del usuario sobre sus tokens provienen de la delegación, nunca de que el adaptador firme como el usuario.

Delegación sin extracción: si tu programa debe gastar directamente desde la cuenta de tokens del usuario, el usuario envía `HelperProgram.approve_spl_raw_delegate(userAta, yourProgramPda, amount, mint, decimals)` directamente a HelperProgram, nombrando la PDA de tu programa como delegado SPL. El puente de Rome usa esto para Wormhole. La regla de un solo delegado de la sección 3 también aplica aquí: la concesión desplaza la del wrapper.

## 8. Pruebas

* Despliega en **Hadrian** (testnet, cadena 200010) primero; las direcciones y el RPC están en [Contract Addresses](/es/referencia/contract-addresses.md) y los [registro](https://github.com/rome-protocol/rome-registry).
* `eth_call` y `eth_estimateGas` ejecuta la misma emulación que usa el proxy para enviar, así que una CPI que falle allí falla en la cadena por la misma razón, y los datos de revert llevan el error subyacente de Solana (`error de llamada no EVM: …` en el registro del programa de Solana).
* Lee el lado de Solana de una transacción EVM procesada con `rome_solanaTxForEvmTx(hash)`; el recibo de Solana es donde viven las CU y los registros de tu programa.
* Una CPI que funciona en `eth_call` pero se rechaza al enviarse normalmente topó con un límite que la emulación informa: el tope de 64 direcciones, el presupuesto atómico de CU (la transacción pasó a iterativa) o la regla de seguimiento.

## 9. Referencia

* [Referencia de precompilados](/es/referencia/precompiles.md) — cada selector de cada precompilado, con su clase de despacho y la regla de delegatecall.
* [Restricciones](/es/conceptos-basicos/constraints.md) — los límites anteriores en una sola tabla.
* [Interop de tokens](/es/conceptos-basicos/token-interop.md) — wrappers, mints canónicos, depósito y retiro.
* Aplicaciones de referencia en los repos públicos: [cardo](https://github.com/rome-protocol/cardo) (el usuario llama directamente al precompilado de CPI, forma B), [rome-dex](https://github.com/rome-protocol/rome-dex) (directo `invoke` más un router sin custodia, forma C), y [aerarium](https://github.com/rome-protocol/aerarium) (una aplicación de préstamos Compound III sobre un mercado compartido; no llama a programas de Solana desde Solidity (sin CPI), por lo que no es un ejemplo de un 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/es/guias-para-desarrolladores/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.
