De trade afwikkelen

SettleDvp wordt ondertekend door de settlement authority die in het traderecord staat. In eé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, geeft ze eventueel overschot in een van beide escrows terug aan de partij van die leg en sluit ze het record en beide escrows. Als een van die overdrachten niet kan worden voltooid, mislukt de instructie en wordt er niets verplaatst.

Deze pagina sluit aan op een trade aanmaken en de legs financieren; de client, signers, trade en de token accounts van de partijen worden overgenomen.

Opnieuw valideren voor het ondertekenen

De settlement authority ondertekent de transactie die beide legs verplaatst, dus voert ze dezelfde controle uit als elke partij voordat ze ondertekent: eigenaar, grootte, partijen, mints, bedragen, vervaldatum en beide bestemmingen (zie de legs financieren). Het programma zelf controleert bij de afwikkeling 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 token accounts van de ontvangers aanmaken

Settle schrijft naar vier token accounts die het programma niet 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 token accounts voor het overschot worden alleen gebruikt wanneer een escrow meer bevat dan het afgesproken bedrag, maar iedereen die tokens van de mint bezit kan een overschot creëren door een paar basis- eenheden naar de escrow te sturen. Als het token account voor de terugbetaling niet bestaat, mislukt de hele Settle, dus maak 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,
}),
);

Afwikkelen

legAExtrasCount geeft het programma aan hoeveel van de accounts die na de vaste lijst zijn toegevoegd bij de transfer hook van de assetleg horen; de rest is voor die van de cashleg. Geef voor mints zonder transfer hooks nul door en voeg niets toe. Het memo program account is vereist voor 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 hookprogramma en het validatieaccount; de accountlimiet van de transactie kan eerder worden bereikt wanneer beide legs hooks hebben. Het programma verwijdert de signer-vlag van elk doorgestuurd account, zodat een hook via dit pad niet de handtekening van de settlement authority 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 uitlezing 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 token account voor de bestemming of terugbetaling ontbreekt of niet meer van de verwachte eigenaar en mint is, meestal omdat de bovenstaande stap voor het aanmaken van accounts is overgeslagen. In elk geval 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.