Weryfikacja adresu

Wysłanie środków na nieprawidłowy adres może skutkować ich trwałą utratą. Weryfikacja adresu zapewnia, że Ty i Twoi użytkownicy wysyłacie środki wyłącznie na adresy, które mogą je prawidłowo odbierać i do nich uzyskiwać dostęp. Jeśli prowadzisz giełdę, zaleca się przeprowadzenie tych kontroli oraz poproszenie użytkownika o weryfikację adresu przed wysłaniem.

Walidacja zależy od tego, co wysyłasz:

  • Tokeny SPL są częściowo samochroniące. Token Program odrzuca transfer, którego konta nie pasują do oczekiwanego mintu, więc błędnie skierowany transfer tokenów kończy się niepowodzeniem bez utraty środków. Większość tej strony dotyczy wysyłania tokenów SPL.
  • Natywne SOL nie ma takiego zabezpieczenia. Transfer przez System Program powiedzie się na każdym koncie, więc nieprawidłowy odbiorca trwale blokuje SOL. Zobacz Wysyłanie natywnego SOL.

Zobacz Jak działają płatności na Solanie, aby poznać podstawowe koncepcje dotyczące płatności.

Zrozumienie adresów Solany

Konta Solany mają dwa typy adresów: na krzywej (on-curve) i poza krzywą (off-curve).

Adresy na krzywej (On-Curve)

Standardowe adresy to klucze publiczne z keypairs Ed25519. Te adresy:

  • Posiadają odpowiadający klucz prywatny, który może podpisywać transakcje
  • Są używane jako adresy portfeli

Adresy poza krzywą (PDAs)

Program Derived Addresses są deterministycznie wyprowadzane z identyfikatora programu i ziaren (seeds). Te adresy:

  • Nie posiadają odpowiadającego klucza prywatnego
  • Mogą być podpisywane wyłącznie przez program, z którego adres został wyprowadzony

Portfele kontrolowane przez programy, powszechnie określane jako smart portfele lub smart konta, posiadają adresy poza krzywą (off-curve). W tym przewodniku konsekwentnie używany jest termin „smart portfel“.

Typy kont w płatnościach

Użyj adresu, aby pobrać konto z sieci, sprawdź właściciela programu i typ konta, aby określić sposób obsługi adresu.

Wiedza o tym, czy adres jest na krzywej, czy poza krzywą, nie mówi ci, jaki to typ konta, który program jest jego właścicielem ani czy konto istnieje pod tym adresem. Aby ustalić te szczegóły, musisz pobrać konto z sieci.

Konta System Program (Portfele)

Konta należące do System Program to standardowe portfele. Aby wysłać tokeny SPL do portfela, należy wyprowadzić i użyć jego Associated Token Account (ATA).

Po wyprowadzeniu adresu ATA sprawdź, czy token account istnieje w łańcuchu. Jeśli ATA nie istnieje, możesz dołączyć instrukcję jego utworzenia dla odbiorcy w tej samej transakcji co przelew. Wymaga to jednak opłacenia rent za nowy token account. Ponieważ odbiorca jest właścicielem ATA, SOL zapłacony za rent nie może zostać odzyskany przez nadawcę.

Konta systemowe mogą istnieć poza krzywą (off-curve). Jeśli użytkownik chce wysłać tokeny na adres off-curve, zaleca się wyświetlenie monitu z prośbą o potwierdzenie, że zamierza wysłać środki do smart portfela.

Bez odpowiednich zabezpieczeń, finansowanie tworzenia ATA może zostać wykorzystane do nadużyć. Złośliwy użytkownik mógłby zażądać przelewu, doprowadzić do utworzenia swojego ATA na Twój koszt, zamknąć ATA w celu odzyskania rent SOL, a następnie powtarzać ten proceder.

Token Accounts

Token accounts są własnością Token Program lub Token-2022 Program i przechowują salda tokenów. Jeśli adres, który otrzymujesz, należy do programu tokenów, powinieneś zweryfikować, czy konto jest token account (nie mint account) i czy odpowiada oczekiwanemu token mint account przed wysłaniem.

Token Programs automatycznie weryfikują, czy oba token accounts w transakcji przechowują tokeny tego samego mintu. Jeśli weryfikacja się nie powiedzie, transakcja zostaje odrzucona i żadne środki nie są tracone.

Konta Mint

Mint accounts śledzą podaż tokenów oraz metadane konkretnego tokena. Mint accounts są również własnością Token Programs, ale nie są prawidłowymi odbiorcami transferów tokenów. Próba wysłania tokenów na adres mint skutkuje nieudaną transakcją, jednak żadne środki nie są tracone.

Inne konta

Konta należące do innych programów są prawidłowe, lecz podlegają regułom uprawnień określonym przez odpowiedni program będący właścicielem. Zaleca się wyświetlenie monitu z prośbą o potwierdzenie, że użytkownik zamierza wysłać środki do smart portfela.

Wysyłanie natywnego SOL

