> 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/ru/rukovodstva-dlya-razrabotchikov/integrate-solana-program.md).

# Интеграция программы Solana

Интеграция программы Solana с Rome EVM — кто является подписантом Solana, как значение попадает в вашу программу и возвращается обратно, правило единого маршрута, атомарный и итеративный режимы, а также выделение аккаунтов.

Это руководство предназначено для команды программы Solana, которая хочет, чтобы пользователи Rome EVM использовали их программу — программу конфиденциальности, кредитования или хранилища, которая должна хранить ценность для аккаунтов EVM. Оно основано на [Вызов Solana из EVM](/ru/rukovodstva-dlya-razrabotchikov/call-solana-from-evm.md) (механике прекомпиляций) и отвечает на вопросы, которые возникают, когда реальная программа оказывается по другую сторону: *кто* подписывает, *как* токены входят и выходят, и *какие* ограничения формируют дизайн.

Используемый на протяжении всего документа поток: адрес EVM переводит USDC в вашу программу ("shield" или "deposit"), ваша программа хранит его для этого пользователя, а затем возвращает обратно ("unshield" или "withdraw"). Замените эти глаголы на свои собственные.

## 1. У каждого адреса EVM есть одна идентичность Solana

Rome выводит для каждого адреса EVM — как для пользователей, так и для контрактов — аккаунт Solana, называемый его **внешним полномочием**:

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

Он владеет связанными токен-аккаунтами этого адреса (то есть именно оттуда `wUSDC.balanceOf(addr)` читается) и является ключом, который подписывает CPI от имени этого адреса. Ваша программа видит 32-байтовый публичный ключ Solana; H160 она никогда не видит.

**Кто подписывает, определяется тем, кто вызывает прекомпиляцию:**

| Прекомпиляция вызывается                                                                 | Подписант Solana                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Приложение **контрактом**, при обычном `CALL`                                            | Названия **собственном** внешнем полномочии (`external_auth(contract)`), а также любыми salted sub-PDA контракта, которые он запрашивает                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| Приложение **пользователем**, в транзакции, отправленной напрямую на адрес прекомпиляции | Названия **собственным полномочием пользователя** внешним полномочием                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| Контрактом через `DELEGATECALL`                                                          | Голое полномочие отклоняется (`DelegatecallOwnerAuthority`). `invoke` без подписанта, а `invoke_signed` с salted sub-PDA по-прежнему выполняются — но эти sub-PDA именуются пространством адреса выполняющегося контракта (`["EXTERNAL_AUTHORITY", caller, running_contract, salt]`), поэтому `pda_with_salt` не выводит их. Из HelperProgram проходят только селекторы создания и пополнения (`create_ata*`, `create_pda*`, `swap_gas_to_lamports`, `init_spl_mint`, `create_and_init_mint` ); они освобождены от этого, потому что их назначение привязано к вызывающей стороне или финансируется оператором, а не потому, что они вообще ничего не подписывают |

Следствие — это правило ERC-20, которое вам уже известно: **контракт не может сам по себе перемещать активы пользователя.** Он действует как собственная идентичность, а пользователь сначала предоставляет ему права. Для токенов, которые должны перемещаться на стороне Solana, это предоставление представляет собой делегирование SPL на токен-аккаунте пользователя; разрешение ERC-20 обёртки `approve` — это лишь allowance на стороне EVM, которое соблюдают собственные переводы обёртки. Именно так работают собственные обёртки токенов Rome, и именно так будет работать ваш адаптер (раздел 3).

Суб-PDA с солью: `invoke_signed` принимает список `bytes32` солей, и Rome подписывает `["EXTERNAL_AUTHORITY", caller_h160, salt]` для каждой из них (bump добавляется; вызывающий — это контракт при прямом вызове). `HelperProgram.pda_with_salt(addr, salt)` возвращает адрес из Solidity. Используйте одну соль на пользователя (например, адрес пользователя), когда вашей программе нужен отдельный аккаунт-владелец для каждой позиции.

Финансирование: PDA внешнего полномочия не обязан существовать, чтобы владеть ATA (`create_ata` идемпотентен, а плательщик комиссии Solana в транзакции покрывает rent). Он должен существовать и хранить lamports только тогда, когда он финансирует аккаунты, создаваемые вашей инструкцией. `HelperProgram.create_pda(addr)` создаёт его как обычный вызов System `CreateAccount`, так что вызовите его один раз; он не идемпотентен. `swap_gas_to_lamports(n)` зачисляет на PDA этого адреса `n` lamports из плательщика комиссии Solana в транзакции, а вызывающий оплачивает их в gas Rome: эффект каждого legacy-track CPI на баланс плательщика комиссии добавляется к комиссии транзакции и списывается с пользователя по цене газа, так же, как взимается rent за аккаунты, создаваемые CPI. Шаг подготовки в полосе Solana описан в [Вызов EVM из Solana](/ru/rukovodstva-dlya-razrabotchikov/call-evm-from-solana.md); контракт подготавливает собственный PDA в своём конструкторе или при первом вызове.

