Regolare il trade

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:

AccountRiceveProprietario
userADestinationAtaBLa leg cash (amount_b)user_a_settlement_destination
userBDestinationAtaALa leg dell'asset (amount_a)user_b_settlement_destination
userAAtaAEventuale surplus sulla leg dell'assetuser_a
userBAtaBEventuale surplus sulla leg cashuser_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 userA
const destinationB = t.userBSettlementDestination; // defaults to userB
const [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

Is this page helpful?

Indice dei contenuti

Modifica pagina
© 2026 Solana Foundation. Tutti i diritti riservati.