정산 없이 자금을 반환하는 명령어는 네 가지입니다. 거래가 열려 있는 동안에는 Reclaim, Cancel, Reject를 사용하고, 거래가 종료된 후 도착한 입금에는 Recover를 사용합니다. 이 중 어느 것도 만료 시간을 확인하지 않습니다. 동결된 에스크로나 변경된 mint 때문에 레그가 계속 묶여 있을 수 있으며, 이는 끝부분의 참고 사항에서 설명합니다.
| 명령어 | 서명자 | 범위 | 이후 거래 상태 |
|---|---|---|---|
ReclaimDvp | user_a 또는 user_b | 서명자 본인의 레그 | 계속 열려 있음 |
CancelDvp | 정산 권한자 | 양쪽 레그 | 종료됨 |
RejectDvp | user_a 또는 user_b | 양쪽 레그 | 종료됨 |
RecoverDvp | user_a 또는 user_b | 종료 후 서명자의 레그 | 이미 종료됨 |
각 경우 에스크로에 들어 있는 자산은 모두 해당 레그의 당사자에게 반환됩니다.
에스크로 A는 user_a의 mint_a용 token account로, 에스크로 B는 user_b의 mint_b용 token account로
반환되며, 누가 입금했는지는 상관없습니다. 메모가 필요한 환불 계정을 위해 memo program account를 함께 제공합니다.
이 페이지는 이전 단계에서 이어집니다. 거래 생성의 클라이언트와 서명자,
레그 입금의 userAAtaA와 userBAtaB,
거래 정산의 MEMO_PROGRAM_ID와 authority를 그대로 사용합니다.
레그 회수하기
Reclaim은 서명자의 레그를 반환하고 거래는 열린 상태로 유지하므로, 해당 레그에 다시 입금할 수 있습니다. 문제가 상대방의 레그에 있을 때 사용하세요. Cancel과 Reject는 거래 전체를 종료합니다.
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]);
취소 또는 거부
Cancel은 정산 권한자가, Reject는 어느 한쪽 당사자가 서명합니다. 둘 다 각 에스크로에 들어 있는 자산을 해당 레그의 당사자에게 환불하고, 레코드와 두 에스크로를 모두 종료하며, 종료된 계정의 rent는 서명자에게 돌아갑니다. 두 명령어는 동일한 계정을 사용하며 서명자만 다릅니다.
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,});
잔액이 있는 레그에는 환불 계정(userAAtaA, userBAtaB)이 반드시 존재해야 합니다. 초기화되지 않은 환불 계정은
토큰 전송을 실패시켜 명령어를 되돌립니다. 한 번도 입금되지 않은 레그는 전송이 필요 없으므로
계정이 없어도 됩니다.
늦은 입금 되찾기
Settle, Cancel, Reject는 모두 두 에스크로 token account를 종료하므로, 종료된 에스크로로의 일반 전송은 실패합니다. 종료 후 입금이 반영되려면 먼저 누군가 에스크로를 다시 생성해야 합니다. 예를 들어 전송에 앞서 create-idempotent associated token account 명령어를 포함한 입금 트랜잭션이 진행 중일 때 상대방이 Reject를 보낸 경우입니다. 이때 토큰은 거래가 더 이상 존재하지 않는 에스크로에 남게 됩니다. 레코드가 사라졌으므로 Reclaim은 이를 찾을 수 없고, nonce tombstone 때문에 같은 주소에 새 거래를 만들어 입금을 가로챌 수도 없습니다.
RecoverDvp를 사용하려면 레그의 당사자가 원래의 seed 입력값(정산 권한자, 양쪽 당사자, 양쪽 mint, nonce)을 제공해야 합니다.
프로그램은 레코드 주소를 다시 도출하고, 거래가 존재했다는 증거로 해당 tombstone을 요구하며,
에스크로의 자산을 서명자 본인의 token account로 옮긴 뒤 에스크로를 종료하고 에스크로 rent를 서명자에게 반환합니다.
서명자의 레그는 서명하는 당사자에 따라 결정됩니다. user_a는 mint_a, user_b는 mint_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]);
복구는 당사자가 생성 파라미터를 보관하고 있는지에 달려 있습니다. 거래에 자금을 입금하는 시스템은 거래가 종료되고 에스크로 잔액이 비어 있음이 확인될 때까지 각 주문과 함께 seed 입력값을 저장해 두어야 합니다.
참고 사항
- 동결된 레그. 게이트가 있는 mint에서는 에스크로가 동결되면 freeze authority가 동결을 해제할 때까지 이 명령어들이 수행하는 토큰 전송이 차단됩니다. 개요를 참고하세요.
- 생성 후 mint 변경. 되돌리기 경로는 확장 기능 및 mint authority 검사를 건너뛰어 프로그램 자체의 검사가 복구를 막지 않도록 합니다. token program 자체의 규칙은 그대로 적용됩니다. mint는 공급량이 0일 때만 종료할 수 있으므로 에스크로에 잔액이 있는 동안에는 변경될 수 없습니다. 하지만 mint가 종료된 후 NonTransferable로 또는 전송 수수료가 있는 형태로 다시 생성된 상태에서 늦은 입금이 도착하면, 그 입금은 이동할 수 없거나 수수료가 부과될 수 있습니다. 이것이 지원 토큰에 나열된 mint authority 의존성입니다.
다음 단계
- DvP 프로그램: 개요, 지원 토큰, mint 구성 제약 사항
- 위임을 사용한 Delivery vs Payment (DvP): 프로그램 없이 위임된 권한으로 수행하는 동일한 교환
Is this page helpful?