CreateDvp фіксує умови угоди та створює два ескроу-рахунки, які
сторони мають поповнити. Токени він не переміщує. Надіслати його може будь-хто, тож запис може
надійти від контрагента, оператора розрахункового органу або третьої сторони,
а кожен інший учасник перевіряє збережені умови, перш ніж діяти на їх підставі (див.
поповнення частин угоди).
У фрагментах коду клієнт, згенерований для програми, використовується напряму, а адреси є заповнювачами, щоб було видно, які акаунти та підписанти беруть участь. Вони націлені на devnet, де програма розгорнута за тією самою адресою, що й у mainnet-beta.
Встановлення
Станом на 2 жовтня 2026 року для клієнтів DvP не опубліковано жодного пакета. Обидва генеруються з IDL програми в репозиторії та використовуються з вихідного коду.
git clone https://github.com/solana-foundation/dvp.gitcd dvp && git checkout df9919ed02c25a93620e7f6820107c9050ce3b92pnpm install && pnpm generate-clients && pnpm build# The client is clients/typescript/src; copy or link it into your project as ./dvppnpm add @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token-2022 @solana-program/memo
Ці сторінки написано для коміту df9919e, з @solana/kit 8 у
TypeScript та крейтами solana-* 2.x у Rust.
Фрагменти коду на кожній сторінці кроків є наскрізними: кожна сторінка використовує клієнт, підписантів
та адреси, визначені на попередніх сторінках. payerSigner, userASigner,
userBSigner і authoritySigner — це TransactionSigner для платника
rent, двох сторін і розрахункового органу, наприклад, створені через
createKeyPairSignerFromBytes. Фрагменти на Rust формують інструкції, а підписання
та надсилання залишають на розсуд викликача.
Виведення адрес
Запис угоди — це Program Derived Address, виведена з розрахункового органу, двох сторін, двох мінтів і nonce. Кожен ескроу — це associated token account запису для одного з мінтів. Обидва виведення не потребують доступу до мережі.
Використовуйте випадковий 64-бітний nonce для кожної угоди. Оскільки створення не потребує дозволів,
передбачуваний nonce дає змогу третій стороні зайняти адресу, яку мала
використати угода. Передавайте nonce і суми як bigint у TypeScript; згенерований
клієнт відхиляє number.
Перед запуском замініть кожен заповнювач ..._HERE на справжню адресу.
address() перевіряє base58 і викидає помилку на заповнювачі, а pubkey! не
компілюється.
import { address, createClient } from "@solana/kit";import { solanaRpc } from "@solana/kit-plugin-rpc";import { signer } from "@solana/kit-plugin-signer";import { TOKEN_2022_PROGRAM_ADDRESS } from "@solana-program/token-2022";import { findSwapDvpEscrowAta, findSwapDvpPda } from "./dvp";const client = createClient().use(signer(payerSigner)).use(solanaRpc({rpcUrl: "https://api.devnet.solana.com",rpcSubscriptionsUrl: "wss://api.devnet.solana.com",}),);const settlementAuthority = address("SETTLEMENT_AUTHORITY_ADDRESS_HERE");const userA = address("ASSET_LEG_PARTY_ADDRESS_HERE");const userB = address("CASH_LEG_PARTY_ADDRESS_HERE");const mintA = address("ASSET_MINT_ADDRESS_HERE");const mintB = address("CASH_MINT_ADDRESS_HERE");const tokenProgramA = TOKEN_2022_PROGRAM_ADDRESS;const tokenProgramB = TOKEN_2022_PROGRAM_ADDRESS;// A fresh random nonce per trade, as a bigint.const nonce = new DataView(crypto.getRandomValues(new Uint8Array(8)).buffer,).getBigUint64(0);const [swapDvp] = await findSwapDvpPda({settlementAuthority,userA,userB,mintA,mintB,nonce,});const [escrowA] = await findSwapDvpEscrowAta({swapDvp,mint: mintA,tokenProgram: tokenProgramA,});const [escrowB] = await findSwapDvpEscrowAta({swapDvp,mint: mintB,tokenProgram: tokenProgramB,});
Фіксація умов
CreateDvp приймає дві суми в базових одиницях, термін дії, nonce та чотири
необов’язкові поля: непрозоре посилання до 64 байтів, адресу призначення розрахунку
для кожної сторони та найраніший час розрахунку (див. примітки). Адреса призначення —
це місце, куди надходять кошти цієї сторони під час розрахунку, наприклад, депозитний гаманець
кастодіана; за замовчуванням це власна адреса сторони, і після створення
запису її змінити не можна. Повернення коштів і відкликання завжди надходять на власний token account
сторони для мінта цієї частини угоди, а не на адресу призначення, хоч би хто поповнив ескроу.
Платник вносить rent за запис, надгробок nonce і обидва ескроу.
Під час закриття цей rent отримує той, хто підписує інструкцію закриття, а не
платник. Надгробок ніколи не закривається, тому кожна угода залишає невеликий постійний
баланс. Плануючи SOL платника, визначайте суми rent за допомогою
RPC-методу getMinimumBalanceForRentExemption, а не фіксуйте їх у коді.
import { getCreateDvpInstruction } from "./dvp";const nowSeconds = BigInt(Math.floor(Date.now() / 1000));const createInstruction = getCreateDvpInstruction({payer: payerSigner,swapDvp,nonceTombstone: (await getProgramDerivedAddress({programAddress: DVP_SWAP_PROGRAM_PROGRAM_ADDRESS,seeds: ["nonce", getAddressEncoder().encode(swapDvp)],}))[0],settlementAuthority,userA,userB,mintA,mintB,dvpAtaA: escrowA,dvpAtaB: escrowB,tokenProgramA,tokenProgramB,amountA: 1_000_000_000n, // 1,000 units of a 6-decimal assetamountB: 998_500_000n, // 998.50 units of a 6-decimal cash tokenexpiryTimestamp: nowSeconds + 60n * 60n * 24n, // one daynonce,refString: "ORDER-2026-10-02-0001",userASettlementDestination: null, // defaults to userAuserBSettlementDestination: null, // defaults to userBearliestSettlementTimestamp: null,});const { context } = await client.sendTransaction([createInstruction]);console.log("Trade record:", swapDvp, "signature:", context.signature);
Для TypeScript-фрагмента в області видимості мають бути getProgramDerivedAddress і getAddressEncoder
з @solana/kit, а також DVP_SWAP_PROGRAM_PROGRAM_ADDRESS з клієнта.
Білдер Rust залишає System Program та Associated Token Program
зі значеннями за замовчуванням.
Примітки
- Термін дії. Лише Settle перевіряє термін дії. Reclaim, Cancel і Reject працюють і після його завершення, а депозит, що надійшов після завершення терміну, може повернути сторона відповідної частини угоди. Термін дії може становити щонайбільше один рік від створення.
- Час — це час мережі. Програма зчитує ончейн-годинник, який може відрізнятися від звичайного часу, подекуди на десятки секунд, і може стрибнути вперед. Залишайте запас між терміном дії та запланованим часом розрахунку, не поповнюйте й не розраховуйте поблизу жодної з меж і не покладайтеся на термін дії як на дедлайн з точністю до секунди. У README програми радять закладати близько хвилини розбіжності.
- Найраніший розрахунок. Необов’язково. Якщо вказано, Settle відхиляється до цього часу, і він не має бути пізнішим за термін дії.
- Перевірки під час створення. Створення завершується помилкою
PartyNotSignerCapable, якщо сторона не є акаунтом, що належить системі (це виключає мультипідпис SPL Token), а такожSettlementDestinationIsSwapDvp,SelfDvp,SameMint,ZeroAmount,SettlementAuthorityIsPartyабоExpiryNotInFuture. Повний перелік наведено в таблиці помилок.
Наступні кроки
- Поповнення частин угоди: кожна сторона переказує свою частину до ескроу угоди
Is this page helpful?