Фінансування — це звичайний TransferChecked на ескроу ноги, тож будь-який гаманець або
кастодіальна система, що вміє надсилати переказ токенів, може профінансувати ногу. Лише читання
запису угоди перед фінансуванням потребує клієнта DvP. Програма перевіряє
баланси ескроу лише під час розрахунку; ніщо не перевіряє переказ у момент його надходження,
тому кожна сторона читає запис угоди перед переказом.
Ця сторінка продовжує створення угоди; клієнт і підписанти залишаються тими самими.
Перевірте умови
Створення запису не потребує дозволів, а адреси ескроу виводяться лише із
запису та мінта, але ніколи не з умов. Тому переказ на ескроу може
надійти за умовами, яких ви ніколи не погоджували, зокрема з адресами призначення розрахунку,
що перенаправляють кошти вашого контрагента на третю адресу.
Перед фінансуванням прочитайте акаунт SwapDvp і звірте його з погодженою
угодою.
verifySwapDvp у TypeScript і verify::decode_swap_dvp_account у Rust
підтверджують, що акаунт належить програмі DvP, має розмір рівно 458 байтів і
знаходиться за адресою, яку виводять його власні поля (fetchSwapDvpChecked виконує лише
перші дві перевірки). Звичайні засоби читання fetchSwapDvp і decodeSwapDvp
не виконують жодної з цих перевірок. Перевірки сторін, сум, часу та адрес призначення
виконує той, хто викликає, звіряючись із погодженою угодою.
import { unwrapOption } from "@solana/kit";import { verifySwapDvp } from "./dvp";const trade = await verifySwapDvp(client.rpc, swapDvp);const t = trade.data;const expectedAmountA = 1_000_000_000n;const expectedAmountB = 998_500_000n;const expectedEarliestSettlement: bigint | null = null; // as agreedconst expectedExpiry = 1_798_761_600n; // as agreed, unix secondsif (t.userA !== userA ||t.userB !== userB ||t.mintA !== mintA ||t.mintB !== mintB ||t.settlementAuthority !== settlementAuthority ||t.tokenProgramA !== tokenProgramA ||t.tokenProgramB !== tokenProgramB ||t.amountA !== expectedAmountA ||t.amountB !== expectedAmountB ||unwrapOption(t.earliestSettlementTimestamp) !== expectedEarliestSettlement ||t.expiryTimestamp !== expectedExpiry ||t.userASettlementDestination !== userA ||t.userBSettlementDestination !== userB) {throw new Error("Stored terms do not match the agreed trade; do not fund");}if (t.expiryTimestamp <= BigInt(Math.floor(Date.now() / 1000)) + 60n) {throw new Error("Trade expires too soon to fund safely");}
Якщо запис створив ваш контрагент або розрахунковий орган, порівняйте кожне поле з умовами, які ви погодили поза реєстром. Якщо ви створили його самі, це читання підтверджує, що запис потрапив у мережу так, як було надіслано.
Переказ на ескроу
Фінансуйте ногу точно на погоджену суму. Програма обмежує розрахунок значенням
amount_x і повертає будь-який надлишок стороні ноги, тож надлишок не втрачається,
але він додає другий переказ під час розрахунку і може призвести до збою з деякими хуками
переказу (див. примітки нижче).
Використовуйте TransferChecked, а не неперевірений Transfer. Мінти Token-2022
із розширеннями, що залежать від mint account, як-от Pausable, відхиляють переказ,
який його не надає, а мінт із хуком переказу потребує, щоб акаунти хука
були визначені й додані так само, як і для будь-якого іншого переказу цього
токена.
Сторона ноги з активом, підписуючи як userASigner, фінансує ескроу A:
import {findAssociatedTokenPda,getTransferCheckedInstruction,} from "@solana-program/token-2022";const [userAAtaA] = await findAssociatedTokenPda({mint: mintA,owner: userA,tokenProgram: tokenProgramA,});const [userBAtaB] = await findAssociatedTokenPda({mint: mintB,owner: userB,tokenProgram: tokenProgramB,});const fundAssetLeg = getTransferCheckedInstruction({source: userAAtaA,mint: mintA,destination: escrowA,authority: userASigner,amount: t.amountA,decimals: 6,}, { programAddress: tokenProgramA });await client.sendTransaction([fundAssetLeg]);
Сторона грошової ноги робить те саме для ескроу B з userBAtaB, mintB,
userBSigner, t.amountB і { programAddress: tokenProgramB }.
Переказ фінансування, який видно зі статусом confirmed,
ще може бути замінений. Програма читає баланс ескроу ончейн
під час розрахунку, тож Settle, надісланий до переказу фінансування, що не надійшов, завершується помилкою
LegNotFunded, і нічого не переміщується; ціна цього — невдалий Settle і повторна спроба.
Вважайте ногу профінансованою, коли її переказ має статус finalized.
Примітки
- Ноги з wrapped SOL. Програма читає баланс нативного ескроу після його синхронізації, тож lamport, надіслані на ескроу wrapped SOL системним переказом, враховуються. Ніколи не надсилайте SOL на ескроу для будь-якого іншого мінта: програма не може його повернути, і він дістанеться тому, хто закриє акаунт.
- Мінти з обмеженим доступом. Для мінта зі станом акаунта за замовчуванням Frozen ескроу створюється замороженим, і переказ завершується помилкою, доки емітент не розморозить його або не допустить. У огляді описано взаємодію з Token ACL.
- Хуки переказу. Фінансуйте ескроу з хуками точно на погоджену суму. Якщо надлишок змушує повертати кошти під час розрахунку, повернення повторно використовує акаунти хука ноги з іншим призначенням і сумою, що деякі хуки відхиляють. Відновлення — це Reclaim, повторне фінансування на точну суму та новий розрахунок.
- Фінансування після завершення строку. Ніщо не зупиняє переказ після
expiry_timestamp. Він надходить, розрахунок більше неможливий, і сторона ноги повертає кошти через Reclaim, поки угода відкрита, або через Recover після її закриття. Див. скасування угоди. - Хто фінансує першим. Програма не визначає послідовність двох ніг. Порядок — справа сторін; кожна сторона може повернути свою ногу в будь-який момент до розрахунку, якщо тільки авторитет мінта (заморожування, пауза або хук переказу) не блокує ескроу.
Наступні кроки
- Розрахунок угоди: розрахунковий орган обмінює обидві ноги в одній транзакції
- Скасування угоди: повернення профінансованої ноги, коли угода не розраховується
Is this page helpful?