Verificar dirección

Enviar fondos a una dirección incorrecta puede resultar en una pérdida permanente. La verificación de direcciones garantiza que tú y tus usuarios solo envíen a direcciones que puedan recibir y acceder a los fondos correctamente. Si operas un exchange, se recomienda ejecutar estas comprobaciones y pedir al usuario que verifique la dirección antes de enviar.

La validación depende de lo que envíes:

  • Los tokens SPL tienen cierta protección incorporada. El Token Program rechaza una transferencia cuyas cuentas no coincidan con el mint esperado, por lo que una transferencia de tokens mal dirigida falla sin perder fondos. La mayor parte de esta página abarca el envío de tokens SPL.
  • SOL nativo no cuenta con dicha protección. Una transferencia mediante el System Program se ejecuta exitosamente en cualquier cuenta, por lo que un destinatario incorrecto bloquea el SOL de forma permanente. Consulta Envío de SOL nativo.

Consulta Cómo funcionan los pagos en Solana para conocer los conceptos fundamentales sobre pagos.

Comprensión de las direcciones de Solana

Las cuentas de Solana tienen dos tipos de direcciones: dentro de la curva y fuera de la curva.

Direcciones dentro de la curva

Las direcciones estándar son las claves públicas de los keypairs Ed25519. Estas direcciones:

  • Tienen una clave privada correspondiente que puede firmar transacciones
  • Se utilizan como direcciones de billetera

Direcciones fuera de la curva (PDAs)

Los Program Derived Addresses se derivan de forma determinista a partir de un ID de programa y semillas. Estas direcciones:

  • No tienen una clave privada correspondiente
  • Solo pueden ser firmadas por el programa del que se derivó la dirección

Las carteras controladas por programas, comúnmente conocidas como smart wallets o smart accounts, tienen direcciones fuera de la curva. Esta guía utiliza el término "smart wallet" a lo largo de todo el documento.

Tipos de cuentas en pagos

Usa la dirección para obtener una cuenta de la red, verifica el propietario del programa y el tipo de cuenta para determinar cómo gestionar la dirección.

Saber si una dirección está dentro o fuera de la curva no te indica qué tipo de cuenta es, qué programa la posee ni si existe una cuenta en esa dirección. Debes obtener la cuenta de la red para determinar estos detalles.

Cuentas del System Program (Wallets)

Las cuentas propiadas por el System Program son wallets estándar. Para enviar tokens SPL a una wallet, debes derivar y utilizar su Associated Token Account (ATA).

Después de derivar la dirección ATA, verifica si el token account existe en la cadena. Si el ATA no existe, puedes incluir una instrucción para crear el token account del destinatario en la misma transacción que la transferencia. Sin embargo, esto requiere pagar rent por el nuevo token account. Dado que el destinatario es el propietario del ATA, el SOL pagado por el rent no puede ser recuperado por el remitente.

Las cuentas del sistema pueden existir fuera de la curva. Si tu usuario desea enviar tokens a una dirección fuera de la curva, se recomienda pedirle que verifique que tiene la intención de enviar fondos a un smart wallet.

Sin medidas de seguridad, subsidiar la creación de ATAs puede ser explotado. Un usuario malintencionado podría solicitar una transferencia, hacer que se cree su ATA a tu costa, cerrar el ATA para recuperar el rent SOL, y repetir el proceso.

Token Accounts

Los token accounts son propiedad del Token Program o Token-2022 Program y almacenan saldos de tokens. Si la dirección que recibes es propiedad de un token program, debes verificar que la cuenta sea un token account (no un mint account) y que coincida con el mint account del token esperado antes de enviar.

Los Token Programs validan automáticamente que ambos token accounts en una transferencia contengan tokens del mismo mint. Si la validación falla, la transacción es rechazada y no se pierden fondos.

Mint Accounts

Los mint accounts rastrean el suministro de tokens y los metadatos de un token específico. Los mint accounts también son propiedad de los Token Programs, pero no son destinatarios válidos para transferencias de tokens. Intentar enviar tokens a una dirección mint resulta en una transacción fallida, pero no se pierden fondos.

Otras Cuentas

