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 del
registro de la operación antes de fondear necesita 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 el registro 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
del registro y del mint únicamente, nunca de los términos. Por lo tanto, una transferencia a un escrow puede
llegar con 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, compará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 lo creó tu contraparte o la autoridad de liquidación, compara cada campo con los términos que acordaste fuera del ledger. Si lo creaste tú mismo, esta lectura confirma que llegó tal como se envió.
Transfiere al escrow
Fondea el tramo exactamente por el importe acordado. El programa limita la liquidación a
amount_x y devuelve cualquier excedente a la parte del tramo, por lo que un excedente no se pierde,
pero añade una segunda transferencia en la liquidación y puede fallar con algunos hooks de
transferencia (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 un hook de transferencia necesita que las
cuentas del hook se resuelvan y se añadan igual que en cualquier otra transferencia de ese
token.
La parte del tramo de 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 contra 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. El programa lee el saldo de un escrow nativo después de sincronizarlo, por lo que los lamports enviados a un escrow de SOL envuelto 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 quien cierre la cuenta.
- Mints con restricciones. En un mint con Default Account State congelado, el escrow se crea congelado y la transferencia falla hasta que el emisor lo descongele o lo admita. La visión general describe la interacción con Token ACL.
- Hooks de transferencia. Fondea los escrows con hook exactamente por 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 y un 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 revertir una operación. - Quién fondea primero. El programa no establece un orden entre los dos tramos. El orden lo deciden 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 hook de transferencia) bloquee el escrow.
Próximos pasos
- Liquidar la operación: la autoridad de liquidación intercambia ambos tramos en una sola transacción
- Revertir una operación: recuperar un tramo fondeado cuando la operación no se liquida
Is this page helpful?