CreateDvp legt de voorwaarden van een trade vast en maakt de twee escrow-accounts aan die de
partijen gaan funden. Er worden geen tokens verplaatst. Iedereen kan de instructie versturen, dus het record
kan afkomstig zijn van een tegenpartij, de operator van de settlement authority of een derde partij,
en elke andere deelnemer controleert de opgeslagen voorwaarden voordat hij erop handelt (zie
de legs funden).
De snippets gebruiken rechtstreeks de gegenereerde client, met placeholder-adressen, zodat de betrokken accounts en ondertekenaars zichtbaar zijn. Ze richten zich op devnet, waar het programma op hetzelfde adres is gedeployed als op mainnet-beta.
Installatie
Per 2 oktober 2026 is er geen package gepubliceerd voor de DvP-clients. Beide worden gegenereerd op basis van de IDL van het programma in de repository en vanuit de broncode gebruikt.
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
Deze pagina's zijn geschreven voor commit df9919e, met @solana/kit 8 in
TypeScript en de solana-* 2.x-crates in Rust.
De snippets op elke stappenpagina bouwen op elkaar voort: elke pagina gebruikt de client, ondertekenaars
en adressen die op eerdere pagina's zijn gedefinieerd. payerSigner, userASigner,
userBSigner en authoritySigner zijn TransactionSigners voor de betaler van de rent,
de twee partijen en de settlement authority, bijvoorbeeld afkomstig van
createKeyPairSignerFromBytes. De Rust-snippets bouwen instructies op en laten het
ondertekenen en verzenden over aan de aanroeper.
De adressen afleiden
Het trade-record is een program-derived address op basis van de settlement authority, de twee partijen, de twee mints en een nonce. Elke escrow is de associated token account van het record voor een van de mints. Voor beide afleidingen is geen netwerktoegang nodig.
Gebruik voor elke trade een willekeurige 64-bits nonce. Omdat het aanmaken permissionless is, kan een
voorspelbare nonce ervoor zorgen dat een derde partij het adres bezet dat een trade zou
gaan gebruiken. Geef de nonce en de bedragen door als bigint in TypeScript; de gegenereerde
client weigert een number.
Vervang elke ..._HERE-placeholder door een echt adres voordat je het uitvoert.
address() valideert base58 en geeft een foutmelding bij een placeholder, en pubkey! compileert
niet.
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,});
De voorwaarden vastleggen
CreateDvp accepteert de twee bedragen in basiseenheden, een vervaldatum, de nonce en vier
optionele velden: een ondoorzichtige referentie van maximaal 64 bytes, een settlement-bestemming
voor elke kant en een vroegste settlement-tijd (zie Opmerkingen). De bestemming is
de plek waar de opbrengst van die partij bij de settlement terechtkomt, bijvoorbeeld de
depositowallet van een custodian; standaard is dit het eigen adres van de partij en het wordt vastgezet zodra
het record bestaat. Terugbetalingen en terugvorderingen gaan altijd naar de eigen token account van de partij
voor de mint van die leg, nooit naar een bestemming, ongeacht wie de escrow heeft gefund.
De betaler financiert de rent voor het record, de nonce-tombstone en beide escrows.
Bij het sluiten gaat die rent naar degene die de sluitinstructie ondertekent, niet terug naar
de betaler. De tombstone wordt nooit gesloten, dus elke trade laat een klein permanent
saldo achter. Bepaal bij het budgetteren van de SOL van de betaler de rent-bedragen met de
RPC-methode getMinimumBalanceForRentExemption in plaats van ze hard te coderen.
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);
Voor de TypeScript-snippet moeten getProgramDerivedAddress en getAddressEncoder
uit @solana/kit, en DVP_SWAP_PROGRAM_PROGRAM_ADDRESS uit de client, beschikbaar
zijn in de scope. De Rust-builder laat het system program en het associated token program
op hun standaardwaarden staan.
Opmerkingen
- Vervaldatum. Alleen Settle controleert de vervaldatum. Reclaim, Cancel en Reject werken ook daarna, en een storting die na de vervaldatum binnenkomt, kan door de partij van die leg worden teruggevorderd. De vervaldatum mag maximaal één jaar na het aanmaken liggen.
- Tijd is netwerktijd. Het programma leest de onchain-klok, die kan afwijken van de werkelijke tijd, soms met tientallen seconden, en die vooruit kan springen. Laat een marge tussen de vervaldatum en het beoogde settlement-moment, vermijd funden of settlen vlak bij een van beide grenzen en vertrouw er niet op dat de vervaldatum een deadline op de seconde nauwkeurig afdwingt. De README van het programma adviseert ongeveer een minuut aan drift te budgetteren.
- Vroegste settlement. Optioneel. Indien ingesteld, wordt Settle ervoor geweigerd, en het mag niet later liggen dan de vervaldatum.
- Controles bij het aanmaken. Aanmaken mislukt met
PartyNotSignerCapableals een partij geen account is dat eigendom is van de System Program (dit sluit een SPL Token-multisig uit), of metSettlementDestinationIsSwapDvp,SelfDvp,SameMint,ZeroAmount,SettlementAuthorityIsPartyofExpiryNotInFuture. De volledige lijst staat in de foutentabel.
Volgende stappen
- De legs funden: elke partij stort haar leg in de escrow van de trade
Is this page helpful?