Отправка токенов на неверный адрес может привести к безвозвратной потере средств. Проверка адреса гарантирует, что вы отправляете токены только на те адреса, которые могут их корректно получить и использовать.
Подробнее о ключевых понятиях платежей читайте в разделе Как работают платежи в Solana.
Понимание адресов Solana
В Solana у аккаунтов есть два типа адресов: on-curve и off-curve.
On-curve адреса
Стандартные адреса — это публичные ключи из пар ключей Ed25519. Эти адреса:
- Имеют соответствующий приватный ключ, который может подписывать транзакции
- Используются как адреса кошельков
Off-curve адреса (PDA)
Program Derived Addresses (PDA) детерминировано создаются на основе ID программы и seed-значений. Эти адреса:
- Не имеют соответствующего приватного ключа
- Могут быть подписаны только программой, от которой был получен этот адрес
Типы аккаунтов в платежах
Используйте адрес, чтобы получить аккаунт из сети, проверьте его владельца (программу) и тип аккаунта, чтобы понять, как работать с этим адресом.
Знание того, является ли адрес on-curve или off-curve, не говорит о том, какой это тип аккаунта, какая программа им владеет или существует ли аккаунт по этому адресу. Необходимо получить аккаунт из сети, чтобы узнать эти детали.
Аккаунты System Program (кошельки)
Аккаунты, принадлежащие System Program, являются стандартными кошельками. Чтобы отправить SPL токены на кошелек, необходимо получить и использовать его associated token account (ATA).
После получения адреса ATA проверьте, существует ли этот token account в блокчейне. Если ATA не существует, вы можете добавить инструкцию на создание токен-аккаунта получателя в ту же транзакцию, что и перевод. Однако для этого потребуется оплатить rent за новый token account. Поскольку получатель владеет ATA, SOL, потраченные на rent, не могут быть возвращены отправителю.
Без мер предосторожности субсидирование создания ATA может быть использовано в корыстных целях. Злоумышленник может запросить перевод, создать свой ATA за ваш счёт, закрыть ATA, чтобы вернуть rent в SOL, и повторить это снова.
Токен-аккаунты
Токен-аккаунты принадлежат Token Program или Token-2022 Program и содержат балансы токенов. Если полученный вами адрес принадлежит токен-программе, необходимо убедиться, что это токен-аккаунт (а не mint account) и что он соответствует ожидаемому mint account токена перед отправкой.
Token Program автоматически проверяют, что оба токен-аккаунта при переводе содержат токены одного и того же mint. Если проверка не проходит, транзакция отклоняется, и средства не теряются.
Mint-аккаунты
Mint-аккаунты отслеживают эмиссию токена и метаданные конкретного токена. Mint-аккаунты также принадлежат Token Program, но не являются допустимыми получателями токенов. Попытка отправить токены на адрес mint приводит к неудачной транзакции, но средства не теряются.
Другие аккаунты
Аккаунты, принадлежащие другим программам, требуют отдельной политики. Некоторые аккаунты (например, мультисиг-кошельки) могут быть допустимыми владельцами токен-аккаунтов, а другие должны быть отклонены.
Процесс верификации
На следующей схеме показано примерное дерево решений для проверки адреса:
Получить аккаунт
Используйте адрес для получения данных аккаунта из сети.
Аккаунт не существует
Если по этому адресу нет аккаунта, проверьте, находится ли адрес на кривой или вне кривой:
-
Off-curve (PDA): Консервативно отклоняйте этот адрес, чтобы избежать отправки на ATA, который может быть недоступен. Без существующего аккаунта невозможно определить только по адресу, какая программа сгенерировала этот PDA или предназначен ли адрес для ATA. Создание ATA для этого адреса с целью отправки токенов может привести к блокировке средств на недоступном token account.
-
On-curve: Это действительный адрес кошелька (публичный ключ), который еще не был профинансирован. Получите ATA, проверьте его наличие и отправьте туда токены. Вам необходимо принять решение о политике: финансировать ли создание ATA, если он отсутствует.
Аккаунт существует
Если аккаунт существует, проверьте, какая программа им владеет:
-
System Program: Это стандартный кошелек. Получите ATA, проверьте его наличие и отправьте туда токены. Необходимо принять решение о политике: финансировать ли создание ATA, если он отсутствует.
-
Token Program / Token-2022: Убедитесь, что аккаунт является token account (а не mint account) и что он содержит нужный вам токен (mint). Если все верно, отправьте токены напрямую на этот адрес. Если это mint account или token account для другого mint, отклоните адрес.
-
Other Program: Требуется решение по политике. Некоторые программы, например мультисиг-кошельки, могут быть допустимыми владельцами token account. Если ваша политика это разрешает, получите ATA и отправьте. В противном случае отклоните адрес.
Демонстрация
Следующий пример показывает только логику валидации адреса. Это справочный код для иллюстрации.
В этом демо не показано, как получить ATA или сформировать транзакцию для отправки токенов. Обратитесь к документации по token account и token transfer, чтобы посмотреть примеры кода.
В демо ниже используются три возможных результата:
| Результат | Значение | Действие |
|---|---|---|
IS_WALLET | Валидный адрес кошелька | Получить и отправить на associated token account |
IS_TOKEN_ACCOUNT | Валидный token account | Отправить токены напрямую на этот адрес |
REJECT | Неверный адрес | Не отправлять |
/*** Validates an input address and classifies it as a wallet, token account, 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* - 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 on-chainif (!account.exists) {// Off-curve = PDA that doesn't exist as an account// Reject conservatively to avoid sending to an address that may be inaccessible.if (isOffCurveAddress(inputAddress)) {return { type: "REJECT", reason: "PDA doesn't exist as an account" };}// On-curve = valid keypair address, treat as unfunded walletreturn { type: "IS_WALLET" };}// Account exists, check program ownerconst owner = account.programAddress;// System Program = walletif (owner === SYSTEM_PROGRAM) {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"};}// Unknown program ownerreturn { type: "REJECT", reason: "Unknown program owner" };}// =============================================================================// Examples// =============================================================================
Is this page helpful?