Revertir una operación

Cuatro instrucciones devuelven fondos sin liquidar: Reclaim, Cancel y Reject mientras la operación está abierta, y Recover para un depósito que llega después de que se haya cerrado. Ninguna comprueba la expiración. Un escrow congelado o un mint modificado todavía puede retener un tramo, como describen las notas del final.

InstrucciónFirmanteAlcanceOperación después
ReclaimDvpuser_a o user_bEl tramo del propio firmanteSigue abierta
CancelDvpAutoridad de liquidaciónAmbos tramosCerrada
RejectDvpuser_a o user_bAmbos tramosCerrada
RecoverDvpuser_a o user_bEl tramo del firmante, tras el cierreYa cerrada

En cada caso, el escrow se vacía hacia la parte del tramo con todo lo que contenga: el escrow A a la token account de user_a para mint_a, y el escrow B a la de user_b para mint_b, sin importar quién lo fondeó. El program account de memo se proporciona para las cuentas de reembolso que requieren un memo.

Esta página continúa desde los pasos anteriores: el cliente y los firmantes de crear una operación, userAAtaA y userBAtaB de fondear los tramos, y MEMO_PROGRAM_ID y authority de liquidar la operación se mantienen.

Reclamar un tramo

Reclaim devuelve el tramo del firmante y deja la operación abierta, de modo que el tramo pueda fondearse de nuevo. Úsalo cuando el problema esté en el tramo de la contraparte; Cancel y Reject cierran toda la operación.

import { MEMO_PROGRAM_ADDRESS } from "@solana-program/memo";
import { getReclaimDvpInstruction } from "./dvp";
// The asset-leg party takes its asset back.
const reclaimInstruction = getReclaimDvpInstruction({
signer: userASigner,
swapDvp,
mint: mintA,
dvpSourceAta: escrowA,
signerDestAta: userAAtaA,
tokenProgram: tokenProgramA,
memoProgram: MEMO_PROGRAM_ADDRESS,
});
await client.sendTransaction([reclaimInstruction]);

Cancelar o rechazar

Cancel lo firma la autoridad de liquidación y Reject, cualquiera de las partes. Ambas instrucciones reembolsan lo que contenga cada escrow a la parte del tramo y cierran el registro y ambos escrows, y el rent de las cuentas cerradas va al firmante. Las dos instrucciones toman las mismas cuentas; solo cambia el firmante.

import { getCancelDvpInstruction, getRejectDvpInstruction } from "./dvp";
const unwindAccounts = {
swapDvp,
mintA,
mintB,
dvpAtaA: escrowA,
dvpAtaB: escrowB,
userAAtaA,
userBAtaB,
tokenProgramA,
tokenProgramB,
memoProgram: MEMO_PROGRAM_ADDRESS,
legAExtrasCount: 0,
};
// Signed by the settlement authority:
const cancelInstruction = getCancelDvpInstruction({
settlementAuthority: authoritySigner,
...unwindAccounts,
});
// Or signed by either party:
const rejectInstruction = getRejectDvpInstruction({
signer: userBSigner,
...unwindAccounts,
});

Las cuentas de reembolso (userAAtaA, userBAtaB) deben existir para cualquier tramo que tenga saldo; una cuenta de reembolso sin inicializar hace que falle la transferencia de tokens y revierte la instrucción. Un tramo que nunca se fondeó no necesita transferencia y tolera una cuenta ausente.

Recuperar un depósito tardío

Settle, Cancel y Reject cierran ambas token accounts de escrow, por lo que una transferencia simple a un escrow cerrado falla. Un depósito solo llega después del cierre si algo recrea antes el escrow, por ejemplo una transacción de fondeo que incluya una instrucción de associated token account con creación idempotente antes de la transferencia y que estuviera en tránsito cuando la contraparte envió Reject. Entonces los tokens quedan en un escrow cuya operación ya no existe: el registro ya no está, por lo que Reclaim no puede encontrarlo, y el tombstone del nonce impide que se cree una nueva operación en la misma dirección y capture el depósito.

Para usar RecoverDvp, la parte del tramo proporciona los seed originales (autoridad de liquidación, ambas partes, ambos mints, nonce). El programa vuelve a derivar la dirección del registro, exige su tombstone como prueba de que la operación existió, vacía el escrow hacia la token account del propio firmante y lo cierra, devolviendo el rent del escrow al firmante. El tramo del firmante se elige según quién firma: mint_a para user_a, mint_b para user_b.

import { getAddressEncoder, getProgramDerivedAddress } from "@solana/kit";
import { DVP_SWAP_PROGRAM_PROGRAM_ADDRESS, getRecoverDvpInstruction } from "./dvp";
const [nonceTombstone] = await getProgramDerivedAddress({
programAddress: DVP_SWAP_PROGRAM_PROGRAM_ADDRESS,
seeds: ["nonce", getAddressEncoder().encode(swapDvp)],
});
const recoverInstruction = getRecoverDvpInstruction({
signer: userASigner,
swapDvp,
nonceTombstone,
mint: mintA,
dvpEscrowAta: escrowA,
signerDestAta: userAAtaA,
tokenProgram: tokenProgramA,
memoProgram: MEMO_PROGRAM_ADDRESS,
settlementAuthority,
userA,
userB,
mintA,
mintB,
nonce,
});
await client.sendTransaction([recoverInstruction]);

La recuperación depende de que la parte conserve los parámetros de creación. Un sistema que fondea operaciones almacena los seed de cada orden hasta que la operación se haya cerrado y se haya confirmado que los saldos de los escrows están vacíos.

Notas

  • Tramos congelados. En un mint con restricciones, un escrow congelado bloquea la transferencia de tokens que realizan estas instrucciones hasta que la autoridad de congelación lo descongele. Consulta la descripción general.
  • Cambios en el mint tras la creación. Las rutas de reversión omiten las comprobaciones de extensiones y de autoridad del mint para que las propias comprobaciones del programa no bloqueen una recuperación. Las reglas propias del Token Program siguen aplicándose. Un mint solo puede cerrarse con suministro cero, por lo que no puede cambiar mientras haya un saldo en el escrow, pero un mint cerrado y recreado como NonTransferable o con una comisión de transferencia antes de que llegue un depósito tardío puede hacer que ese depósito sea inmovible o esté sujeto a comisión. Esa es la dependencia de la autoridad del mint indicada en tokens compatibles.

Siguientes pasos

Is this page helpful?

Tabla de Contenidos

Editar Página