Enviar tokens a la dirección incorrecta puede resultar en la pérdida permanente de fondos. La verificación de direcciones garantiza que solo envíes tokens a direcciones que puedan recibirlos y acceder a ellos correctamente.
Consulta Cómo funcionan los pagos en Solana para conocer los conceptos básicos de pagos.
Comprender las direcciones de Solana
Las cuentas de Solana tienen dos tipos de direcciones: en curva y fuera de curva.
Direcciones en curva
Las direcciones estándar son las claves públicas de pares de claves Ed25519. Estas direcciones:
- Tienen una clave privada correspondiente que puede firmar transacciones
- Se utilizan como direcciones de billetera
Direcciones fuera de curva (PDA)
Las direcciones derivadas de programa 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 cual se derivó la dirección
Tipos de cuenta en pagos
Utiliza la dirección para obtener una cuenta de la red, verifica su propietario de programa y tipo de cuenta para determinar cómo manejar la dirección.
Saber si una dirección está en curva o fuera de curva no te indica qué tipo de cuenta es, qué programa la posee o si existe una cuenta en esa dirección. Debes obtener la cuenta de la red para determinar estos detalles.
Cuentas del System Program (billeteras)
Las cuentas propiedad del System Program son billeteras estándar. Para enviar tokens SPL a una billetera, debes derivar y usar su cuenta de token asociada (ATA).
Después de derivar la dirección ATA, verifica si la token account existe en cadena. Si la ATA no existe, puedes incluir una instrucción para crear la token account del destinatario en la misma transacción que la transferencia. Sin embargo, esto requiere pagar rent por la nueva token account. Dado que el destinatario posee la ATA, el SOL pagado por el rent no puede ser recuperado por el remitente.
Sin salvaguardas, subsidiar la creación de ATA puede ser explotado. Un usuario malicioso podría solicitar una transferencia, hacer que su ATA se cree a tu costa, cerrar la ATA para reclamar el SOL de rent y repetir el proceso.
Token accounts
Las token accounts son propiedad del Token Program o Token-2022 Program y contienen saldos de tokens. Si la dirección que recibes es propiedad de un token program, debes verificar que la cuenta sea una token account (no una mint account) y coincida con la mint account de token esperada antes de enviar.
Los Token Programs validan automáticamente que ambas token accounts en una transferencia contengan tokens del mismo mint. Si la validación falla, la transacción se rechaza y no se pierden fondos.
Mint accounts
Las mint accounts rastrean el suministro de tokens y los metadatos de un token específico. Las 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 de mint resulta en una transacción fallida, pero no se pierden fondos.
Otras cuentas
Las cuentas propiedad de otros programas requieren una decisión de política. Algunas cuentas (por ejemplo, wallets multifirma) pueden ser propietarios válidos de token accounts, mientras que otras deben ser rechazadas.
Flujo de verificación
El siguiente diagrama muestra un árbol de decisión de referencia para validar una dirección:
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, verifica si la dirección está on-curve o off-curve:
-
Fuera de la curva (PDA): rechaza conservadoramente la dirección para evitar enviar a una ATA que pueda ser inaccesible. Sin una cuenta existente, no puedes determinar solo desde la dirección qué programa derivó este PDA o si la dirección es para una ATA. Derivar una ATA para esta dirección para enviar tokens podría resultar en fondos bloqueados en una cuenta de tokens inaccesible.
-
En la curva: esta es una dirección de billetera válida (clave pública) que aún no ha sido financiada. Deriva la ATA, verifica si existe y envía tokens a ella. Debes tomar una decisión de política sobre si financiar la creación de la ATA si no existe.
La cuenta existe
Si existe una cuenta, verifica qué programa la posee:
-
System Program: esta es una billetera estándar. Deriva la ATA, verifica si existe y envía tokens a ella. Debes tomar una decisión de política sobre si financiar la creación de la ATA si no existe.
-
Token Program / Token-2022: verifica que la cuenta sea una cuenta de tokens (no una mint account) y que contenga el token (mint) que pretendes enviar. Si es válida, envía tokens directamente a esta dirección. Si es una mint account o una cuenta de tokens para un mint diferente, rechaza la dirección.
-
Otro programa: esto requiere una decisión de política. Algunos programas como billeteras multifirma pueden ser propietarios aceptables de cuentas de tokens. Si tu política lo permite, deriva la ATA y envía. De lo contrario, rechaza la dirección.
Demo
El siguiente ejemplo muestra solo la lógica de validación de direcciones. Este es código de referencia con fines ilustrativos.
La demostración no muestra cómo derivar una ATA o construir una transacción para enviar tokens. Consulta la documentación de cuenta de token y transferencia de tokens para ver código de ejemplo.
La demostración a continuación utiliza tres posibles resultados:
| Resultado | Significado | Acción |
|---|---|---|
IS_WALLET | Dirección de billetera válida | Derivar y enviar a la associated token account |
IS_TOKEN_ACCOUNT | Token account válida | Enviar tokens directamente a esta dirección |
REJECT | Dirección inválida | No enviar |
/*** 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?