# Users

> Canonical: https://docs.velocity.exchange/developers/velocity-sdk/users

## How it works

A user account is the onchain account that holds positions, orders, and collateral. Each wallet can create several of them, called subaccounts, identified by a numeric ID starting at 0. Every subaccount is a separate account with its own margin calculation: collateral and positions in subaccount 0 neither back nor endanger subaccount 1. Cross-margin applies only *within* one subaccount, where its positions and balances net against each other.

The account is a Solana PDA owned by the Velocity program, and it stores perp positions, spot balances (deposits and borrows), open orders, and leverage settings. Every write, placing an order, depositing, trading, is a mutation of that account. Subaccounts share only the wallet authority and one `UserStats` account, which carries volume, fee tier, and delegate permissions for all of them.

That isolation is what makes subaccounts worth using: separating strategies, keeping a risky book away from a conservative one, or handing a bot one subaccount while the owner trades another by hand.

## SDK Usage

Most write actions go through `VelocityClient`. Account-level reads (positions, orders, health) go through a `User`, obtained from the client.

### Initialize a user account

Creating a subaccount returns both the transaction signature and the new account's address. `getNextSubAccountId()` returns the next free ID for this client, so the caller does not have to track it.

  
```js
// Assumes `velocityClient` is constructed and subscribed.
const subAccountId = await velocityClient.getNextSubAccountId();

const [txSig, userAccountPublicKey] = await velocityClient.initializeUserAccount(
  subAccountId,
  "my-account"
);
console.log(txSig, userAccountPublicKey.toBase58());
```
  

Two rules bind when a referrer is involved, and both reject rather than recording nothing.
Passing a referrer at initialization requires that referrer's **subaccount 0**, and that
account's authority must match the authority on its own `UserStats`, or the instruction
fails with `InvalidReferrer`. Claiming a referrer name through `initialize_referrer_name`
has the same subaccount 0 requirement and additionally requires `pool_id == 0`.

A referrer is also recorded once and never rewritten, so a user who was referred cannot be
re-referred by deleting and recreating their accounts.

### Get a User and subscribe

`velocityClient.getUser()` returns the `User` for the active subaccount; pass a subaccount ID to get a specific one. Call `subscribe()` on it before reading, and `fetchAccounts()` to force a refresh from RPC rather than waiting for the next subscription update.

  
```js
const user = velocityClient.getUser();      // active subaccount
const otherUser = velocityClient.getUser(1); // subaccount 1

await user.subscribe();
await user.fetchAccounts(); // force-refresh from RPC
```
  

The raw onchain `UserAccount` is readable from either side. `user.getUserAccount()` reads it off a `User`; `velocityClient.getUserAccount()` is a shortcut for the active subaccount.

  
```js
const account = velocityClient.getUser().getUserAccount();
const sameAccount = velocityClient.getUserAccount(); // active subaccount

console.log(account.orders.length, account.perpPositions.length);
```
  

### Derive the account address

User accounts are Program Derived Addresses: deterministic addresses generated from the program ID, the wallet authority, and the subaccount ID. Deriving one takes no RPC call, which matters when the address is needed before the account exists, such as when building a transaction or fanning out parallel queries. See [Program Structure](/developers/concepts/program-structure.md) for the seeds and the rest of the account layout.

  
```js
const userAccountPublicKey = await velocityClient.getUserAccountPublicKey(0);
console.log(userAccountPublicKey.toBase58());
```
  

### Query orders and positions

These accessors all read the cached account, so they cost nothing and return `undefined` rather than throwing when the thing does not exist. `getTokenAmount` returns a signed value: positive for a deposit, negative for a borrow.

  
```js
import { BN } from "@velocity-exchange/sdk";

const user = velocityClient.getUser();
const tokenAmount = user.getTokenAmount(0); // spot market 0

const isDeposit = tokenAmount.gte(new BN(0));
const isBorrow = tokenAmount.lt(new BN(0));
console.log({ tokenAmount: tokenAmount.toString(), isDeposit, isBorrow });
```
  

  
```js
const position = velocityClient.getUser().getPerpPosition(0); // undefined if flat
console.log(position?.baseAssetAmount.toString());
```
  