## 2. Три способа хранить позицию пользователя

**A. Контракт-адаптер (рекомендуется для переиспользуемого адаптера).** Один контракт на Solidity фронтирует вашу программу. Пользователь предоставляет полномочию адаптера SPL-делегирование на своём токен-аккаунте; адаптер вытягивает токены на токен-аккаунт, которым он владеет, вызывает вашу программу от своего имени и ключует позицию пользователя внутри вашей программы с помощью суб-PDA на пользователя или идентификатора, который он передаёт в данных инструкции. На выходе он сообщает вашей программе, чтобы та выпустила средства на собственный токен-аккаунт пользователя. Адаптер — это единственная идентичность Solana, которую вашей программе нужно знать. Это предоставление — SPL-делегирование, а не ERC-20 `approve`; раздел 3 объясняет, почему и сколько это стоит пользователю.

**B. Пользователь как подписант Solana.** Фронтенд отправляет транзакцию из EVM-аккаунта пользователя **напрямую в прекомпиляцию CpiProgram** (`to = 0xff…08`, calldata = ABI-encoded `invoke` или `invoke_signed`), поэтому собственное внешнее полномочие пользователя подписывает, а ваша программа ключует позицию через него. Никакого контракта-адаптера и никакого делегирования, но каждое действие — это непрозрачная транзакция calldata в кошельке, а всё, что потоку нужно помимо CPI (ATA, предварительный перевод), — отдельная транзакция. Это подходит для одноразовых разрешений ( `approve_spl` approve пользователя обёртке) и для простых программ, но не для многошаговых потоков. [Cardo](https://github.com/rome-protocol/cardo) использует именно эту схему: его фронтенд отправляет `invoke` напрямую в прекомпиляцию из кошелька пользователя.

**C. Маршрутизатор без хранения средств.** Контракт, который никогда не хранит токены пользователя. Пользователь предоставляет полномочию маршрутизатора SPL-делегирование на своём собственном токен-аккаунте; маршрутизатор выполняет CPI в вашу программу, используя это полномочие как authority перевода, так что токены перемещаются с токен-аккаунта пользователя на аккаунт вашей программы (или обратно пользователю), а маршрутизатор ничего не держит между вызовами. Маршрутизатор выводит каждый пользовательский аккаунт из `msg.sender`, поэтому грант одного пользователя нельзя направить на аккаунт другого пользователя, и он вызывает одну фиксированную программу с фиксированными формами инструкций, а не выступает как общий `invoke` проксирующий канал.  `RomeDexRouter` из [rome-dex](https://github.com/rome-protocol/rome-dex) написан именно так; EVM-полоса rome-dex также предлагает прямой сырой `invoke` вариант формы B. Ему нужен тот же grant, что и A, с той же стоимостью одного делегирования (раздел 3), и без шага извлечения.

Остальная часть этого руководства следует варианту A; C использует тот же grant и то же правило подписания.

## 3. Токены на вход, токены на выход

USDC в Rome — это один SPL-mint, видимый с двух сторон: `wUSDC` ERC-20-обёртка на стороне EVM и ATA внешнего полномочия на стороне Solana. Для собственного адреса пользователя это один и тот же баланс: `wUSDC.balanceOf(user)` читается из ATA пользователя. Посредине нет ни моста, ни шага обёртывания.

**Баланс обёртки контракта — это не токен-аккаунт, которым контракт управляет.** Фабрика разворачивает `SPL_ERC20_cached` для обычного mint, а обёртка Hadrian's `wUSDC` — одна из них. Эта обёртка не может подписывать за контракт, поэтому когда `wUSDC.transferFrom(user, adapter, amount)` или `transfer` отправляет токены на контракт, SPL-токены перемещаются на **собственный эскроу-токен-аккаунт обёртки** (`escrow_ata()`), а обёртка записывает сумму по контракту в своём хранилище. `wUSDC.balanceOf(adapter)` возвращает эту запись, эскроу-реестр, а не баланс токен-аккаунта, которым владеет `external_auth(adapter)`. Ваш адаптер не может передать эти токены вашей программе в CPI; они могут уйти только через обёртку снова. Поэтому адаптер, который пополняет себя с помощью `transferFrom` не имеет ничего, что он мог бы потратить на стороне Solana.

Рабочий путь — это SPL-делегирование:

* **Предоставление.** Пользователь отправляет `approve_spl(adapter, amount, mint)` как транзакцию **прямо в HelperProgram** (`to = 0xff…09`), где `mint` является `mint_id()`. Собственное полномочие пользователя подписывает, а делегат, который оно устанавливает на токен-аккаунте пользователя, — это внешнее полномочие адаптера.
* **В.** deposit(amount) `адаптера` извлекает с помощью перегрузки delegate `HelperProgram.transfer_spl(srcAta, dstAta, amount, mint)`, где источник — ATA пользователя, а назначение — собственный ATA адаптера (`HelperProgram.ata(address(this), mint)`, созданный один раз с помощью `create_ata`) в качестве назначения. Полномочие адаптера подписывает как делегат. Теперь токены находятся на токен-аккаунте, которым владеет `external_auth(adapter)`, который и является аккаунтом, названным в вашем CPI; подписант и источник — собственные аккаунты адаптера, так что дальнейшее разрешение не нужно. Они не появляются в `wUSDC.balanceOf(adapter)`.
* **Вывод.** Инструкция вывода вашей программы переводит на **ATA пользователя,** HelperProgram.ata(user, mint) `. Получение не требует подписи пользователя, и баланс немедленно виден как`. Если ATA ещё не существует, сначала создайте его с помощью `wUSDC.balanceOf(user)`. `HelperProgram.create_ata(user, mint)` (идемпотентно).

**У токен-аккаунта один делегат.** Указанное выше предоставление заменяет собственное предоставление обёртки на этом аккаунте. Пока пользователь не предоставит обёртке права снова, каждый `wUSDC` `transfer` или `transferFrom` вывод со своего адреса откатывается с ошибкой SPL `0x4`. После любого потока, который использует это предоставление, вызывайте `wUSDC.isEnabled(user)`; когда он возвращает `false`, попросите пользователя отправить `approve_spl(wrapper, 2^64-1, mint)` в HelperProgram снова, то же максимальное предоставление, вокруг которого построена обёртка (см. [Однократно: предоставьте обёртке](/ru/rukovodstva-dlya-razrabotchikov/dual-lane-app.md#one-time-grant-the-wrapper)). Ограниченное предоставление снова сломает обычные `wUSDC` переводы пользователя, когда оно закончится, а `isEnabled` останется `true` , пока какая-либо его часть ещё остаётся, так что приложение не поймёт, что нужно попросить снова.

Чтобы проверить, какая обёртка соответствует mint, прочитайте `wrapper_kind_by_mint(mint)` (адрес фабрики находится в цепочке `contracts.json` в [реестре](https://github.com/rome-protocol/rome-registry)). `1` — это кэшированная обёртка, описываемая в этом разделе. `2` — это обёртка прямого CPI, которую фабрика разворачивает для mint Token-2022 с активированным transfer hook; это руководство её не рассматривает. Реестр `tokens.json` перечисляет адрес обёртки и mint, но не указывает, к какому типу он относится.

## 4. Один трек на контракт и на транзакцию

В Rome есть два семейства прекомпиляций, которые изменяют состояние Solana, и **одна транзакция использует только одно из них** — runtime отклоняет транзакцию, которая смешивает мутирующие вызовы из обоих семейств, даже между разными контрактами.

| Трек             | Прекомпиляции                                                                                       | Эффекты достигают                                                                        | Работает в итеративном выполнении                                                                |
| ---------------- | --------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| **Legacy**       | `CpiProgram` `0xff…08` (`invoke`, `invoke_signed`), `HelperProgram` `0xff…09`, `Withdraw` `0x42…16` | Немедленно, как реальный CPI внутри шага EVM                                             | **Нет** — legacy-CPI в итеративной транзакции завершается ошибкой с `CpiProhibitedInIterativeTx` |
| **Кэшированный** | `SplCached` `0xff…05`, `ASplCached` `0xff…06`, `SystemCached` `0xff…04`, `WithdrawCached` `0xff…0b` | Стадируется в оверлее и коммитится как CPI в конце транзакции; EVM revert отбрасывает их | Да                                                                                               |

Что это означает для интеграции программы:

* **Вызов инструкций собственной программы возможен только на legacy-треке.** У кэшированного трека нет универсального `invoke`; он охватывает SPL-переводы, создание ATA, операции системной программы и вывод газа.
* Следовательно, шаг, который финансирует адаптер, тоже должен быть legacy-трековым, если он выполняется в той же транзакции, что и CPI. Вызов `transferFrom` — это вызов на cached-треке, поэтому он не может разделить транзакцию с вашим CPI (и, как показывает раздел 3, он лишь зачислит эскроу-реестр). Извлекайте с помощью `HelperProgram.transfer_spl(userAta, adapterAta, amount, mint)` вместо этого, после того как пользователь сделал адаптер SPL-делегатом (`approve_spl` , отправленным пользователем напрямую в HelperProgram). Извлечение и CPI — оба legacy-трековые, так что они выполняются в одной транзакции.
* **Держите обёртку вне этой транзакции.** Не вызывайте мутирующие функции обёртки (`wUSDC.transfer`, `transferFrom`) из адаптера в той же транзакции, что и legacy-CPI. Проверяйте `isEnabled(user)` и балансы с фронтенда с помощью `eth_call`.
* **И транзакция CPI должна быть атомарной.** Именно под этим ограничением лежит дизайн.

Чтения находятся вне этого правила: `account_info`, `account_data_at`, `account_u64_at`, `account_lamports`, `pdas_batch_derive` и `HelperProgram.user_balance` / `allowance_of` — это чтение заранее загруженных аккаунтов (без CPI), разрешённое на любом треке и в обоих режимах выполнения. Используйте их для предварительных проверок. Одно правило порядка: как только в транзакции сработала cached-мутaция, legacy-трековые чтения блокируются до конца этой транзакции — сначала читайте, потом мутируйте.

## 5. Атомарность — это бюджет

Атомарная транзакция Rome — это одна транзакция Solana: около **1,4 млн вычислительных единиц**, **64-адресный** список аккаунтов и **4 КБ** размер по wire (транзакции Solana v1). Программа Rome и ваш CPI делят этот бюджет. Перевод обёртки на Hadrian занимает около 170K CU, и ваша инструкция добавляет свой собственный расход; измеряйте по `computeUnitsConsumed`, а не по EVM `gasUsed`.

Когда эмуляция решает, что транзакция не помещается, Rome выполняет её **итеративно** через несколько транзакций Solana, и legacy-CPI внутри неё затем завершается ошибкой. Сведите каждый из deposit и withdraw к одному движению токена плюс одному CPI в вашу программу, и сделайте окружающий Solidity-код небольшим. Всё более крупное разделите на две пользовательские транзакции.

Глубина CPI: Solana допускает 4 уровня, а Rome использует один, так что ваша инструкция выполняется на уровне 2 с двумя уровнями ниже неё (ваша программа → SPL Token оставляет один).

## 6. Подготовка аккаунтов

Ваша программа не получает свои аккаунты из Solidity во время выполнения. Прокси **эмулирует** каждую транзакцию перед её отправкой, записывает каждый аккаунт Solana, к которому обращались CPI, и помещает их в транзакцию Solana. Ваш адаптер указывает аккаунты в `invoke_signed` списке аккаунтов; эмуляция доказывает, что они разрешаются. Отсюда следуют три вещи:

* Каждый аккаунт, к которому обращается ваша инструкция, должен выводиться из входных данных, которые есть у адаптера (его собственный PDA и суб-PDA, идентификатор вашей программы, mint'ы, адрес пользователя). `SystemProgram.find_program_address` и `CpiProgram.pdas_batch_derive` выполняют выводы в Solidity.
* Аккаунт, которого ещё не существует (свежая позиция, свежий ATA), всё равно должен быть указан в списке аккаунтов; его адрес — это то, что попадает в транзакцию Solana.
* Всё, к чему прикасается транзакция — включая собственные аккаунты Rome для пользователя, адаптера и обёртки — должно укладываться в 64 адреса. Дизайн, который за один вызов затрагивает десять рынков, не поместится.

Для полосы кошелька Solana, `rome_emulateCallAccounts` предоставляет клиенту то же обнаружение; SDK использует его.

Два аккаунта, которые CPI никогда не может указать: плательщик комиссии Solana, отправляющий транзакцию (кроме случая внутри обычной инструкции System transfer), и сама программа Rome. CPI обратно в программу Rome отклоняется.

## 7. Deposit и withdraw на Solidity

Минимальный набросок адаптера на legacy-треке. Пользователь уже отправил `approve_spl(adapter, amount, mint)` в HelperProgram (раздел 3). `PRIVACY_PROGRAM` — идентификатор вашей программы; `encodeDeposit` / `encodeWithdraw` формируют данные вашей инструкции (Borsh, little-endian); метаданные аккаунтов следуют макету вашей инструкции.

```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));                 // собственная идентичность адаптера в Solana
        Helper.create_ata(address(this), USDC_MINT);      // и аккаунт USDC, которым он владеет
    }

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

    function deposit(uint64 amount) external {
        bytes32 self       = Helper.pda(address(this));                   // подписант: полномочие адаптера
        bytes32 adapterAta = Helper.ata(address(this), USDC_MINT);
        bytes32 position   = Helper.pda_with_salt(address(this), _salt(msg.sender)); // суб-PDA на пользователя, тоже подписывает

        // Извлекаем из токен-аккаунта пользователя. Полномочие адаптера подписывает как SPL
        // delegate, который предоставил пользователь; это вызов legacy-трека, как и CPI ниже.
        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);                          // источник: принадлежит полномочию адаптера
        accs[3] = ICrossProgramInvocation.AccountMeta(_vaultFor(position), false, true);                 // хранилище вашей программы
        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);            // назначение: собственный аккаунт пользователя
        // ... та же структура: ваша программа перемещает `amount` из хранилища в userAta, подписано `position`
        Cpi.invoke_signed(PRIVACY_PROGRAM, accs, encodeWithdraw(amount), salts);
    }
}
```

Адаптер никогда не вызывает `wUSDC` контракт. `external_auth(adapter)` Извлечение — это вызов HelperProgram, который расходует делегирование пользователя, а токены находятся на токен-аккаунте, которым

владеет`Helper.pda(address(this))`), поэтому CPI может расходовать их. `солей`и один суб-PDA с солью на каждую запись в `солей`. Каждая указанная вами соль должна присутствовать в списке аккаунтов как подписант, иначе вызов завершается ошибкой `signer account calculated from the provided seed was not found`. Любому другому аккаунту, помеченному как signer, включая собственное полномочие пользователя, Rome не даёт seed, и runtime Solana отклоняет CPI. Права пользователя на свои токены происходят из делегирования, а не из того, что адаптер подписывает как пользователь.

Делегирование без извлечения: если ваша программа должна тратить напрямую с токен-аккаунта пользователя, пользователь отправляет `HelperProgram.approve_spl_raw_delegate(userAta, yourProgramPda, amount, mint, decimals)` напрямую в HelperProgram, указывая PDA вашей программы как SPL delegate. Мост Rome использует это для Wormhole. Правило одного делегата из раздела 3 применимо и здесь: предоставление вытесняет предоставление обёртки.

## 8. Тестирование

* Развертывайте на **Hadrian** (сначала в testnet, цепочка 200010); адреса и RPC находятся в [справочнике Contract Addresses](/ru/spravochnik/contract-addresses.md) и [реестре](https://github.com/rome-protocol/rome-registry).
* `eth_call` и `eth_estimateGas` выполняет ту же эмуляцию, которую прокси использует для отправки, поэтому CPI, который там завершается ошибкой, завершится ошибкой и в цепочке по той же причине, а данные отката содержат базовую ошибку Solana (`ошибка вызова non-EVM: …` в журнале программы Solana).
* Читать Solana-сторону успешно выполненной EVM-транзакции с помощью `rome_solanaTxForEvmTx(hash)`; в Solana-квитанции находятся CU и журналы вашей программы.
* CPI, который работает в `eth_call` но отклоняется при отправке, обычно упирается в лимит, о котором сообщает эмуляция: ограничение в 64 адреса, атомарный бюджет CU (транзакция стала итеративной) или правило track.

## 9. Справочник

* [Справочник precompile](/ru/spravochnik/precompiles.md) — каждый селектор для каждого precompile, с его классом диспетчеризации и правилом delegatecall.
* [Ограничения](/ru/klyuchevye-ponyatiya/constraints.md) — все перечисленные выше ограничения в одной таблице.
* [Совместимость токенов](/ru/klyuchevye-ponyatiya/token-interop.md) — обёртки, канонические mint-ы, пополнение и вывод.
* Приложения-референсы в публичных репозиториях: [cardo](https://github.com/rome-protocol/cardo) (пользователь вызывает precompile CPI напрямую, схема B), [rome-dex](https://github.com/rome-protocol/rome-dex) (прямой `invoke` плюс маршрутизатор без кастодиального хранения, схема C), и [aerarium](https://github.com/rome-protocol/aerarium) (лендинговое приложение Compound III поверх одного общего рынка; оно не вызывает программы Solana из Solidity (без CPI), поэтому это не пример адаптера).


---

# 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/ru/rukovodstva-dlya-razrabotchikov/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.
