Zasilenie to zwykły TransferChecked na escrow danej strony, więc każdy portfel lub system
kustodialny, który potrafi wysłać transfer tokenów, może zasilić stronę transakcji. Klienta DvP wymaga tylko odczyt
rekordu transakcji przed zasileniem. Program sprawdza salda
escrow dopiero podczas rozliczenia; nic nie weryfikuje transferu w chwili jego zaksięgowania,
dlatego każda ze stron odczytuje rekord transakcji przed wykonaniem transferu.
Ta strona jest kontynuacją części tworzenie transakcji; klient i podpisujący są ci sami.
Zweryfikuj warunki
Utworzenie rekordu nie wymaga uprawnień, a adresy escrow wynikają
wyłącznie z rekordu i mint, nigdy z warunków. Transfer na escrow może
więc zostać zaksięgowany przy warunkach, na które nigdy się nie zgodziłeś, w tym przy docelowych adresach rozliczenia,
które przekierowują środki twojego kontrahenta na trzeci adres.
Przed zasileniem odczytaj konto SwapDvp i porównaj je z uzgodnioną
transakcją.
verifySwapDvp w TypeScript i verify::decode_swap_dvp_account w Rust
potwierdzają, że konto należy do programu DvP, ma dokładnie 458 bajtów i
znajduje się pod adresem wyprowadzonym z jego własnych pól (fetchSwapDvpChecked wykonuje
tylko dwie pierwsze kontrole). Zwykłe funkcje odczytu fetchSwapDvp i decodeSwapDvp
nie wykonują żadnej z nich. Kontrole stron, kwot, terminów i adresów docelowych
wykonuje wywołujący, porównując je z uzgodnioną transakcją.
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");}
Jeśli rekord utworzył twój kontrahent lub organ rozliczający, porównaj każde pole z warunkami uzgodnionymi poza księgą. Jeśli utworzyłeś go samodzielnie, ten odczyt potwierdza, że został zaksięgowany tak, jak go wysłano.
Transfer na escrow
Zasil stronę transakcji dokładnie uzgodnioną kwotą. Program ogranicza rozliczenie do
amount_x i zwraca nadwyżkę stronie, do której należy dana strona transakcji, więc nadwyżka nie przepada,
ale wymaga drugiego transferu podczas rozliczenia i może się nie powieść przy niektórych
hookach transferu (zobacz uwagi poniżej).
Użyj TransferChecked, a nie niesprawdzanego Transfer. Mint Token-2022 z
rozszerzeniami zależnymi od konta mint, takimi jak Pausable, odrzucają transfer,
który go nie zawiera, a mint z hookiem transferu wymaga, aby konta
hooka zostały rozwiązane i dołączone tak samo jak przy każdym innym transferze tego
tokena.
Strona aktywa, podpisująca jako userASigner, zasila escrow 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]);
Strona gotówkowa robi to samo dla escrow B, używając userBAtaB, mintB,
userBSigner, t.amountB oraz { programAddress: tokenProgramB }.
Transfer zasilający widoczny ze statusem confirmed
nadal może zostać unieważniony. Program odczytuje saldo escrow onchain podczas
rozliczenia, więc Settle wysłany dla transferu zasilającego, który nie został zaksięgowany, kończy się niepowodzeniem
z błędem LegNotFunded i nic się nie przemieszcza; kosztem jest nieudany Settle i ponowna próba.
Uznaj stronę transakcji za zasiloną dopiero, gdy jej transfer ma status finalized.
Uwagi
- Strony z wrapped SOL. Program odczytuje saldo natywnego escrow po jego synchronizacji, więc lamport przesłane na escrow wrapped SOL przelewem systemowym są wliczane. Nigdy nie wysyłaj SOL na escrow dla żadnego innego mint: program nie może ich zwrócić, a trafią one do osoby, która zamknie konto.
- Mint z ograniczeniami. W przypadku mint z Default Account State ustawionym na frozen escrow jest tworzony jako zamrożony, a transfer kończy się niepowodzeniem, dopóki emitent go nie odblokuje lub nie dopuści. W przeglądzie opisano współdziałanie z Token ACL.
- Hooki transferu. Zasilaj escrow z hookami dokładnie uzgodnioną kwotą. Jeśli nadwyżka wymusza zwrot podczas rozliczenia, zwrot ponownie wykorzystuje konta hooka danej strony z innym miejscem docelowym i kwotą, co niektóre hooki odrzucają. Rozwiązaniem jest Reclaim, ponowne zasilenie dokładną kwotą i ponowne rozliczenie.
- Zasilenie po wygaśnięciu. Nic nie blokuje transferu po
expiry_timestamp. Zostaje zaksięgowany, rozliczenie nie jest już możliwe, a strona, do której należy dana strona transakcji, odzyskuje środki przez Reclaim, gdy transakcja jest otwarta, lub Recover po jej zamknięciu. Zobacz wycofanie transakcji. - Kto zasila pierwszy. Program nie ustala kolejności obu stron. Kolejność to kwestia uzgodnienia między stronami; każda ze stron może odzyskać swoją część w dowolnym momencie przed rozliczeniem, chyba że autorytet mint (freeze, pause lub hook transferu) blokuje escrow.
Następne kroki
- Rozlicz transakcję: organ rozliczający wymienia obie strony w jednej transakcji
- Wycofaj transakcję: odzyskiwanie zasilonej strony, gdy transakcja nie zostaje rozliczona
Is this page helpful?