SettleDvp è firmata dalla settlement authority indicata nel record dello scambio. In
un'unica transazione sposta amount_a della leg dell'asset verso la destinazione
della parte della leg in denaro e amount_b della leg in denaro verso la destinazione
della parte della leg dell'asset, restituisce l'eventuale eccedenza di ciascun escrow
alla parte della rispettiva leg e chiude il record e entrambi gli escrow. Se anche uno solo
di questi trasferimenti non può essere completato, l'istruzione
fallisce e nulla viene spostato.
Questa pagina prosegue da creare uno scambio
e finanziare le leg; il client, i firmatari,
trade e i token account delle parti restano gli stessi.
Rivalidare prima di firmare
La settlement authority firma la transazione che sposta entrambe le leg, quindi effettua la stessa lettura di ciascuna parte prima di firmare: proprietario, dimensione, parti, mint, importi, scadenza ed entrambe le destinazioni (vedi finanziare le leg). Il programma stesso ricontrolla al momento del regolamento che ogni mint appartenga ancora al token program registrato alla creazione, non abbia estensioni bloccate e abbia la stessa mint authority di quando lo scambio è stato creato, quindi un mint ricreato con un'estensione bloccata, un token program diverso o una mint authority diversa non può essere regolato.
Creare gli account destinatari
L'istruzione Settle scrive su quattro token account che il programma non crea:
| Account | Riceve | Proprietario |
|---|---|---|
userADestinationAtaB | La leg in denaro (amount_b) | user_a_settlement_destination |
userBDestinationAtaA | La leg dell'asset (amount_a) | user_b_settlement_destination |
userAAtaA | Eventuale eccedenza sulla leg dell'asset | user_a |
userBAtaB | Eventuale eccedenza sulla leg in denaro | user_b |
Gli account per le eccedenze vengono usati solo quando un escrow contiene più dell'importo concordato, ma chiunque possieda il mint può creare un'eccedenza inviando qualche unità base all'escrow. Se l'account di rimborso non esiste, l'intera istruzione Settle fallisce, quindi crea tutti e quattro gli account in modo idempotente nella stessa transazione.
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,}),);
Regolamento
legAExtrasCount indica al programma quanti degli account aggiunti dopo l'elenco
fisso appartengono al transfer hook della leg dell'asset; i restanti vanno a quello della
leg in denaro. Per i mint senza transfer hook, passa zero e non aggiungere nulla. Il memo
program account è richiesto dall'istruzione e viene usato solo per le destinazioni
che richiedono un memo.
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 hook
L'IDL generato elenca solo gli account fissi, quindi i builder generati
non conoscono gli account dei hook. Risolvi i meta degli account aggiuntivi di ciascun mint con hook
nello stesso modo in cui lo faresti per un trasferimento diretto di quel token, quindi aggiungili
all'istruzione: prima gli account della leg dell'asset, poi quelli della leg in denaro, con
legAExtrasCount impostato sul numero del primo gruppo. In TypeScript, espandi
i meta risolti nell'array accounts dell'istruzione; in Rust, usa
add_remaining_accounts sul builder. Il limite è di 32 account per leg,
compresi il programma hook e l'account di validazione; il limite di account della transazione
può essere raggiunto per primo quando entrambe le leg hanno hook. Il programma rimuove il flag di firmatario
di ogni account inoltrato, quindi un hook non può ottenere la firma
della settlement authority attraverso questo percorso.
Registrare il risultato
Considera lo scambio regolato quando la transazione Settle raggiunge lo stato finalized. Il
record e entrambi gli escrow non esistono più dopo il regolamento, quindi un sistema che abbia bisogno
dei termini in seguito li memorizza dalla lettura precedente al regolamento o dalla
transazione di creazione. La rent degli account chiusi è stata trasferita alla settlement
authority.
Errori di regolamento
LegNotFunded significa che un escrow contiene meno dell'importo concordato; DvpExpired
e SettlementTooEarly significano che la finestra temporale è stata mancata; MintAuthorityChanged
e BlockedMintExtension significano che un mint è cambiato dopo la creazione;
RecipientAtaMismatch significa che un token account di destinazione o di rimborso manca oppure
non appartiene più al proprietario e al mint previsti, di solito perché il
passo di creazione degli account indicato sopra è stato saltato. In ogni caso nulla è stato spostato e le
parti possono annullare lo scambio, nei limiti delle authority del mint (vedi
annullare uno scambio).
Passi successivi
- Annullare uno scambio: recuperare le leg finanziate quando uno scambio non viene regolato
Is this page helpful?