Las cuentas que pertenecen a otros programas son válidas, pero están regidas por las reglas de autoridad establecidas por el programa propietario correspondiente. Se recomienda pedirle al usuario que verifique que tiene la intención de enviar fondos a un smart wallet.

Envío de SOL nativo

La clasificación anterior determina a dónde pueden ir los tokens SPL. El SOL nativo es más estricto: el único destinatario seguro es una billetera de System Program (o una dirección en curva sin fondos que se convierta en una).

Una transferencia de System Program agrega lamport a cualquier cuenta, incluidas las acuñaciones, token accounts, programas y PDAs. Los lamport solo pueden ser retirados por el programa propietario de la cuenta, por lo que enviar SOL a un destinatario incorrecto puede resultar en la pérdida permanente de fondos.

A diferencia de una transferencia de tokens SPL, la transacción no falla cuando el destinatario es una dirección inesperada.

Al enviar SOL nativo, solo un resultado IS_WALLET es aceptable. IS_TOKEN_ACCOUNT no lo es: un token account contiene tokens SPL, y el SOL enviado allí queda fuera del control del remitente.

Esta es una forma común en que se pierde SOL: un usuario pega la dirección de acuñación de un token (o una dirección de programa) en un retiro de SOL. La transferencia se realiza con éxito y el SOL es irrecuperable. Siempre clasifica al destinatario antes de firmar una transferencia de SOL.

Flujo de Verificación

El siguiente diagrama muestra un árbol de decisiones de referencia para validar una dirección:

Address Verification Flow

Obtener cuenta

Usa la dirección para obtener los detalles de la cuenta desde la red.

La cuenta no existe

Si no existe ninguna cuenta en esta dirección, comprueba si la dirección está en la curva o fuera de ella:

  • Fuera de la curva (PDA): Requiere verificación explícita del destinatario antes de crear un ATA o enviar tokens SPL. Sin una cuenta existente, no puedes determinar solo a partir de la dirección qué programa derivó este PDA ni si el programa del destinatario puede acceder a su ATA.

  • En la curva: Esta es una dirección de cartera válida (clave pública) que aún no ha sido financiada. Deriva el ATA, comprueba si existe y envía los tokens a él. Debes tomar una decisión de política sobre si financiar la creación del ATA en caso de que no exista.

La cuenta existe

Si existe una cuenta, comprueba qué programa la posee:

  • System Program: Esta es una cartera estándar. Deriva el ATA, comprueba si existe y envía los tokens a él. Debes tomar una decisión de política sobre si financiar la creación del ATA en caso de que no exista.

  • Token Program / Token-2022: Verifica que la cuenta sea un token account (no un mint account) y que contenga el token (mint) que deseas enviar. Si es válida, envía los tokens directamente a esta dirección. Si es un mint account o un token account para un mint diferente, rechaza la dirección.

  • Otro programa: Programas como las carteras multifirma son propietarios aceptables de token accounts. Pide al usuario que confirme que tiene la intención de enviar a un smart wallet.

    Algunos smart wallets comunes:

Demo

El siguiente ejemplo muestra únicamente la lógica de validación de direcciones. Este es código de referencia con fines ilustrativos.

La demo no muestra cómo derivar una ATA ni cómo construir una transacción para enviar tokens. Consulta la documentación de token account y transferencia de tokens para ver código de ejemplo.

La demo a continuación utiliza tres posibles resultados:

ResultadoSignificadoAcción
IS_WALLETDirección de billetera válidaDeriva y envía al associated token account
IS_TOKEN_ACCOUNTToken account válidoEnvía tokens directamente a esta dirección
USER_VERIFICATIONLa dirección requiere confirmación del destinatarioRequiere revisión explícita antes de enviar tokens SPL o financiar un ATA
REJECTDirección inválidaNo enviar

Luego mapea cada resultado a la aceptabilidad por activo con canReceiveNativeSol (solo carteras) y canReceiveSplToken (carteras o token accounts). Un resultado USER_VERIFICATION no se acepta automáticamente; tu aplicación debe pedir al usuario que confirme su intención antes de enviar tokens SPL. Un token account devuelve IS_TOKEN_ACCOUNT, por lo que puede recibir tokens SPL pero no SOL nativo — la distinción que evita que el SOL quede bloqueado.

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?