Developers
Clients
Validator Client

Validator Client

Getting Started

Installation

pnpm install @dydxprotocol/v4-client-js 

Initializing the Client

import { ValidatorClient, Network } from "@dydxprotocol/v4-client-js";
 
const client = await ValidatorClient.connect(Network.testnet().validatorConfig);

Configuring a Network

    import {
      Network,
      ValidatorClient,
      IndexerConfig,
      ValidatorConfig
    } from '@dydxprotocol/v4-client-js';
 
    const indexerConfig = new IndexerConfig(
        {INDEXER_REST_URL},
        {INDEXER_WEBSOCKET_URL}
    );
 
    const denomConfig = {
        USDC_DENOM: 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5',
        USDC_DECIMALS: 6,
        USDC_GAS_DENOM: 'uusdc',
        CHAINTOKEN_DENOM: {CHAIN_TOKEN_DENOM} //string
        CHAINTOKEN_DECIMALS: {CHAIN_TOKEN_DECIMALS} //integer
    };
 
    const validatorConfig = new ValidatorConfig(
        {VALIDATOR_REST_URL},
        {CHAIN_ID},
        denomConfig
    );
 
    const custom_network = new Network(
        'custom-network-name',
        indexerConfig,
        validatorConfig
    );
 
    const client = await ValidatorClient.connect(
        custom_network.validatorConfig
    );

Creating a LocalWallet

import {
  BECH32_PREFIX,
  LocalWallet,
} from '@dydxprotocol/v4-client-js';
 
const mnemonic = 'YOUR MNEMONIC HERE';
const wallet = await LocalWallet.fromMnemonic(mnemonic, BECH32_PREFIX);

Simulate, Sign and Send Transactions

Simulate a Transaction

const messages = () => Promise.resolve([ /* ... your transaction messages here */ ]);
const fee = await client.simulate(wallet, messages);

Sign a Transaction

const messages = () => Promise.resolve([ /* ... your transaction messages here */ ]);
const zeroFee = true;
const signedTransaction = await client.sign(wallet, messages, zeroFee);

Send a Transaction

const messages = () => Promise.resolve([ /* ... your transaction messages here */ ]);
const zeroFee = true;
const signedTransaction = await client.send(wallet, messages, zeroFee);

Get Account Balances

// Get all balances for an account.
const balances = await client.get.getAccountBalances(DYDX_ADDRESS)
 
// Get balance of one denom for an account.
const balance = await client.get.getAccountBalance(DYDX_ADDRESS, TOKEN_DENOM)

Transfers, Deposits, and Withdraws

Transfering an Asset

import { SubaccountClient } from '@dydxprotocol/v4-client-js';
 
const subaccount = new SubaccountClient(wallet, 0);
const recipientAddress = 'dydx...' // address of the recipient
const recipientSubaccountNumber = 0 // subaccount number of the recipient
const assetId = 0 // asset id of the token you want to transfer
const amount = Long.fromNumber(/* amount of the token you want to transfer */);
 
const tx = await client.post.transfer(
  subaccount,
  recipientAddress,
  recipientSubaccountNumber,
  assetId,
  amount
);

Depositing from wallet to Subaccount

import { SubaccountClient } from '@dydxprotocol/v4-client-js';
 
const subaccount = new SubaccountClient(wallet, 0);
const assetId = 0 // asset id of the token you want to deposit
const amount = Long.fromNumber(/* amount of the token you want to deposit */);
 
const tx = await client.post.deposit(
  subaccount,
  assetId,
  amount
);

Withdrawing from Subaccount to wallet

import { SubaccountClient } from '@dydxprotocol/v4-client-js';
 
const subaccount = new SubaccountClient(wallet, 0);
const assetId = 0 // asset id of the token you want to withdraw
const amount = Long.fromNumber(/* amount of the token you want to withdraw */);
 
const tx = await client.post.withdraw(
  subaccount,
  assetId,
  amount
);

Placing and Cancelling Orders

Placing an Order

import { OrderFlags, Order_Side, Order_TimeInForce, SubaccountClient } from '@dydxprotocol/v4-client-js';
 
const subaccount = new SubaccountClient(wallet, 0);
const clientId = 123 // set to a number, can be used by the client to identify the order
const clobPairId = 0 // perpertual market id
const side = Order_Side.SIDE_BUY // side of the order
const quantums = Long.fromNumber(1_000_000_000); // quantums are calculated by the size if the order
const subticks = Long.fromNumber(1_000_000_000); // subticks are calculated by the price of the order
const timeInForce = Order_TimeInForce.TIME_IN_FORCE_UNSPECIFIED; // TimeInForce indicates how long an order will remain active before it is executed or expires
const orderFlags = OrderFlags.SHORT_TERM; // either SHORT_TERM, LONG_TERM or CONDITIONAL
const reduceOnly = false; // if true, the order will only reduce the position size
 
const tx = await client.post.placeOrder(
  subaccount,
  clientId,
  clobPairId,
  side,
  quantums,
  subticks,
  timeInForce,
  orderFlags,
  reduceOnly
);

Cancelling an Order

All paramsters are from Order object from indexer goodTilBlockTime is the UTC epoch second of the order's goodTilBlockTime One and only one of goodTilBlock and goodTilBlockTime should be passed in as a parameter

/*
order is an Order object from the Indexer
*/
const goodTilBlock = order.goodTilBlock
let goodTilBlockTime: number | undefined;
if (order.goodTilBlockTime) {
  const datetime = new Date(order.goodTilBlockTime);
  const utcMilllisecondsSinceEpoch = datetime.getTime()
  goodTilBlockTime = Math.round(utcMilllisecondsSinceEpoch / 1000);
}
 
const tx = await client.post.cancelOrder(
  subaccount,
  order.clientId,
  order.orderFlags,
  order.clobPairId,
  goodTilBlock,
  goodTilBlockTime
);