TypeScript SDK for the WaterX perpetual protocol on Sui: build PTBs with gRPC (@mysten/sui), run read-only simulateTransaction queries, and optional Pyth helpers.
ABI note: PTB entry points follow
contracts/waterx_perpin this repo. Read-onlyview::*helpers resolve the module package from each shared object’s on-chain type (soMarket/WlpPoolcan sit on a newer publish thanGlobalConfig/AccountRegistry). BCS layouts forMarketSummary,PositionInfo, andTokenPoolSummarymatch the deployedviewstructs (seecontracts/waterx_perp/package_summaries/waterx_perp/view.json). PinWaterXConfigto your environment’s package and object IDs.
pnpm install
pnpm buildConsumers:
pnpm add @waterx/perp-sdk @mysten/suibuildMintWlpTx and buildSettleRedeemWlpTx are async and return Promise<Transaction> (they resolve deposit / redeem coin oracle wiring). Callers must await:
const tx = await buildMintWlpTx(client, params);
const tx2 = await buildSettleRedeemWlpTx(client, { requestId: 1n });Move entry points are deposit_collateral_request / withdraw_collateral_request. The SDK exposes depositCollateral / withdrawCollateral as the preferred names; increaseCollateral / releaseCollateral remain as deprecated aliases (same parameters). High-level helpers: buildDepositCollateralTx / buildWithdrawCollateralTx (deprecated: buildIncreaseCollateralTx / buildReleaseCollateralTx).
Withdraw paths take collateralAmount for the size to pull from margin; amount is a deprecated alias (if both are passed, collateralAmount wins).
Trading (openPosition, closePosition, …), account helpers (depositToAccount, delegates, …), high-level build*Tx, and orders (placeOrder, cancelOrder) all use accountObjectAddress: the UserAccount object id (hex). Trading paths pass it as tx.pure.address; registry calls use tx.pure.id. It is not a numeric registry index.
getAccountsByOwner returns accountObjectAddress on each AccountInfo row.
High-level build*Tx helpers also accept optional collateralTokenType (defaults to WaterXConfig.usdcType). Only token types wired in resolveTokenPriceFeed (src/tx-builders.ts) get automatic Pyth updates; extend there when the protocol adds collaterals.
All network I/O uses gRPC (SuiGrpcClient). Trading helpers require bucketFrameworkPackageId (Bucket bucket_v2_framework package) so the PTB can call account::request.
Testnet (built-in constants):
import { WaterXClient } from "@waterx/perp-sdk";
const client = WaterXClient.testnet();
// optional: custom fullnode gRPC URL
// const client = WaterXClient.testnet({ grpcUrl: "https://fullnode.testnet.sui.io:443" });Custom config (any network):
import { WaterXClient, createTestnetConfig, type WaterXConfig } from "@waterx/perp-sdk";
const config: WaterXConfig = {
...createTestnetConfig(),
packageId: "0x...", // your deployed waterx_perp package
globalConfig: "0x...",
// ...all other object IDs and token type strings
};
const client = new WaterXClient(config);Uses gRPC simulateTransaction + BCS (no signer).
import { WaterXClient, getPoolSummary, getWlpTotalSupply, getWlpTvlUsd } from "@waterx/perp-sdk";
const client = WaterXClient.testnet();
const pool = await getPoolSummary(client);
console.log("LP supply (raw):", pool.totalLpSupply.toString());
console.log("TVL (u128):", pool.tvlUsd.toString());
const supply = await getWlpTotalSupply(client);
const tvl = await getWlpTvlUsd(client);import {
WaterXClient,
getAccountsByOwner,
getPosition,
positionExists,
} from "@waterx/perp-sdk";
const client = WaterXClient.testnet();
const owner = "0x..."; // Sui address
const accounts = await getAccountsByOwner(client, owner);
const accountObjectAddress = accounts[0]!.accountObjectAddress;
const market = client.config.btcMarket;
const has = await positionExists(client, market, 0n);
if (has) {
const pos = await getPosition(client, market, 0n);
// `accountObjectAddress` = on-chain `user_address`; `marketIndex` = pool row index (not Market object id).
console.log(pos.accountObjectAddress, pos.marketIndex, pos.sizeAmount);
}Returns a Transaction you sign and execute with the same client.
import { WaterXClient, buildOpenPositionTx } from "@waterx/perp-sdk";
import { Ed25519Keypair } from "@mysten/sui/keypairs/ed25519";
const client = WaterXClient.testnet();
// Use your own keypair or any @mysten/sui Signer (e.g. wallet adapter).
const keypair = Ed25519Keypair.generate();
const tx = await buildOpenPositionTx(client, {
accountObjectAddress: "0x...", // UserAccount object id (hex), not a numeric id
base: "BTC",
isLong: true,
leverage: 10,
collateralAmount: 1_000_000_000n, // 1000 USDC if 6 decimals
});
const result = await client.signAndExecuteTransaction({
transaction: tx,
signer: keypair,
});
console.log(result.digest);Create a Transaction, append Pyth / aggregator calls (updatePythPrices, buildPythRuleFeedCalls from this package — mirror src/tx-builders.ts), then call openPosition(client, tx, openPositionParams) (or any other builder in src/user/). Params are typed as OpenPositionParams, ClosePositionParams, etc.
| Export | Purpose |
|---|---|
WaterXClient |
gRPC client, simulate(), signAndExecuteTransaction() |
createTestnetConfig() |
Default testnet package/object/token IDs + Pyth config |
WaterXConfig |
Full config; must include bucketFrameworkPackageId for trading PTBs |
| Group | Functions |
|---|---|
| Shared | accountSenderRequest(tx, client) |
| Trading | openPosition, closePosition, increasePosition, decreasePosition, depositCollateral, withdrawCollateral (increaseCollateral / releaseCollateral deprecated), liquidate, matchOrders, updateFundingRate |
| Orders | placeOrder, cancelOrder |
| WLP | mintWlp, requestRedeemWlp, cancelRedeemWlp, settleRedeemWlp |
| Account | createAccount, depositToAccount, receiveCoin, transferAccount, addDelegate, removeDelegate, updateDelegatePermissions |
| Referral | setReferralCode, useReferralCode, registerReferralCode, bindReferral |
Param types: OpenPositionParams, IncreasePositionParams, DecreasePositionParams, etc. (see src/index.ts).
| Area | Functions |
|---|---|
| Account | getAccountsByOwner, getAccountDelegates, getAccountObjectId (deprecated — use accountObjectAddress directly), getAccountCoins, getAccountBalance, selectCoinsForAmount |
| Market / pool | getMarketSummary (view::market_summary<LP> — optional typeArgs: LP type string or { lpTokenType? } only), getPoolSummary, getWlpTotalSupply, getWlpTvlUsd, getTokenPoolSummary |
| Position | getPosition, positionExists (same LP type-arg rules as getMarketSummary) |
View return shapes: MarketSummary includes marketIndex (on-chain index). PositionInfoView exposes marketIndex (bigint) and accountObjectAddress (from user_address). getTokenPoolSummary maps TokenPoolSummary.lastPriceRefreshTimestamp when the return payload includes it; older 72-byte deployments surface 0n (see parseTokenPoolSummaryReturn in fetch.ts).
buildOpenPositionTx, buildClosePositionTx, buildIncreasePositionTx, buildDecreasePositionTx, buildDepositCollateralTx, buildWithdrawCollateralTx (buildIncreaseCollateralTx / buildReleaseCollateralTx deprecated), buildPlaceOrderTx, buildCancelOrderTx (all async, Pyth-backed). buildMintWlpTx and buildSettleRedeemWlpTx are also async (deposit / redeem coin oracle). buildRequestRedeemWlpTx (requires recipient), buildCancelRedeemWlpTx.
Permission bits, order tags, testnet IDs, Pyth feeds: src/constants.ts.
On testnet, TESTNET_TYPES.WLP is the LP type wired to the live WlpPool / Market (wlp_token::WLP_TOKEN); TESTNET_PACKAGE_IDS.WLP_STANDALONE points at the standalone contracts/wlp publish for reference.
Oracle wiring: fetchPriceFeedsUpdateData, updatePythPrices, buildPythRuleFeedCalls, PythCache, etc. in src/utils/pyth.ts.
| Command | Use |
|---|---|
pnpm typecheck |
Typecheck |
pnpm test |
Tests |
pnpm lint / pnpm format |
Prettier |
pnpm codegen |
Regenerate src/generated from Move |