Powyższa klasyfikacja określa, dokąd mogą trafiać tokeny SPL. Natywny SOL jest bardziej restrykcyjny: jedynym bezpiecznym odbiorcą jest portfel System Program (lub niefinansowany adres na krzywej, który staje się nim).

Transfer w ramach System Program dodaje lamport do dowolnego konta, w tym mint, token accounts, programów i PDA. Lamports mogą być wyprowadzone tylko przez program będący właścicielem konta, więc wysłanie SOL do nieprawidłowego odbiorcy może skutkować trwałą utratą środków.

W przeciwieństwie do transferu tokenów SPL, transakcja nie kończy się niepowodzeniem, gdy odbiorca jest nieoczekiwanym adresem.

Podczas wysyłania natywnego SOL akceptowalnym wynikiem jest wyłącznie IS_WALLET. IS_TOKEN_ACCOUNT nie jest: token account przechowuje tokeny SPL, a SOL wysłany tam jest poza kontrolą nadawcy.

To częsty sposób na utratę SOL: użytkownik wkleja adres mint tokena (lub adres programu) do pola wypłaty SOL. Transfer kończy się powodzeniem, a SOL jest nieodwracalnie utracony. Zawsze klasyfikuj odbiorcę przed podpisaniem transferu SOL.

Przepływ weryfikacji

Poniższy diagram przedstawia referencyjne drzewo decyzyjne do walidacji adresu:

Address Verification Flow

Pobierz konto

Użyj adresu, aby pobrać szczegóły konta z sieci.

Konto nie istnieje

Jeśli pod tym adresem nie istnieje żadne konto, sprawdź, czy adres jest on-curve, czy off-curve:

  • Off-curve (PDA): Wymagaj jawnego potwierdzenia odbiorcy przed utworzeniem ATA lub wysłaniem tokenów SPL. Bez istniejącego konta nie można określić wyłącznie na podstawie adresu, który program wyprowadził ten PDA ani czy program odbiorcy może uzyskać dostęp do jego ATA.

  • On-curve: Jest to prawidłowy adres portfela (klucz publiczny), który nie został jeszcze zasilony. Wyprowadź ATA, sprawdź, czy istnieje, i wyślij na niego tokeny. Musisz podjąć decyzję dotyczącą polityki, czy sfinansować utworzenie ATA, jeśli jeszcze nie istnieje.

Konto istnieje

Jeśli konto istnieje, sprawdź, który program jest jego właścicielem:

  • System Program: Jest to standardowy portfel. Wyprowadź ATA, sprawdź, czy istnieje, i wyślij na niego tokeny. Musisz podjąć decyzję dotyczącą polityki, czy sfinansować utworzenie ATA, jeśli jeszcze nie istnieje.

  • Token Program / Token-2022: Sprawdź, czy konto jest token account (nie mint account) oraz czy przechowuje token (mint), który zamierzasz wysłać. Jeśli jest prawidłowe, wyślij tokeny bezpośrednio na ten adres. Jeśli jest to mint account lub token account powiązany z innym mintem, odrzuć adres.

  • Inny program: Programy takie jak portfele multisig są dopuszczalnymi właścicielami token accounts. Wymagaj od użytkownika potwierdzenia, że zamierza wysłać środki do smart portfela.

    Niektóre popularne smart portfele:

Demo

Poniższy przykład pokazuje wyłącznie logikę walidacji adresu. Jest to kod referencyjny dla celów ilustracyjnych.

Demo nie pokazuje, jak wyprowadzić ATA ani jak zbudować transakcję wysyłania tokenów. Zapoznaj się z dokumentacją token account oraz token transfer, aby zobaczyć przykładowy kod.

Demo poniżej wykorzystuje trzy możliwe wyniki:

WynikZnaczenieAkcja
IS_WALLETPrawidłowy adres portfelaWyprowadź i wyślij na associated token account
IS_TOKEN_ACCOUNTPrawidłowy token accountWyślij tokeny bezpośrednio na ten adres
USER_VERIFICATIONAdres wymaga potwierdzenia przez odbiorcęWymagaj jawnej weryfikacji przed wysłaniem tokenów SPL lub sfinansowaniem ATA
REJECTNieprawidłowy adresNie wysyłaj

Następnie mapuje każdy wynik na akceptowalność dla poszczególnych zasobów za pomocą canReceiveNativeSol (wyłącznie portfele) oraz canReceiveSplToken (portfele lub token accounts). Wynik USER_VERIFICATION nie jest akceptowany automatycznie — Twoja aplikacja powinna wymagać od użytkownika potwierdzenia zamiaru przed wysłaniem tokenów SPL. Token account zwraca IS_TOKEN_ACCOUNT, dzięki czemu może odbierać tokeny SPL, ale nie natywny SOL — to rozróżnienie zapobiega zablokowaniu SOL.

Demo
/**
* 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 demo
console.log("\nAccount:", account);
// Account doesn't exist onchain
if (!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 wallet
return { type: "IS_WALLET" };
}
// Account exists, check program owner
const 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 account
if (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
// =============================================================================
Console
Click to execute the code.

Is this page helpful?

Spis treści

Edytuj stronę