Fondear es un simple TransferChecked al escrow del tramo, por lo que cualquier billetera o sistema de
custodia que pueda enviar una transferencia de tokens puede fondear un tramo. Solo la lectura de
la cuenta de la operación antes de fondear requiere el cliente DvP. El programa comprueba los
saldos del escrow únicamente en la liquidación; nada verifica la transferencia cuando llega,
por lo que cada parte lee la cuenta de la operación antes de transferir.
Esta página continúa desde crear una operación; el cliente y los firmantes se mantienen.
Verifica los términos
Crear un registro no requiere permisos, y las direcciones de escrow se derivan únicamente del
registro y del mint, nunca de los términos. Por lo tanto, una transferencia a un escrow puede
llegar asociada a términos que nunca acordaste, incluidos destinos de liquidación
que redirigen los fondos de tu contraparte a una tercera dirección.
Antes de fondear, lee la cuenta SwapDvp y compárala con la operación
acordada.
verifySwapDvp en TypeScript y verify::decode_swap_dvp_account en Rust
confirman que la cuenta pertenece al programa DvP, tiene exactamente 458 bytes y
se encuentra en la dirección que derivan sus propios campos (fetchSwapDvpChecked realiza
solo las dos primeras comprobaciones). Los lectores simples fetchSwapDvp y decodeSwapDvp
no realizan ninguna de ellas. Las comprobaciones de partes, importes, plazos y destinos las
realiza quien llama, contrastándolas con la operación acordada.
import { unwrapOption } from "@solana/kit";import { verifySwapDvp } from "./dvp";const trade = await verifySwapDvp(client.rpc, swapDvp);const t = trade.data;const expectedAmountA = 1_000_000_000n;const expectedAmountB = 998_500_000n;const expectedEarliestSettlement: bigint | null = null; // as agreedconst expectedExpiry = 1_798_761_600n; // as agreed, unix secondsif (t.userA !== userA ||t.userB !== userB ||t.mintA !== mintA ||t.mintB !== mintB ||t.settlementAuthority !== settlementAuthority ||t.tokenProgramA !== tokenProgramA ||t.tokenProgramB !== tokenProgramB ||t.amountA !== expectedAmountA ||t.amountB !== expectedAmountB ||unwrapOption(t.earliestSettlementTimestamp) !== expectedEarliestSettlement ||t.expiryTimestamp !== expectedExpiry ||t.userASettlementDestination !== userA ||t.userBSettlementDestination !== userB) {throw new Error("Stored terms do not match the agreed trade; do not fund");}if (t.expiryTimestamp <= BigInt(Math.floor(Date.now() / 1000)) + 60n) {throw new Error("Trade expires too soon to fund safely");}
Si el registro fue creado por tu contraparte o por la autoridad de liquidación, compara cada campo con los términos que acordaste fuera del libro mayor. Si lo creaste tú mismo, esta lectura confirma que llegó tal como se envió.
Transferir al escrow
Fondea el tramo exactamente con el importe acordado. El programa limita la liquidación a
amount_x y devuelve cualquier excedente a la parte del tramo, por lo que el excedente no se pierde,
pero añade una segunda transferencia en la liquidación y puede fallar con algunos
transfer hooks (consulta las notas más abajo).
Usa TransferChecked, no un Transfer sin verificación. Los mints de Token-2022 con
extensiones que dependen de la mint account, como Pausable, rechazan una transferencia
que no la incluya, y un mint con transfer hook requiere que las cuentas del hook
se resuelvan y se añadan igual que en cualquier otra transferencia de ese
token.
La parte del tramo del activo, firmando como userASigner, fondea el escrow A:
import {findAssociatedTokenPda,getTransferCheckedInstruction,} from "@solana-program/token-2022";const [userAAtaA] = await findAssociatedTokenPda({mint: mintA,owner: userA,tokenProgram: tokenProgramA,});const [userBAtaB] = await findAssociatedTokenPda({mint: mintB,owner: userB,tokenProgram: tokenProgramB,});const fundAssetLeg = getTransferCheckedInstruction({source: userAAtaA,mint: mintA,destination: escrowA,authority: userASigner,amount: t.amountA,decimals: 6,}, { programAddress: tokenProgramA });await client.sendTransaction([fundAssetLeg]);
La parte del tramo de efectivo hace lo mismo para el escrow B con userBAtaB, mintB,
userBSigner, t.amountB y { programAddress: tokenProgramB }.
Una transferencia de fondeo vista en confirmed
aún puede ser reemplazada. El programa lee el saldo del escrow onchain en la
liquidación, por lo que un Settle enviado frente a una transferencia de fondeo que no llegó falla
con LegNotFunded y no se mueve nada; el costo es un Settle fallido y un reintento.
Considera un tramo como fondeado cuando su transferencia esté en finalized.
Notas
- Tramos de SOL envuelto (wrapped SOL). El programa lee el saldo de un escrow nativo tras sincronizarlo, por lo que los lamports enviados a un escrow de wrapped SOL mediante una transferencia del sistema se contabilizan. Nunca envíes SOL a un escrow de ningún otro mint: el programa no puede devolverlo, y va a parar a quien cierre la cuenta.
- Mints restringidos. En un mint con Default Account State en estado congelado, el escrow se crea congelado y la transferencia falla hasta que el emisor lo descongele o lo admita. La descripción general explica la interacción con Token ACL.
- Transfer hooks. Fondea los escrows con hooks exactamente con el importe acordado. Si un excedente obliga a un reembolso en la liquidación, el reembolso reutiliza las cuentas del hook del tramo con un destino e importe distintos, lo que algunos hooks rechazan. La recuperación consiste en Reclaim, volver a fondear con el importe exacto y liquidar de nuevo.
- Fondeo tras el vencimiento. Nada impide una transferencia después de
expiry_timestamp. Esta llega, la liquidación ya no es posible, y la parte del tramo la recupera con Reclaim mientras la operación está abierta o con Recover una vez cerrada. Consulta deshacer una operación. - Quién fondea primero. El programa no establece un orden entre los dos tramos. El orden depende de las partes; cualquiera de ellas puede reclamar su propio tramo en cualquier momento antes de la liquidación, salvo que una autoridad del mint (congelación, pausa o transfer hook) bloquee el escrow.
Próximos pasos
- Liquidar la operación: la autoridad de liquidación intercambia ambos tramos en una sola transacción
- Deshacer una operación: recuperar un tramo fondeado cuando la operación no se liquida
Is this page helpful?