SettleDvp est signée par l'autorité de règlement indiquée dans l'enregistrement de
l'opération. En une seule transaction, l'instruction transfère amount_a du volet des actifs vers la
destination de la partie du volet espèces et amount_b du volet espèces vers la destination de la partie
du volet des actifs, restitue tout excédent présent dans l'un ou l'autre escrow à la partie du volet concerné,
puis ferme l'enregistrement et les deux escrows. Si l'un de ces transferts ne peut pas aboutir, l'instruction
échoue et rien ne bouge.
Cette page fait suite à créer une opération
et financer les volets ; le client, les signataires,
trade et les token accounts des parties sont repris tels quels.
Revalider avant de signer
L'autorité de règlement signe la transaction qui déplace les deux volets ; elle effectue donc la même lecture que chaque partie avant de signer : propriétaire, taille, parties, mints, montants, expiration et les deux destinations (voir financer les volets). Le programme revérifie lui-même au moment du règlement que chaque mint appartient toujours au Token Program enregistré à la création, ne comporte aucune extension bloquée et possède la même autorité de mint qu'à la création de l'opération ; un mint recréé avec une extension bloquée, un autre Token Program ou une autre autorité de mint ne peut donc pas être réglé.
Créer les comptes destinataires
Settle écrit dans quatre token accounts que le programme ne crée pas :
| Compte | Reçoit | Propriétaire |
|---|---|---|
userADestinationAtaB | Le volet espèces (amount_b) | user_a_settlement_destination |
userBDestinationAtaA | Le volet des actifs (amount_a) | user_b_settlement_destination |
userAAtaA | Tout excédent du volet des actifs | user_a |
userBAtaB | Tout excédent du volet espèces | user_b |
Les comptes d'excédent ne sont utilisés que lorsqu'un escrow contient plus que le montant convenu, mais toute personne détenant le mint peut créer un excédent en envoyant quelques unités de base dans l'escrow. Si le token account de remboursement n'existe pas, l'ensemble de Settle échoue : créez donc les quatre de façon idempotente dans la même transaction.
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,}),);
Régler
legAExtrasCount indique au programme combien de comptes ajoutés après la
liste fixe appartiennent au transfer hook du volet des actifs ; les autres reviennent à celui du volet
espèces. Pour les mints sans transfer hook, passez zéro et n'ajoutez rien. Le
program account du programme memo est requis par l'instruction et n'est utilisé que pour les destinations
qui exigent un mémo.
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
L'IDL généré ne répertorie que les comptes fixes ; les builders générés
ne connaissent donc pas les comptes de hook. Résolvez les account metas supplémentaires de chaque mint avec hook
comme vous le feriez pour un transfert direct de ce token, puis ajoutez-les à
l'instruction : d'abord les comptes du volet des actifs, puis ceux du volet espèces, avec
legAExtrasCount défini sur le nombre de comptes du premier groupe. En TypeScript, étalez
les metas résolus dans le tableau accounts de l'instruction ; en Rust, utilisez
add_remaining_accounts sur le builder. La limite est de 32 comptes par volet,
y compris le programme de hook et le compte de validation ; la limite de comptes par transaction
peut être atteinte en premier lorsque les deux volets comportent des hooks. Le programme retire l'indicateur de signataire
de chaque compte transmis, de sorte qu'un hook ne peut pas obtenir la
signature de l'autorité de règlement par ce biais.
Enregistrer le résultat
Considérez l'opération comme réglée lorsque la transaction Settle atteint l'état finalized. L'enregistrement
et les deux escrows n'existent plus après le règlement ; un système qui a besoin
des conditions par la suite doit donc les conserver à partir de sa lecture avant règlement ou de la transaction
de création. Le rent des comptes fermés a été versé à l'autorité de
règlement.
Erreurs de règlement
LegNotFunded signifie qu'un escrow contient moins que le montant convenu ; DvpExpired
et SettlementTooEarly signifient que la fenêtre de temps a été manquée ; MintAuthorityChanged
et BlockedMintExtension signifient qu'un mint a changé après la création ;
RecipientAtaMismatch signifie qu'un token account de destination ou de remboursement est absent ou
n'appartient plus au propriétaire et au mint attendus, généralement parce que l'étape de
création de compte ci-dessus a été omise. Dans tous les cas, rien n'a bougé, et les
parties peuvent annuler l'opération, sous réserve des autorités du mint (voir
annuler une opération).
Étapes suivantes
- Annuler une opération : récupérer les volets financés lorsqu'une opération n'est pas réglée
Is this page helpful?