Enviar fundos para o endereço errado pode resultar em perda permanente. A verificação de endereços garante que você e seus usuários enviem apenas para endereços que possam receber e acessar os fundos corretamente. Se você opera uma exchange, é recomendável realizar essas verificações e pedir que o usuário confirme o endereço antes de enviar.
A validação depende do que você envia:
- Tokens SPL são parcialmente autoprotegidos. O Token Program rejeita uma transferência cujas contas não correspondem ao mint esperado, portanto, uma transferência de token mal direcionada falha sem perda de fundos. A maior parte desta página aborda o envio de tokens SPL.
- SOL nativo não possui essa proteção. Uma transferência do System Program é bem-sucedida em qualquer conta, portanto, um destinatário incorreto bloqueia o SOL permanentemente. Consulte Enviando SOL nativo.
Consulte Como os Pagamentos Funcionam na Solana para os conceitos básicos de pagamento.
Entendendo os Endereços da Solana
As contas da Solana têm dois tipos de endereços: na curva e fora da curva.
Endereços na Curva
Os endereços padrão são as chaves públicas de keypairs Ed25519. Esses endereços:
- Possuem uma chave privada correspondente que pode assinar transações
- São usados como endereços de carteira
Endereços Fora da Curva (PDAs)
Program Derived Addresses são derivados deterministicamente de um ID de programa e seeds. Esses endereços:
- Não possuem uma chave privada correspondente
- Só podem ser assinados pelo programa do qual o endereço foi derivado
Carteiras controladas por programas, comumente chamadas de smart wallets ou smart accounts, possuem endereços fora da curva. Este guia utiliza o termo "smart wallet" ao longo do texto.
Tipos de Conta em Pagamentos
Use o endereço para buscar uma conta na rede, verifique o proprietário do programa e o tipo de conta para determinar como tratar o endereço.
Saber se um endereço está na curva ou fora da curva não indica o tipo de conta que é, qual programa a detém, nem se existe uma conta nesse endereço. Você deve buscar a conta na rede para determinar esses detalhes.
Contas do System Program (Carteiras)
Contas pertencentes ao System Program são carteiras padrão. Para enviar tokens SPL para uma carteira, você deriva e usa sua Conta de Token Associada (ATA).
Após derivar o endereço da ATA, verifique se o token account existe onchain. Se a ATA não existir, você pode incluir uma instrução para criar o token account do destinatário na mesma transação que a transferência. No entanto, isso exige o pagamento de rent para o novo token account. Como o destinatário é o dono da ATA, o SOL pago pelo rent não pode ser recuperado pelo remetente.
Contas do sistema podem existir fora da curva. Se o seu usuário deseja enviar tokens para um endereço fora da curva, é recomendável solicitar que o usuário confirme que pretende enviar fundos para uma smart wallet.
Sem medidas de proteção, subsidiar a criação de ATAs pode ser explorado. Um usuário mal-intencionado poderia solicitar uma transferência, ter sua ATA criada às suas custas, encerrar a ATA para recuperar o rent em SOL e repetir o processo.
Token Accounts
Os token accounts pertencem ao Token Program ou ao Token-2022 Program e armazenam saldos de tokens. Se o endereço que você receber pertencer a um token program, você deve verificar se a conta é um token account (e não um mint account) e se corresponde ao mint account do token esperado antes de enviar.
Os Token Programs validam automaticamente que ambos os token accounts em uma transferência contêm tokens do mesmo mint. Se a validação falhar, a transação é rejeitada e nenhum fundo é perdido.
Mint Accounts
Os mint accounts rastreiam o fornecimento de tokens e os metadados de um token específico. Os mint accounts também pertencem aos Token Programs, mas não são destinatários válidos para transferências de tokens. Tentar enviar tokens para um endereço de mint resulta em uma transação com falha, mas nenhum fundo é perdido.
Outras Contas
Contas pertencentes a outros programas são válidas, mas estão sujeitas às regras de autoridade estabelecidas pelo programa proprietário correspondente. É recomendável solicitar que o usuário confirme que pretende enviar fundos para uma smart wallet.
Enviando SOL nativo
A classificação acima determina para onde os tokens SPL podem ir. O SOL nativo é mais restritivo: o único destinatário seguro é uma carteira do System Program (ou um endereço não financiado na curva que se torna um).
Uma transferência do System Program adiciona lamports a qualquer conta, incluindo mints, token accounts, programas e PDAs. Os lamports só podem ser retirados pelo programa proprietário da conta, portanto, enviar SOL para um destinatário incorreto pode resultar em fundos perdidos permanentemente.
Ao contrário de uma transferência de token SPL, a transação não falha quando o destinatário é um endereço inesperado.
Ao enviar SOL nativo, apenas um resultado IS_WALLET é aceitável.
IS_TOKEN_ACCOUNT não é: uma token account armazena tokens SPL, e o SOL
enviado para lá fica fora do controle do remetente.
Esta é uma forma comum de perder SOL: um usuário cola o endereço mint de um token (ou um endereço de programa) em um saque de SOL. A transferência é concluída e o SOL não pode ser recuperado. Sempre classifique o destinatário antes de assinar uma transferência de SOL.
Fluxo de Verificação
O diagrama a seguir mostra uma árvore de decisão de referência para validar um endereço:
Buscar conta
Use o endereço para buscar os detalhes da conta na rede.
Conta inexistente
Se nenhuma conta existir neste endereço, verifique se o endereço está na curva ou fora da curva:
-
Fora da curva (PDA): Exija verificação explícita do destinatário antes de criar um ATA ou enviar SPL tokens. Sem uma conta existente, não é possível determinar apenas pelo endereço qual programa originou este PDA ou se o programa do destinatário consegue acessar seu ATA.
-
Na curva: Este é um endereço de carteira válido (chave pública) que ainda não foi financiado. Derive o ATA, verifique se ele existe e envie os tokens para ele. Você deve tomar uma decisão de política sobre financiar a criação do ATA caso ele não exista.
Conta existente
Se uma conta existir, verifique qual programa é seu proprietário:
-
System Program: Esta é uma carteira padrão. Derive o ATA, verifique se ele existe e envie os tokens para ele. Você deve tomar uma decisão de política sobre financiar a criação do ATA caso ele não exista.
-
Token Program / Token-2022: Verifique se a conta é um token account (não um mint account) e se ela contém o token (mint) que você pretende enviar. Se válido, envie os tokens diretamente para este endereço. Se for um mint account ou um token account de um mint diferente, rejeite o endereço.
-
Outro Programa: Programas como carteiras multisig são proprietários aceitáveis de token accounts. Exija que o usuário confirme que pretende enviar para uma smart wallet.
Algumas smart wallets comuns:
| Carteira | Endereço do Programa |
|---|---|
| Squads | SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf |
| Swig | swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB |
Demo
O exemplo a seguir mostra apenas a lógica de validação de endereço. Este é um código de referência para fins ilustrativos.
A demo não mostra como derivar um ATA ou construir uma transação para enviar tokens. Consulte a documentação de token account e transferência de tokens para exemplos de código.
A demo abaixo usa três resultados possíveis:
| Resultado | Significado | Ação |
|---|---|---|
IS_WALLET | Endereço de carteira válido | Derive e envie para o associated token account |
IS_TOKEN_ACCOUNT | Token account válido | Envie tokens diretamente para este endereço |
USER_VERIFICATION | Endereço requer confirmação do destinatário | Exigir revisão explícita antes de enviar SPL tokens ou financiar um ATA |
REJECT | Endereço inválido | Não enviar |
Em seguida, cada resultado é mapeado para a aceitabilidade por ativo com
canReceiveNativeSol (apenas carteiras) e canReceiveSplToken (carteiras ou
token accounts). Um resultado USER_VERIFICATION não é aceito automaticamente;
sua aplicação deve solicitar que o usuário confirme sua intenção antes de
enviar SPL tokens. Um token account retorna IS_TOKEN_ACCOUNT, portanto pode
receber SPL tokens, mas não SOL nativo — a distinção que impede o SOL
de ser bloqueado.
/*** 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?