Orders are addressable two ways: by the program's own `orderId`, or by the `userOrderId` set at placement. `getOpenOrders()` returns everything currently resting.

  
```js
const user = velocityClient.getUser();

const byOrderId = user.getOrder(1);             // program-assigned orderId
const byUserOrderId = user.getOrderByUserOrderId(1); // caller-assigned tag
const open = user.getOpenOrders();

console.log(open.length);
```
  

### The active subaccount

The active subaccount is the one `VelocityClient` methods operate on when no subaccount ID is named. It defaults to `0`. `velocityClient.getUser()`, `getUserAccount()`, `getSpotPosition(marketIndex)`, and `placePerpOrder(orderParams)` all resolve against it.

Change it with `switchActiveUser()`, or bypass it by passing a subaccount ID to the methods that accept one.

  
```js
await velocityClient.switchActiveUser(1);
const user1 = velocityClient.getUser(); // now subaccount 1
```
  

### Update delegate

A delegate is another wallet that can trade on behalf of a user account without being able to withdraw funds, which is how a bot gets a position to manage while withdrawal authority stays with the owner. See [Delegated Accounts](/protocol/getting-started/delegated-accounts.md) for the trader-facing description.

  
```js
import { PublicKey } from "@solana/web3.js";

// Pass PublicKey.default to clear the delegate.
await velocityClient.updateUserDelegate(new PublicKey("<DELEGATE_PUBKEY>"), 0);
```
  

A delegate can sign most trading instructions on a subaccount's behalf: place orders, cancel orders, modify orders. `withdraw` always requires the owning authority's own signature, so a delegate can never move funds out of the protocol.

#### Delegate-initiated internal transfers

A delegate can move a subaccount's collateral to another of the *owner's* subaccounts via `transferDepositByDelegate`, but only after the owner opts in. The opt-in is a bit in `delegatePermissions` on the owner's `UserStats` account. It gates delegate transfers across *all* of that owner's subaccounts at once, and it does not affect direct deposits, withdrawals, or trading. While the bit is clear the program rejects `transferDepositByDelegate`; while it is set the delegate can move collateral between the owner's subaccounts. Read the owner's `UserStats` account for the bit's setting.

The owner opts in first, signing with their own wallet rather than the delegate's:

  
```js
// Run with a VelocityClient whose wallet is the account owner (authority).
await velocityClient.updateUserAllowDelegateTransfer(true);
```
  

Then the delegate can transfer between the owner's subaccounts:

  
```js
// Run with a VelocityClient constructed with `authority: <OWNER_PUBKEY>` and a
// delegate wallet, per the delegated-accounts note in Setup.
const marketIndex = 0; // spot market 0 is the quote asset
const amount = velocityClient.convertToSpotPrecision(marketIndex, 100);

await velocityClient.transferDepositByDelegate(
  amount,
  marketIndex,
  0, // fromSubAccountId (owner's subaccount)
  1  // toSubAccountId (owner's subaccount)
);
```
  

Without the opt-in, the program rejects the call regardless of which subaccount the delegate is authorized on. See [Transfers](/developers/velocity-sdk/transfers.md#delegate-transfers) for the rest of the transfer surface.

### Update margin settings

Margin settings control how a subaccount uses leverage and borrows against collateral. Both updaters take an array, so one transaction can change several subaccounts. `marginRatio` is scaled by `MARGIN_PRECISION` (1e4), and it is a *minimum margin ratio*, so a larger number means less leverage: `10000` caps the account at 1x, `5000` at 2x, `2000` at 5x. See [Margin](/protocol/trading/margin.md).

  
```js
await velocityClient.updateUserMarginTradingEnabled([
  { marginTradingEnabled: true, subAccountId: 0 },
]);
```
  

  
```js
// marginRatio is scaled by MARGIN_PRECISION (1e4).
await velocityClient.updateUserCustomMarginRatio([
  { marginRatio: 5000, subAccountId: 0 }, // 2x max leverage
]);
```
  

### Delete a user account

A subaccount with no assets and no liabilities can be deleted to reclaim its rent.

  
```js
await velocityClient.deleteUser(1);
```
