Розрахунок за угодою

SettleDvp підписує розрахунковий орган, указаний у записі угоди. В одній транзакції інструкція переказує amount_a зі сторони активу на призначення учасника грошової сторони та amount_b з грошової сторони на призначення учасника сторони активу, повертає будь-який надлишок в обох ескроу учаснику відповідної сторони, а також закриває запис і обидва ескроу. Якщо будь-який із цих переказів неможливо виконати, інструкція завершується помилкою, і нічого не переміщується.

Ця сторінка продовжує матеріали створення угоди та фінансування сторін; клієнт, підписанти, trade і token accounts учасників переходять звідти.

Повторна перевірка перед підписанням

Розрахунковий орган підписує транзакцію, яка переміщує обидві сторони, тому він виконує те саме читання, що й кожен учасник перед підписанням: власник, розмір, учасники, мінти, суми, строк дії та обидва призначення (див. фінансування сторін). Сама програма під час розрахунку повторно перевіряє, що кожен мінт досі належить до token program, записаної під час створення, не має заблокованого розширення і має ту саму mint authority, що й під час створення угоди. Тому мінт, відтворений із заблокованим розширенням, іншою token program або іншою mint authority, не може бути розрахований.

Створення акаунтів отримувачів

Settle записує дані в чотири token accounts, які програма не створює:

АкаунтОтримуєВласник
userADestinationAtaBГрошову сторону (amount_b)user_a_settlement_destination
userBDestinationAtaAСторону активу (amount_a)user_b_settlement_destination
userAAtaAБудь-який надлишок на стороні активуuser_a
userBAtaBБудь-який надлишок на грошовій стороніuser_b

Акаунти для надлишку використовуються лише тоді, коли ескроу містить більше за погоджену суму, але будь-хто, хто володіє мінтом, може створити надлишок, надіславши кілька базових одиниць в ескроу. Якщо акаунта для повернення не існує, уся інструкція Settle завершується помилкою, тому створіть усі чотири ідемпотентно в тій самій транзакції.

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,
}),
);

Розрахунок

legAExtrasCount повідомляє програмі, скільки акаунтів, доданих після фіксованого списку, належать до transfer hook сторони активу; решта належать до transfer hook грошової сторони. Для мінтів без transfer hooks передайте нуль і нічого не додавайте. Memo program account потрібен інструкції й використовується лише для призначень, які вимагають 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 hooks

Згенерований IDL перелічує лише фіксовані акаунти, тому згенеровані білдери не знають про акаунти hook. Визначте додаткові account metas кожного мінта з hook так само, як для прямого переказу цього токена, а потім додайте їх до інструкції: спершу акаунти сторони активу, потім грошової сторони, а legAExtrasCount має дорівнювати кількості в першій групі. У TypeScript розгорніть визначені metas у масив accounts інструкції; у Rust використайте add_remaining_accounts у білдері. Ліміт становить 32 акаунти на сторону, включно з програмою hook і акаунтом валідації; ліміт акаунтів у транзакції може спрацювати раніше, коли hooks є в обох сторін. Програма прибирає прапорець підписанта з кожного переданого акаунта, тому hook не може отримати підпис розрахункового органу цим шляхом.

Фіксація результату

Вважайте угоду розрахованою, коли транзакція Settle досягає finalized. Запис і обидва ескроу після розрахунку більше не існують, тож система, якій пізніше потрібні умови, зберігає їх зі свого читання перед розрахунком або з транзакції створення. rent закритих акаунтів перейшов до розрахункового органу.

Помилки Settle

LegNotFunded означає, що ескроу містить менше за погоджену суму; DvpExpired і SettlementTooEarly означають, що часове вікно пропущено; MintAuthorityChanged і BlockedMintExtension означають, що мінт змінився після створення; RecipientAtaMismatch означає, що token account призначення або повернення відсутній чи більше не належить очікуваному власнику та мінту, зазвичай через пропущений вище крок створення акаунтів. У кожному з цих випадків нічого не переміщено, і учасники можуть скасувати угоду з урахуванням повноважень мінта (див. скасування угоди).

Наступні кроки

Is this page helpful?

Зміст

Редагувати сторінку