Надсилання токенів на неправильну адресу може призвести до безповоротної втрати коштів. Перевірка адреси гарантує, що ви надсилаєте токени лише на адреси, які можуть належним чином отримати їх та отримати до них доступ.
Див. Як працюють платежі в Solana для ознайомлення з основними концепціями платежів.
Розуміння адрес Solana
Акаунти Solana мають два типи адрес: on-curve та off-curve.
Адреси on-curve
Стандартні адреси — це публічні ключі з пар ключів Ed25519. Ці адреси:
- Мають відповідний приватний ключ, який може підписувати транзакції
- Використовуються як адреси гаманців
Адреси off-curve (PDA)
Program Derived Addresses детерміновано виводяться з ідентифікатора програми та seeds. Ці адреси:
- Не мають відповідного приватного ключа
- Можуть бути підписані лише програмою, з якої було виведено адресу
Типи акаунтів у платежах
Використовуйте адресу для отримання акаунта з мережі, перевірте його власника-програму та тип акаунта, щоб визначити, як обробляти адресу.
Знання того, чи є адреса on-curve або off-curve, не повідомляє вам, який тип акаунта це, яка програма володіє ним або чи існує акаунт за цією адресою. Ви повинні отримати акаунт з мережі, щоб визначити ці деталі.
Акаунти System Program (гаманці)
Акаунти, що належать System Program, є стандартними гаманцями. Щоб надіслати SPL-токени на гаманець, ви виводите та використовуєте його associated token account (ATA).
Після виведення адреси ATA перевірте, чи існує токен-акаунт в мережі. Якщо ATA не існує, ви можете включити інструкцію для створення токен-акаунта одержувача в тій самій транзакції, що й переказ. Однак це вимагає сплати rent за новий токен-акаунт. Оскільки одержувач володіє ATA, SOL, сплачені за rent, не можуть бути повернені відправнику.
Без захисних заходів субсидування створення ATA може бути використане зловмисниками. Зловмисник може запитати переказ, створити свій ATA за ваш рахунок, закрити ATA для повернення орендної плати в SOL і повторити процес.
Токен-акаунти
Токен-акаунти належать Token Program або Token-2022 Program і зберігають баланси токенів. Якщо отримана адреса належить токен-програмі, ви повинні перевірити, що акаунт є токен-акаунтом (а не mint account) і відповідає очікуваному mint account токена перед відправленням.
Token Programs автоматично перевіряють, що обидва токен-акаунти в переказі містять токени одного mint. Якщо перевірка не вдається, транзакція відхиляється і кошти не втрачаються.
Mint accounts
Mint accounts відстежують пропозицію токенів та метадані конкретного токена. Mint accounts також належать Token Programs, але не є дійсними одержувачами для переказів токенів. Спроба надіслати токени на адресу mint призводить до невдалої транзакції, але кошти не втрачаються.
Інші акаунти
Акаунти, що належать іншим програмам, вимагають прийняття рішення щодо політики. Деякі акаунти (наприклад, мультипідписні гаманці) можуть бути дійсними власниками токен-акаунтів, тоді як інші слід відхилити.
Процес перевірки
Наступна діаграма показує еталонне дерево рішень для валідації адреси:
Отримання акаунта
Використовуйте адресу для отримання деталей акаунта з мережі.
Акаунт не існує
Якщо за цією адресою не існує акаунта, перевірте, чи адреса знаходиться на кривій чи поза кривою:
-
Поза кривою (PDA): Консервативно відхиляйте адресу, щоб уникнути надсилання на ATA, який може бути недоступним. Без існуючого облікового запису ви не можете визначити лише за адресою, яка програма створила цей PDA або чи є адреса для ATA. Виведення ATA для цієї адреси для надсилання токенів може призвести до блокування коштів у недоступному токен-акаунті.
-
На кривій: Це дійсна адреса гаманця (публічний ключ), яка ще не була профінансована. Виведіть ATA, перевірте, чи він існує, і надішліть токени на нього. Ви повинні прийняти рішення щодо політики, чи фінансувати створення ATA, якщо він не існує.
Обліковий запис існує
Якщо обліковий запис існує, перевірте, якій програмі він належить:
-
System Program: Це стандартний гаманець. Виведіть ATA, перевірте, чи він існує, і надішліть токени на нього. Ви повинні прийняти рішення щодо політики, чи фінансувати створення ATA, якщо він не існує.
-
Token Program / Token-2022: Переконайтеся, що обліковий запис є токен-акаунтом (а не mint account) і що він містить токен (mint), який ви маєте намір надіслати. Якщо дійсний, надішліть токени безпосередньо на цю адресу. Якщо це mint account або токен-акаунт для іншого mint, відхиліть адресу.
-
Інша програма: Це вимагає рішення щодо політики. Деякі програми, такі як мультипідписні гаманці, можуть бути прийнятними власниками токен-акаунтів. Якщо ваша політика дозволяє це, виведіть ATA і надішліть. В іншому випадку відхиліть адресу.
Демонстрація
Наступний приклад показує лише логіку валідації адреси. Це довідковий код для ілюстративних цілей.
Демонстрація не показує, як отримати ATA або побудувати транзакцію для відправлення токенів. Зверніться до документації про обліковий запис токенів та переказ токенів для прикладів коду.
Демонстрація нижче використовує три можливі результати:
| Результат | Значення | Дія |
|---|---|---|
IS_WALLET | Дійсна адреса гаманця | Отримати та надіслати на associated token account |
IS_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?