Отправка средств на неверный адрес может привести к их безвозвратной потере. Проверка адреса гарантирует, что вы и ваши пользователи отправляете средства только на адреса, которые могут их корректно принять и использовать. Если вы управляете биржей, рекомендуется выполнять эти проверки и просить пользователя подтвердить адрес перед отправкой.
Валидация зависит от того, что именно вы отправляете:
- SPL-токены частично защищены встроенными механизмами. Token Program отклоняет перевод, если аккаунты не соответствуют ожидаемому минту, поэтому ошибочный перевод токенов завершится неудачей без потери средств. Большая часть этой страницы посвящена отправке SPL-токенов.
- Нативный SOL не имеет подобной защиты. Перевод через System Program успешно выполняется на любой аккаунт, поэтому при указании неверного получателя SOL будет заблокирован навсегда. См. Отправка нативного SOL.
См. Как работают платежи в Solana для ознакомления с основными концепциями платежей.
Понимание адресов Solana
Аккаунты Solana имеют два типа адресов: on-curve и off-curve.
On-Curve адреса
Стандартные адреса — это публичные ключи из Ed25519 keypair. Такие адреса:
- Имеют соответствующий приватный ключ, которым можно подписывать транзакции
- Используются в качестве адресов кошельков
Off-Curve адреса (PDA)
Program Derived Addresses детерминированно выводятся из идентификатора программы и сидов. Такие адреса:
- Не имеют соответствующего приватного ключа
- Могут быть подписаны только той программой, из которой был выведен адрес
Кошельки, управляемые программами, которые часто называют смарт-кошельками или смарт-аккаунтами, имеют адреса вне кривой. В данном руководстве повсеместно используется термин «смарт-кошелёк».
Типы аккаунтов в платежах
Используйте адрес для получения аккаунта из сети, проверьте владельца программы и тип аккаунта, чтобы определить порядок работы с данным адресом.
Знание того, является ли адрес on-curve или off-curve, не говорит вам о типе аккаунта, какой программе он принадлежит и существует ли аккаунт по этому адресу. Для получения этих сведений необходимо запросить аккаунт из сети.
Аккаунты System Program (Кошельки)
Аккаунты, принадлежащие System Program, являются стандартными кошельками. Чтобы отправить SPL-токены на кошелёк, необходимо получить и использовать его Associated Token Account (ATA).
После получения адреса ATA проверьте, существует ли token account в сети. Если ATA не существует, вы можете включить инструкцию по созданию token account получателя в ту же транзакцию, что и перевод. Однако это требует оплаты rent за новый token account. Поскольку получатель является владельцем ATA, SOL, уплаченные за rent, не могут быть возвращены отправителю.
Системные аккаунты могут существовать вне кривой. Если пользователь хочет отправить токены на адрес вне кривой, рекомендуется предложить ему подтвердить, что он намерен отправить средства на смарт-кошелёк.
Без защитных мер субсидирование создания ATA может быть использовано в мошеннических целях. Злоумышленник может запросить перевод, добиться создания своего ATA за ваш счёт, закрыть ATA, чтобы вернуть rent SOL, и повторять эту схему снова.
Token Accounts
Token accounts принадлежат Token Program или Token-2022 Program и хранят балансы токенов. Если адрес, который вы получили, принадлежит token program, следует убедиться, что аккаунт является token account (а не mint account) и соответствует ожидаемому mint account токена перед отправкой.
Token Programs автоматически проверяют, что оба token account в транзакции перевода содержат токены одного и того же mint. Если проверка не пройдена, транзакция отклоняется и средства не теряются.
Mint Accounts
Mint accounts отслеживают объём предложения токенов и метаданные конкретного токена. Mint accounts также принадлежат Token Programs, но не являются допустимыми получателями при переводе токенов. Попытка отправить токены на mint-адрес приведёт к неудачной транзакции, однако средства не будут потеряны.
Другие аккаунты
Аккаунты, принадлежащие другим программам, являются допустимыми, однако подчиняются правилам управления, установленным соответствующей программой-владельцем. Рекомендуется предложить пользователю подтвердить, что он намерен отправить средства на смарт-кошелёк.
Отправка нативного SOL
Приведённая выше классификация определяет, куда могут поступать SPL-токены. Нативный SOL подчиняется более строгим правилам: единственным безопасным получателем является кошелёк System Program (или незафондированный адрес на кривой, который станет таковым).
Перевод через System Program добавляет lamport на любой аккаунт, включая минты, token account, программы и PDA. Lamport могут быть выведены только программой-владельцем аккаунта, поэтому отправка SOL на неверный адрес получателя может привести к безвозвратной потере средств.
В отличие от перевода SPL-токенов, транзакция не завершается ошибкой, если получателем оказывается неожиданный адрес.
При отправке нативного SOL приемлемым результатом является только IS_WALLET.
IS_TOKEN_ACCOUNT не является таковым: token account хранит SPL-токены, и
отправленный туда SOL выходит из-под контроля отправителя.
Это распространённая причина потери SOL: пользователь вставляет адрес минта токена (или адрес программы) в поле вывода SOL. Перевод проходит успешно, и SOL становится невозможно вернуть. Всегда определяйте тип получателя перед подписанием SOL-перевода.
Процесс верификации
На следующей диаграмме показано справочное дерево решений для валидации адреса:
Получение данных аккаунта
Используйте адрес для получения данных аккаунта из сети.
Аккаунт не существует
Если по данному адресу нет аккаунта, проверьте, находится ли адрес на кривой или вне кривой:
-
Вне кривой (PDA): Требуйте явного подтверждения от получателя перед созданием ATA или отправкой SPL-токенов. При отсутствии существующего аккаунта невозможно определить только по адресу, какая программа породила этот PDA или сможет ли программа получателя получить доступ к его ATA.
-
На кривой: Это действительный адрес кошелька (публичный ключ), который ещё не пополнялся. Определите ATA, проверьте его существование и отправьте на него токены. Вам необходимо принять политическое решение — финансировать ли создание ATA, если он не существует.
Аккаунт существует
Если аккаунт существует, проверьте, какая программа им владеет:
-
System Program: Это стандартный кошелёк. Определите ATA, проверьте его существование и отправьте на него токены. Вам необходимо принять политическое решение — финансировать ли создание ATA, если он не существует.
-
Token Program / Token-2022: Убедитесь, что аккаунт является token account (а не mint account) и содержит тот токен (mint), который вы намерены отправить. Если всё верно, отправьте токены непосредственно на этот адрес. Если это mint account или token account для другого mint, отклоните адрес.
-
Другая программа: Такие программы, как кошельки с мультиподписью, являются допустимыми владельцами token accounts. Попросите пользователя подтвердить, что он намерен отправить средства на смарт-кошелёк.
Некоторые распространённые смарт-кошельки:
Демонстрация
Следующий пример демонстрирует только логику проверки адреса. Это справочный код в ознакомительных целях.
Демонстрация не показывает, как получить ATA или создать транзакцию для отправки токенов. Обратитесь к документации по token account и переводу токенов для получения примеров кода.
Демонстрация ниже использует три возможных результата:
| Результат | Значение | Действие |
|---|---|---|
IS_WALLET | Действительный адрес кошелька | Получить ATA и отправить на него токены |
IS_TOKEN_ACCOUNT | Действительный token account | Отправить токены непосредственно на этот адрес |
USER_VERIFICATION | Адрес требует подтверждения от получателя | Требуйте явной проверки перед отправкой SPL-токенов или финансированием ATA |
REJECT | Недействительный адрес | Не отправлять |
Затем каждый результат сопоставляется с допустимостью для конкретного актива с помощью canReceiveNativeSol (только для кошельков) и canReceiveSplToken (для кошельков или token accounts). Результат USER_VERIFICATION не принимается автоматически — ваше приложение должно запросить у пользователя подтверждение намерения перед отправкой SPL-токенов. Token account возвращает IS_TOKEN_ACCOUNT, поэтому он может принимать SPL-токены, но не нативный SOL — именно это различие предотвращает блокировку SOL.
/*** Validates an input address and classifies it as a wallet, token account,* address requiring recipient verification, or invalid.** @param inputAddress - The address to validate* @param rpc - Optional RPC client (defaults to mainnet)* @returns Classification result:* - IS_WALLET: Valid wallet address* - IS_TOKEN_ACCOUNT: Valid token account* - USER_VERIFICATION: Require explicit review before sending SPL tokens* - REJECT: Invalid address for transfers*/export async function validateAddress(inputAddress: Address,rpc: Rpc<GetAccountInfoApi> = defaultRpc): Promise<ValidationResult> {const account = await fetchJsonParsedAccount(rpc, inputAddress);// Log the account data for democonsole.log("\nAccount:", account);// Account doesn't exist onchainif (!account.exists) {// An unfunded PDA may belong to a smart wallet, but the address// alone cannot prove that its program can access a newly-created ATA.if (isOffCurveAddress(inputAddress)) {return {type: "USER_VERIFICATION",reason:"Unfunded PDA: confirm the recipient is using a smart wallet and controls this address"};}// On-curve = valid keypair address, treat as unfunded walletreturn { type: "IS_WALLET" };}// Account exists, check program ownerconst owner = account.programAddress;// A System Program account can be a standard wallet or an off-curve smart// wallet. Require verification before automatically sending to the// latter.if (owner === SYSTEM_PROGRAM) {if (isOffCurveAddress(inputAddress)) {return {type: "USER_VERIFICATION",reason:"Off-curve System Program account: confirm recipient is using a smart wallet"};}return { type: "IS_WALLET" };}// Token Program or Token-2022, check if token accountif (owner === TOKEN_PROGRAM || owner === TOKEN_2022_PROGRAM) {const accountType = (account.data as { parsedAccountMeta?: { type?: string } }).parsedAccountMeta?.type;if (accountType === "account") {return { type: "IS_TOKEN_ACCOUNT" };}// Reject if not a token account (mint account)return {type: "REJECT",reason: "Not a token account"};}// An account owned by another program can be a smart wallet.return {type: "USER_VERIFICATION",reason:"Program-owned account: confirm the recipient is using a smart wallet"};}/*** Native SOL is only safe to send to a wallet. Any other account locks it.*/function canReceiveNativeSol(result: ValidationResult): boolean {return result.type === "IS_WALLET";}/*** SPL tokens can go to a wallet (via its ATA) or directly to a token account.*/function canReceiveSplToken(result: ValidationResult): boolean {return result.type === "IS_WALLET" || result.type === "IS_TOKEN_ACCOUNT";}// =============================================================================// Examples// =============================================================================
Is this page helpful?