SettleDvp è firmata dall'autorità di regolamento indicata nel record del trade. In
una sola transazione sposta amount_a della leg dell'asset verso la destinazione
della parte della leg cash e amount_b della leg cash verso la destinazione della
parte della leg dell'asset, restituisce alla parte della leg l'eventuale surplus presente
in uno dei due escrow e chiude il record e entrambi gli escrow. Se anche solo uno di questi
trasferimenti non può essere completato, l'istruzione fallisce e nulla viene spostato.
Questa pagina prosegue da creare un trade
e finanziare le leg; il client, i firmatari,
trade e i token account delle parti restano gli stessi.
Riconvalidare prima di firmare
L'autorità di regolamento firma la transazione che sposta entrambe le leg, quindi effettua prima di firmare la stessa lettura di ciascuna parte: 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 il trade è 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 dei destinatari
Settle scrive su quattro token account che il programma non crea:
| Account | Riceve | Proprietario |
|---|---|---|
userADestinationAtaB | La leg cash (amount_b) | user_a_settlement_destination |
userBDestinationAtaA | La leg dell'asset (amount_a) | user_b_settlement_destination |
userAAtaA | Eventuale surplus sulla leg dell'asset | user_a |
userBAtaB | Eventuale surplus sulla leg cash | user_b |
Gli account per il surplus vengono usati solo quando un escrow contiene più dell'importo concordato, ma chiunque possieda il mint può creare un surplus inviando alcune unità base all'escrow. Se l'account di rimborso non esiste, l'intero Settle fallisce, quindi crea tutti e quattro 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,}),);
Settle
legAExtrasCount indica al programma quanti degli account aggiunti dopo l'elenco
fisso appartengono al transfer hook della leg dell'asset; i restanti appartengono a quello della leg
cash. Per i mint senza transfer hook, passa zero e non aggiungere nulla. Il
program account memo è 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 degli hook. Risolvi gli extra account meta di ciascun mint con hook nello
stesso modo in cui lo faresti per un trasferimento diretto di quel token, poi aggiungili
all'istruzione: prima gli account della leg dell'asset, poi quelli della leg cash, con
legAExtrasCount impostato al 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,
incluso 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
da ogni account inoltrato, quindi un hook non può ottenere la firma dell'autorità di regolamento
attraverso questo percorso.
Registrare il risultato
Considera il trade regolato quando la transazione Settle raggiunge finalized. Il
record e i due 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. Il rent degli account chiusi è andato all'autorità
di regolamento.
Errori di Settle
LegNotFunded indica che un escrow contiene meno del proprio importo concordato; DvpExpired
e SettlementTooEarly indicano che la finestra temporale è stata mancata; MintAuthorityChanged
e BlockedMintExtension indicano che un mint è cambiato dopo la creazione;
RecipientAtaMismatch indica che un token account di destinazione o di rimborso manca oppure
non appartiene più al proprietario e al mint previsti, di solito perché il passaggio di
creazione degli account descritto sopra è stato saltato. In ogni caso nulla è stato spostato e le
parti possono annullare l'operazione, nel rispetto delle autorità del mint (vedi
annullare un trade).
Passaggi successivi
- Annullare un trade: recuperare le leg finanziate quando un trade non viene regolato
Is this page helpful?