Skip to content
parchmentdocs
Open app

TypeScript SDK

@parchment-trade/sdk is a TypeScript client for the public API. It reads markets and accounts, previews trades and builds unsigned Sui transactions. You sign and execute them with your own wallet or key.

Package: @parchment-trade/sdk on npm (Apache-2.0). Full API reference: API reference.

Install

Shell
npm install @parchment-trade/sdk @mysten/sui
RequirementVersion
Node22.14 or newer
@mysten/sui (peer dependency)>=1.45.2 <3
TypeScript
import { Parchment } from "@parchment-trade/sdk";

Create a client

TypeScript
const parchment = await Parchment.create({
  baseUrl: "https://api.parchment.trade",
});

That is the whole setup: no package ids to configure. The client trusts the Parchment API. Each transaction builder returns the transaction the API built for your request, and you sign it with your wallet as you would any other transaction. The package and object ids are listed under Contract addresses for reference.

Reads are get*. Transaction builders are get*Tx.

Amounts

Amounts are integers in base units. USDC has 6 decimals, so 10_000_000n is 10 USDC. Prices are 1e18 fixed-point integers. Inputs take a bigint or a digit string. Every integer in a response is a bigint.

Read markets and an account

TypeScript
const { markets } = await parchment.getMarkets();
const market = markets[0];

// Within the market's range: 100x to 1000x, 50x to 500x on SUI.
const leverage = market.market.risk!.minLeverage;

const account = await parchment.getAccount({ walletAddress });
const positions = account.getPositions();

Preview a trade

Previews are estimates at the current mid, not fills. Pass slippageBps (0 to 10000) to get a suggested price bound.

TypeScript
const preview = await parchment.getPreviewOpen({
  marketId: market.market.marketId,
  accountId,
  margin: 10_000_000n,
  leverage,
  isLong: true,
  slippageBps: 50n,
});

if (preview.errors.length === 0) {
  console.log(preview.notional, preview.entryWad, preview.bustWad, preview.suggestedBoundWad);
}

Open and close

Opens and closes are two-step requests. A keeper fills them at the oracle mid.

TypeScript
const built = await parchment.getRequestOpenTx({
  walletAddress,
  accountId,
  accountCapId, // your AccountCap object id
  marketId: market.market.marketId,
  margin: 10_000_000n,
  leverage,
  isLong: true,
  acceptablePriceWad: preview.suggestedBoundWad!,
});

Without a preview, compute the bound from a price:

TypeScript
import { boundFromSlippage } from "@parchment-trade/sdk";

const acceptablePriceWad = boundFromSlippage({
  side: "long",
  action: "open",
  priceWad: market.price.priceWad!,
  slippageBps: 50,
});

To close, request a close for the position:

TypeScript
const position = positions[0];
const closed = await parchment.getRequestCloseTx({
  walletAddress,
  accountId,
  accountCapId,
  marketId: position.marketId,
  positionId: position.positionId,
});
  • On an open, acceptablePriceWad is required and non-zero. A missing or zero value throws price_bound_required before any request.
  • On a close it is optional. Omitted or 0 means no bound.
  • The bound is stored on the order only. Fills do not check it.
  • margin is the order's margin. The $0.02 execution fee comes from your free balance on top of it.
  • To send a builder code, pass builderCode (the API resolves it to its id) or builderId, not both. The trade pays the code only if you approved it; see Builder codes.

Built transactions

Every builder returns:

FieldMeaning
requestThe route and body the transaction was built for
txA @mysten/sui Transaction, with your address as sender
commandsThe Move calls it makes
noteGuidance text, or null
txBytesBase64The transaction kind as base64

Gas is not included. Your wallet sets it when it signs.

TypeScript
import { requestedOrderIdFromTx } from "@parchment-trade/sdk";

// @mysten/sui 2.x
const result = await client.signAndExecuteTransaction({
  transaction: built.tx,
  signer,
  include: { events: true },
});

const orderId = requestedOrderIdFromTx(result);
if (orderId) {
  const order = await parchment.waitForOrder(orderId, { timeoutMs: 10_000 });
  if (order.status === "filled") console.log(order.positionId);
  if (order.status === "refunded") console.log(order.reason);
}

One-click trading

A session key is a key in your app that the account grants as a delegate. It can open, close and cancel trades. It cannot withdraw, deposit or move funds out of the account.

StepSDK
Create a keycreateSessionKey()
Grant it (the wallet signs once)getGrantDelegateTx, with an expiryMs. sessionKeyExpiryMs() gives just under 30 days from now; the Parchment app grants with no expiry (a far-future expiryMs)
Grant it with the TP/SL delegate in one transactiongetGrantSessionAndTriggerTx
Trade as the keygetRequestOpenAsDelegateTx, getRequestCloseAsDelegateTx
RevokegetRevokeDelegateTx, getRevokeSessionAndTriggerTx

Gas sponsorship

Session-key trades can be sponsored. Sign a proof with signSponsorProof, send it with sponsorTransaction, then sign the result with signSessionSponsoredTx. Owner transactions are never sponsored.

On a sponsor error, shouldPayOwnGas(error) says whether to fall back to the wallet. isSessionKeyRevoked(error) says the key is no longer a delegate.

Take-profit and stop-loss

setTriggers({ owner, accountId, target, takeProfitWad, stopLossWad }, signer) sets both legs with one owner-signed proof. null clears a leg. getTriggers({ walletAddress }) lists them. Triggers need the close-only delegate, granted with getGrantCloseDelegateTx or getGrantSessionAndTriggerTx. See Stop-loss and take-profit.

Close All

Several closes fit in one transaction.

FunctionDoes
planCloseBatches(legs, options)Groups positions into batches before anything is built
fitCloseBatch(legs, options)Returns the longest prefix of built legs that fits one transaction, and that transaction
batchCloseTx(legs, options)Builds one transaction from the legs

Each built leg is { tx: built.tx, request: built.request }. fitCloseBatch and batchCloseTx take { sender }.

TypeScript
import { fitCloseBatch } from "@parchment-trade/sdk";

const legs = [];
for (const p of positions) {
  const built = await parchment.getRequestCloseTx({
    walletAddress, accountId, accountCapId, marketId: p.marketId, positionId: p.positionId,
  });
  legs.push({ tx: built.tx, request: built.request });
}

const { tx, count } = await fitCloseBatch(legs, { sender: walletAddress });
// Sign and execute tx. If count < legs.length, batch the rest after it confirms.

Locked PARCHMENT

getExitEarlyBoundedTx({ unlocks, maxPenalty }) exits only the entries you quote and aborts above maxPenalty. Pass the game profile's earlyExitUnlocks and earlyExitPenaltyNow. Use it instead of getExitEarlyTx, which exits every eligible entry at execution time.

Pay out the queue

TypeScript
await parchment.getHarvestTx({ walletAddress, maxEntries: 32n });

Anyone can run it. maxEntries defaults to 32 and must be between 1 and 128.

Errors

API and local errors throw ParchmentApiError:

FieldMeaning
statusHTTP status, or 0 for a local error
codeError code
messageDescription
retryAfterMsFrom the Retry-After header, when there is one
CodeCause
price_bound_requiredAn open without a non-zero acceptablePriceWad
bad_requestA malformed address, cursor or limit, caught before sending
timeoutA request passed its timeoutMs

The Close All functions throw BatchCloseError.