De trade afwikkelen

SettleDvp wordt ondertekend door de settlement authority die in het traderecord is vermeld. In één transactie verplaatst de instructie amount_a van de assetleg naar de bestemming van de partij van de cashleg en amount_b van de cashleg naar de bestemming van de partij van de assetleg, stort ze eventueel overschot in beide escrows terug aan de partij van die leg en sluit ze het record en beide escrows. Als een van deze overdrachten niet kan worden voltooid, mislukt de instructie en wordt er niets verplaatst.

Deze pagina vervolgt op een trade aanmaken en de legs funden; de client, de ondertekenaars, trade en de token accounts van de partijen blijven hetzelfde.

Opnieuw valideren voordat je ondertekent

De settlement authority ondertekent de transactie die beide legs verplaatst, dus ze voert dezelfde controle uit als elke partij voordat ze ondertekent: eigenaar, grootte, partijen, mints, bedragen, vervaldatum en beide bestemmingen (zie de legs funden). Het programma controleert bij de afwikkeling zelf opnieuw of elke mint nog steeds bij het token program hoort dat bij het aanmaken is vastgelegd, geen geblokkeerde extensie bevat en dezelfde mint authority heeft als toen de trade werd aangemaakt. Een mint die opnieuw is aangemaakt met een geblokkeerde extensie, een ander token program of een andere mint authority kan dus niet worden afgewikkeld.

De ontvangende accounts aanmaken

Settle schrijft naar vier token accounts die het programma niet zelf aanmaakt:

AccountOntvangtEigenaar
userADestinationAtaBDe cashleg (amount_b)user_a_settlement_destination
userBDestinationAtaADe assetleg (amount_a)user_b_settlement_destination
userAAtaAEventueel overschot op de assetleguser_a
userBAtaBEventueel overschot op de cashleguser_b

De overschotaccounts worden alleen gebruikt wanneer een escrow meer bevat dan het afgesproken bedrag, maar iedereen die de mint bezit kan een overschot creëren door een paar basis- eenheden naar de escrow te sturen. Als het terugbetalingsaccount niet bestaat, mislukt de hele Settle. Maak daarom alle vier idempotent aan in dezelfde transactie.

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 geeft het programma aan hoeveel van de accounts die na de vaste lijst worden toegevoegd bij de transfer hook van de assetleg horen; de rest hoort bij die van de cashleg. Geef voor mints zonder transfer hooks nul door en voeg niets toe. Het memo program account is vereist door de instructie en wordt alleen gebruikt voor bestemmingen die een memo vereisen.

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

De gegenereerde IDL vermeldt alleen de vaste accounts, dus de gegenereerde builders kennen de hook-accounts niet. Bepaal de extra account metas van elke hook-mint op dezelfde manier als bij een directe overdracht van dat token en voeg ze vervolgens toe aan de instructie: eerst de accounts van de assetleg, dan die van de cashleg, waarbij legAExtrasCount is ingesteld op het aantal in de eerste groep. Spreid in TypeScript de bepaalde metas over de accounts-array van de instructie; gebruik in Rust add_remaining_accounts op de builder. De limiet is 32 accounts per leg, inclusief het hook-programma en het validatieaccount; de accountlimiet van de transactie kan eerder gelden wanneer beide legs hooks hebben. Het programma verwijdert de signer-vlag van elk doorgestuurd account, zodat een hook via dit pad de handtekening van de settlement authority niet kan verkrijgen.

Het resultaat vastleggen

Beschouw de trade als afgewikkeld wanneer de Settle-transactie finalized bereikt. Het record en beide escrows bestaan na de afwikkeling niet meer, dus een systeem dat de voorwaarden later nodig heeft, slaat ze op vanuit de controle vóór de afwikkeling of vanuit de aanmaaktransactie. De rent van de gesloten accounts is naar de settlement authority gegaan.

Settle-fouten

LegNotFunded betekent dat een escrow minder bevat dan het afgesproken bedrag; DvpExpired en SettlementTooEarly betekenen dat het tijdvenster is gemist; MintAuthorityChanged en BlockedMintExtension betekenen dat een mint na het aanmaken is gewijzigd; RecipientAtaMismatch betekent dat een bestemmings- of terugbetalings-token account ontbreekt of niet langer van de verwachte eigenaar en mint is, meestal doordat de stap voor het aanmaken van accounts hierboven is overgeslagen. In alle gevallen is er niets verplaatst en kunnen de partijen de trade terugdraaien, afhankelijk van de authorities van de mint (zie een trade terugdraaien).

Volgende stappen

Is this page helpful?

Inhoudsopgave

Pagina Bewerken
© 2026 Solana Foundation. Alle rechten voorbehouden.