SettleDvp wird von der im Trade-Datensatz genannten Abwicklungsstelle signiert. In
einer Transaktion überträgt es amount_a des Asset-Legs an das Ziel der
Cash-Leg-Partei und amount_b des Cash-Legs an das Ziel der Asset-Leg-Partei,
gibt jeden Überschuss in einem der beiden Escrows an die Partei des jeweiligen Legs zurück und schließt den Datensatz
sowie beide Escrows. Kann eine dieser Überweisungen nicht abgeschlossen werden, schlägt die Anweisung
fehl und es wird nichts bewegt.
Diese Seite knüpft an Einen Trade erstellen
und Die Legs finanzieren an; Client, Signer,
trade und die token account der Parteien werden übernommen.
Vor dem Signieren erneut validieren
Die Abwicklungsstelle signiert die Transaktion, die beide Legs überträgt, und führt daher vor dem Signieren denselben Lesevorgang durch wie jede Partei: Eigentümer, Größe, Parteien, Mints, Beträge, Ablauf und beide Ziele (siehe Die Legs finanzieren). Das Programm selbst prüft bei der Abwicklung erneut, dass jeder Mint weiterhin zu dem bei der Erstellung erfassten Token Program gehört, keine gesperrte Erweiterung enthält und dieselbe Mint Authority hat wie bei der Erstellung des Trades. Ein Mint, der mit einer gesperrten Erweiterung, einem anderen Token Program oder einer anderen Mint Authority neu erstellt wurde, kann daher nicht abgewickelt werden.
Die Empfängerkonten erstellen
Settle schreibt in vier token account, die das Programm nicht erstellt:
| Konto | Empfängt | Eigentümer |
|---|---|---|
userADestinationAtaB | Das Cash-Leg (amount_b) | user_a_settlement_destination |
userBDestinationAtaA | Das Asset-Leg (amount_a) | user_b_settlement_destination |
userAAtaA | Jeden Überschuss im Asset-Leg | user_a |
userBAtaB | Jeden Überschuss im Cash-Leg | user_b |
Die Überschusskonten werden nur verwendet, wenn ein Escrow mehr als den vereinbarten Betrag enthält. Allerdings kann jeder, der den Mint besitzt, einen Überschuss erzeugen, indem er ein paar Basis einheiten in den Escrow sendet. Existiert das Rückerstattungskonto nicht, schlägt der gesamte Settle fehl. Erstellen Sie daher alle vier idempotent in derselben Transaktion.
import {findAssociatedTokenPda,getCreateAssociatedTokenIdempotentInstruction,} from "@solana-program/token-2022";const destinationA = t.userASettlementDestination; // defaults to userAconst destinationB = t.userBSettlementDestination; // defaults to userBconst [userADestinationAtaB] = await findAssociatedTokenPda({mint: mintB,owner: destinationA,tokenProgram: tokenProgramB,});const [userBDestinationAtaA] = await findAssociatedTokenPda({mint: mintA,owner: destinationB,tokenProgram: tokenProgramA,});// userAAtaA and userBAtaB are from fund the legs.const createRecipientAccounts = [{ ata: userADestinationAtaB, owner: destinationA, mint: mintB, tokenProgram: tokenProgramB },{ ata: userBDestinationAtaA, owner: destinationB, mint: mintA, tokenProgram: tokenProgramA },{ ata: userAAtaA, owner: userA, mint: mintA, tokenProgram: tokenProgramA },{ ata: userBAtaB, owner: userB, mint: mintB, tokenProgram: tokenProgramB },].map(({ ata, owner, mint, tokenProgram }) =>getCreateAssociatedTokenIdempotentInstruction({payer: authoritySigner,ata,owner,mint,tokenProgram,}),);
Settle
legAExtrasCount teilt dem Programm mit, wie viele der nach der
festen Liste angehängten Konten zum Transfer Hook des Asset-Legs gehören; der Rest gehört zu dem
des Cash-Legs. Übergeben Sie für Mints ohne Transfer Hooks null und hängen Sie nichts an. Das Memo-
program account ist für die Anweisung erforderlich und wird nur für Ziele verwendet,
die ein Memo verlangen.
import { MEMO_PROGRAM_ADDRESS } from "@solana-program/memo";import { getSettleDvpInstruction } from "./dvp";const settleInstruction = getSettleDvpInstruction({settlementAuthority: authoritySigner,swapDvp,mintA,mintB,dvpAtaA: escrowA,dvpAtaB: escrowB,userADestinationAtaB,userBDestinationAtaA,userAAtaA,userBAtaB,tokenProgramA,tokenProgramB,memoProgram: MEMO_PROGRAM_ADDRESS,legAExtrasCount: 0,});const { context: settleContext } = await client.sendTransaction([...createRecipientAccounts,settleInstruction,]);const settleSignature = settleContext.signature;console.log("Submitted:", settleSignature);// sendTransaction returns at the client's commitment (confirmed by default).// Wait for finalized before recording the trade as settled.let finalized = false;for (let attempt = 0; attempt < 30 && !finalized; attempt++) {const {value: [status],} = await client.rpc.getSignatureStatuses([settleSignature]).send();if (status?.err) {throw new Error("Settle transaction failed");}finalized = status?.confirmationStatus === "finalized";if (!finalized) {await new Promise((resolve) => setTimeout(resolve, 2_000));}}if (!finalized) {// A closed record means it settled; an open one is safe to settle again.throw new Error("Settle not finalized after 60s; read the trade record");}console.log("Settled:", settleSignature);
Transfer Hooks
Die generierte IDL listet nur die festen Konten auf, daher kennen die generierten Builder
keine Hook-Konten. Lösen Sie die zusätzlichen Account-Metas jedes Hook-Mints auf die
gleiche Weise auf wie bei einem direkten Transfer dieses Tokens und hängen Sie sie dann an die
Anweisung an: zuerst die Konten des Asset-Legs, dann die des Cash-Legs, wobei
legAExtrasCount auf die Anzahl in der ersten Gruppe gesetzt wird. In TypeScript fügen Sie
die aufgelösten Metas per Spread in das accounts-Array der Anweisung ein; in Rust verwenden Sie
add_remaining_accounts am Builder. Das Limit liegt bei 32 Konten pro Leg,
einschließlich des Hook-Programms und des Validierungskontos; das Konten-Limit der Transaktion
kann zuerst greifen, wenn beide Legs Hooks haben. Das Programm entfernt das Signer-Flag
von jedem weitergeleiteten Konto, sodass ein Hook auf diesem Weg nicht die
Signatur der Abwicklungsstelle erlangen kann.
Das Ergebnis erfassen
Betrachten Sie den Trade als abgewickelt, wenn die Settle-Transaktion finalized erreicht. Der
Datensatz und beide Escrows existieren nach der Abwicklung nicht mehr. Ein System, das
die Bedingungen später benötigt, speichert sie daher aus seinem Lesevorgang vor der Abwicklung oder aus der
erstellenden Transaktion. Die rent der geschlossenen Konten ist an die Abwicklungsstelle
gegangen.
Settle-Fehler
LegNotFunded bedeutet, dass ein Escrow weniger als den vereinbarten Betrag enthält; DvpExpired
und SettlementTooEarly bedeuten, dass das Zeitfenster verpasst wurde; MintAuthorityChanged
und BlockedMintExtension bedeuten, dass sich ein Mint nach der Erstellung geändert hat;
RecipientAtaMismatch bedeutet, dass ein Ziel- oder Rückerstattungs-token account fehlt oder
nicht mehr dem erwarteten Eigentümer und Mint gehört, meist weil der oben beschriebene
Schritt zum Erstellen der Konten übersprungen wurde. In jedem Fall wurde nichts bewegt, und die
Parteien können rückabwickeln, vorbehaltlich der Authorities des Mints (siehe
Einen Trade rückabwickeln).
Nächste Schritte
- Einen Trade rückabwickeln: finanzierte Legs zurückholen, wenn ein Trade nicht abgewickelt wird
Is this page helpful?