# Account

### Overview

The `PerpetualsAccount` class is a high-level wrapper around a single **Perpetuals account** or **vault account** that provides transaction builders and data access methods for trading and general account management.

**Key Features:**

* **Transaction Builders** for:
  * Collateral management (deposit, withdraw, allocate, deallocate, transfer)
  * Order placement (market, limit, scale orders, stop orders, SL/TP)
  * Order management (cancel, edit, cancel-and-place)
  * Leverage adjustment
* **Preview Methods** for:
  * Market, limit, and scale order simulations
  * Cancel order effects
  * Leverage changes
  * Collateral adjustments
* **Data Query Methods** for:
  * Order and stop order data
  * Collateral change history
  * Order history
  * Margin history
* **Helper Methods** for:
  * Position lookups
  * SL/TP order categorization
  * Account metadata access

{% hint style="warning" %}
This class wraps a **snapshot** of account state fetched via `Perpetuals.getAccount()`. For long-lived applications, refresh the account periodically to avoid stale state, especially:

* After placing/canceling orders
* After fills, liquidations, or funding settlements
* After switching markets or wallets
  {% endhint %}

**Typical Usage:**

```typescript
import { Aftermath } from "aftermath-ts-sdk";

const afSdk = new Aftermath("MAINNET");
await afSdk.init();

const perps = afSdk.Perpetuals();

// Get owned account caps
const { accounts: accountCaps } = await perps.getOwnedAccountCaps({
	walletAddress: "0xUSER_ADDRESS",
});

// Fetch full account with positions
const { account } = await perps.getAccount({
	accountCap: accountCaps[0],
});

// Use account methods
const { tx } = await account.getPlaceMarketOrderTx({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	size: 1000000000n,
	collateralChange: 10,
	reduceOnly: false,
});
```

***

### Constructor

#### `constructor`

```typescript
constructor(
  public readonly account: PerpetualsAccountObject,
  public readonly accountCap: PerpetualsAccountCap | PerpetualsPartialVaultCap,
  config?: CallerConfig,
  public readonly Provider?: AftermathApi
)
```

Creates a new `PerpetualsAccount` wrapper instance.

{% hint style="warning" %}
You typically don't construct this directly. Instead, use `Perpetuals.getAccount()` or `Perpetuals.getAccounts()`.
{% endhint %}

**Parameters:**

* **`account`**: `PerpetualsAccountObject`
  * Raw account object containing:
    * `positions`: Array of open positions
    * `availableCollateral`: Free collateral
    * `totalEquity`: Total account equity
    * Other account state fields
* **`accountCap`**: `PerpetualsAccountCap | PerpetualsPartialVaultCap`
  * Account cap or partial vault cap object containing:
    * `accountId`: Numeric account ID
    * `accountObjectId`: On-chain account object ID
    * `collateralCoinType`: Collateral type
    * `walletAddress` (for direct accounts) or `ownerAddress` (for vaults)
    * `vaultId` (only for vault accounts)
* **`config`** (optional): `CallerConfig`
  * Configuration object containing network settings
* **`Provider`** (optional): `AftermathApi`
  * Shared provider instance for transaction building

**Remarks:**

* This class extends `Caller` with the `"perpetuals"` route prefix
* Automatically detects whether the account is vault-backed by checking for `vaultId` in the cap
* Routes API calls to `/perpetuals/account/...` or `/perpetuals/vault/...` accordingly

**Example:**

```typescript
// Standard usage (recommended)
const perps = afSdk.Perpetuals();
const { accounts: accountCaps } = await perps.getOwnedAccountCaps({
	walletAddress: "0xUSER_ADDRESS",
});

const { account } = await perps.getAccount({
	accountCap: accountCaps[0],
});

// Access account properties
console.log(`Account ID: ${account.accountId()}`);
console.log(`Available Collateral: ${account.collateral()}`);
console.log(`Total Positions: ${account.account.positions.length}`);

// Direct construction (advanced usage)
const rawAccount: PerpetualsAccountObject = {
	positions: [],
	availableCollateral: 1000,
	totalEquity: 1000,
	// ... other fields
};

const rawCap: PerpetualsAccountCap = {
	objectId: "0xCAP_ID",
	accountId: 123n,
	accountObjectId: "0xACCOUNT_ID",
	collateralCoinType:
		"0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN",
	walletAddress: "0xUSER_ADDRESS",
};

const customConfig = {
	network: "MAINNET" as SuiNetwork,
};

const account = new PerpetualsAccount(rawAccount, rawCap, customConfig);
```

**Use Cases:**

1. **Account Wrapping**: Wrap raw account data with convenient methods
2. **Testing**: Create account instances with mock data
3. **Custom Initialization**: Initialize with specific configs

***

### Public Properties

#### `account`

```typescript
public readonly account: PerpetualsAccountObject;
```

Raw account object containing the current snapshot of account state.

**Available Fields:**

* `positions`: Array of `PerpetualsPosition` objects for each market
* `availableCollateral`: Free collateral not allocated to markets
* `totalEquity`: Total account equity (collateral + unrealized PnL)
* Other account state fields

**Example:**

```typescript
// Access positions
console.log(`Total Positions: ${account.account.positions.length}`);

for (const position of account.account.positions) {
	console.log(`\nMarket: ${position.marketId}`);
	console.log(`  Size: ${position.baseAssetAmount}`);
	console.log(`  Entry Price: $${position.entryPrice}`);
	console.log(`  Unrealized PnL: $${position.unrealizedPnlUsd}`);
	console.log(`  Leverage: ${position.leverage}x`);
	console.log(`  Liquidation Price: $${position.liquidationPrice}`);
}

// Access account-level data
console.log(`\nAccount Summary:`);
console.log(`  Available Collateral: ${account.account.availableCollateral}`);
console.log(`  Total Equity: ${account.account.totalEquity}`);

// Calculate total position value
const totalPositionValue = account.account.positions.reduce(
	(sum, pos) => sum + Math.abs(pos.baseAssetAmount * pos.entryPrice),
	0,
);
console.log(`  Total Position Value: $${totalPositionValue.toFixed(2)}`);
```

***

#### `accountCap`

```typescript
public readonly accountCap: PerpetualsAccountCap | PerpetualsPartialVaultCap;
```

Account cap or vault cap containing ownership and identification metadata.

**For Direct Accounts (`PerpetualsAccountCap`):**

* `objectId`: Cap object ID
* `accountId`: Numeric account ID
* `accountObjectId`: Account object ID
* `collateralCoinType`: Collateral type
* `walletAddress`: Owner address

**For Vault Accounts (`PerpetualsPartialVaultCap`):**

* `vaultId`: Vault object ID
* `accountId`: Vault's trading account ID
* `accountObjectId`: Account object ID
* `collateralCoinType`: Collateral type
* `ownerAddress`: Vault owner address

**Example:**

```typescript
// Check if vault-backed
if ("vaultId" in account.accountCap) {
	console.log(`Vault Account:`);
	console.log(`  Vault ID: ${account.accountCap.vaultId}`);
	console.log(`  Owner: ${account.accountCap.ownerAddress}`);
} else {
	console.log(`Direct Account:`);
	console.log(`  Cap ID: ${account.accountCap.objectId}`);
	console.log(`  Owner: ${account.accountCap.walletAddress}`);
}

// Access common fields
console.log(`Account ID: ${account.accountCap.accountId}`);
console.log(`Collateral Type: ${account.accountCap.collateralCoinType}`);
```

***

### Agent Wallet Methods

{% hint style="info" %}
Want to find out more about Agent Wallets? [Read more.](https://docs.aftermath.finance/perpetuals/architecture/account/agent-wallets)
{% endhint %}

#### `getGrantAgentWalletTx`

```typescript
async getGrantAgentWalletTx(inputs: {
  recipientAddress: SuiAddress;
  tx?: Transaction;
}): Promise<{ tx: Transaction }>
```

Build a transaction that grants Agent Wallet (assistant permissions) for this perpetuals account.

**What This Does:**

Grants trading permissions to another wallet address, allowing it to execute trading operations on behalf of this account without being able to withdraw funds. This is useful for:

* Automated trading bots
* Portfolio managers
* Trading assistants
* Third-party trading services

**Important:**

* **Only supported for direct accounts**, NOT vault accounts
* Transaction must be signed by the account admin wallet
* Agent wallets can perform all trading actions EXCEPT:
  * Withdrawing collateral
  * Granting or revoking other agent wallets
* Throws error if called on a vault account

**Parameters:**

* **`recipientAddress`**: `SuiAddress`
  * Wallet address to receive agent permissions
  * This wallet will be able to trade on behalf of the account
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Grant agent wallet to trading bot
const { tx } = await account.getGrantAgentWalletTx({
	recipientAddress: "0xTRADING_BOT_ADDRESS",
});

// Sign and execute with ADMIN wallet
// await adminWallet.signAndExecuteTransaction({ transaction: tx });

console.log("Agent wallet granted to trading bot");

// Grant to multiple agents
async function grantMultipleAgents(agentAddresses: string[]) {
	const tx = new Transaction();

	for (const agentAddress of agentAddresses) {
		const { tx: grantTx } = await account.getGrantAgentWalletTx({
			recipientAddress: agentAddress,
			tx,
		});
	}

	console.log(`Granting agent access to ${agentAddresses.length} wallets`);
	return tx;
}

// Usage
await grantMultipleAgents([
	"0xBOT_1_ADDRESS",
	"0xBOT_2_ADDRESS",
	"0xMANAGER_ADDRESS",
]);

// Grant with validation
async function grantAgentWithValidation(
	recipientAddress: string,
): Promise<Transaction | null> {
	// Validate recipient address
	if (!recipientAddress.startsWith("0x") || recipientAddress.length !== 66) {
		console.error("Invalid recipient address format");
		return null;
	}

	// Check if already an agent (you'd need to track this separately)
	// For demonstration:
	const existingAgents = ["0xEXISTING_AGENT_1", "0xEXISTING_AGENT_2"];
	if (existingAgents.includes(recipientAddress)) {
		console.error("Address already has agent permissions");
		return null;
	}

	try {
		const { tx } = await account.getGrantAgentWalletTx({
			recipientAddress,
		});

		console.log(`✓ Agent wallet grant prepared for ${recipientAddress}`);
		return tx;
	} catch (error) {
		if (error.message.includes("not supported by vault")) {
			console.error("Cannot grant agent wallet on vault account");
		} else {
			console.error("Failed to grant agent wallet:", error);
		}
		return null;
	}
}

// Automated trading bot setup
async function setupTradingBot(botAddress: string) {
	console.log("Setting up automated trading bot...");

	// Step 1: Grant agent permissions
	const { tx: grantTx } = await account.getGrantAgentWalletTx({
		recipientAddress: botAddress,
	});

	await adminWallet.signAndExecuteTransaction({ transaction: grantTx });
	console.log("✓ Agent permissions granted");

	// Step 2: Allocate some collateral for trading
	const { tx: allocateTx } = await account.getAllocateCollateralTx({
		marketId: "0xBTC_MARKET",
		allocateAmount: 5_000n * 1_000_000n, // 5,000 USDC
	});

	await adminWallet.signAndExecuteTransaction({ transaction: allocateTx });
	console.log("✓ Collateral allocated");

	console.log(`Trading bot ${botAddress} is ready to trade`);
}

// Portfolio manager delegation
async function delegateToPortfolioManager(
	managerAddress: string,
	markets: string[],
) {
	// Grant agent permissions
	const { tx: grantTx } = await account.getGrantAgentWalletTx({
		recipientAddress: managerAddress,
	});

	await adminWallet.signAndExecuteTransaction({ transaction: grantTx });

	console.log(`Portfolio manager ${managerAddress} granted access to:`);
	for (const marketId of markets) {
		console.log(`  - Market: ${marketId}`);
	}

	console.log("\nManager can now:");
	console.log("  ✓ Place market and limit orders");
	console.log("  ✓ Cancel orders");
	console.log("  ✓ Set stop-loss and take-profit");
	console.log("  ✓ Adjust leverage");
	console.log("  ✓ Allocate/deallocate collateral between markets");
	console.log("\nManager CANNOT:");
	console.log("  ✗ Withdraw collateral from account");
	console.log("  ✗ Grant or revoke other agent wallets");
}

// Error handling
try {
	const { tx } = await account.getGrantAgentWalletTx({
		recipientAddress: "0xBOT_ADDRESS",
	});

	// Execute with admin wallet
	await adminWallet.signAndExecuteTransaction({ transaction: tx });
} catch (error) {
	if (error.message.includes("not supported by vault")) {
		console.error("Agent wallets are only available for direct accounts");
		console.error("Vault accounts use the vault owner's permissions");
	} else {
		console.error("Failed to grant agent wallet:", error);
	}
}
```

**Use Cases:**

1. **Trading Bots**: Grant permissions to automated trading systems
2. **Portfolio Management**: Allow managers to trade on behalf of users
3. **Trading Services**: Integrate with third-party trading platforms
4. **Team Trading**: Enable team members to execute trades
5. **Testing**: Create test agents for strategy development

***

#### `getRevokeAgentWalletTx`

```typescript
async getRevokeAgentWalletTx(inputs: {
  accountCapId: ObjectId;
  tx?: Transaction;
}): Promise<{ tx: Transaction }>
```

Build a transaction that revokes Agent Wallet (assistant capability) from this perpetuals account.

**What This Does:**

Removes trading permissions from an agent wallet, immediately terminating its ability to trade on behalf of the account. Use this to:

* Disable compromised agent wallets
* Remove inactive trading bots
* Revoke portfolio manager access
* Clean up unused permissions

**Important:**

* **Only supported for direct accounts**, NOT vault accounts
* Transaction must be signed by the account admin wallet
* Revoked wallet immediately loses all delegated permissions
* Agent wallet can no longer execute any trading operations
* Throws error if called on a vault account

**Parameters:**

* **`accountCapId`**: `ObjectId`
  * Object ID of the assistant capability to revoke
  * This is the capability object that was created when granting agent permissions
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Revoke single agent wallet
const { tx } = await account.getRevokeAgentWalletTx({
	accountCapId: "0xAGENT_CAP_OBJECT_ID",
});

// Sign and execute with ADMIN wallet
// await adminWallet.signAndExecuteTransaction({ transaction: tx });

console.log("Agent wallet revoked");

// Revoke multiple agent wallets
async function revokeMultipleAgents(agentCapIds: string[]) {
	const tx = new Transaction();

	for (const capId of agentCapIds) {
		const { tx: revokeTx } = await account.getRevokeAgentWalletTx({
			accountCapId: capId,
			tx,
		});
	}

	console.log(`Revoking ${agentCapIds.length} agent wallets`);
	return tx;
}

// Usage
await revokeMultipleAgents(["0xAGENT_CAP_1", "0xAGENT_CAP_2", "0xAGENT_CAP_3"]);

// Revoke with confirmation
async function revokeAgentWithConfirmation(
	agentCapId: string,
	agentAddress: string,
): Promise<Transaction | null> {
	console.log(`⚠️  Preparing to revoke agent wallet:`);
	console.log(`   Agent Address: ${agentAddress}`);
	console.log(`   Capability ID: ${agentCapId}`);
	console.log(`   This action is immediate and cannot be undone`);

	// In a real application, you'd prompt for user confirmation here
	const confirmed = true; // Replace with actual confirmation logic

	if (!confirmed) {
		console.log("Revocation cancelled");
		return null;
	}

	try {
		const { tx } = await account.getRevokeAgentWalletTx({
			accountCapId: agentCapId,
		});

		console.log(`✓ Revocation transaction prepared`);
		return tx;
	} catch (error) {
		console.error("Failed to revoke agent wallet:", error);
		return null;
	}
}

// Emergency revoke all agents
async function emergencyRevokeAllAgents(
	agentCaps: Array<{
		capId: string;
		address: string;
	}>,
) {
	console.log(`🚨 EMERGENCY: Revoking all ${agentCaps.length} agent wallets`);

	const tx = new Transaction();

	for (const agent of agentCaps) {
		const { tx: revokeTx } = await account.getRevokeAgentWalletTx({
			accountCapId: agent.capId,
			tx,
		});

		console.log(`  Revoking: ${agent.address}`);
	}

	await adminWallet.signAndExecuteTransaction({ transaction: tx });

	console.log("✓ All agent wallets revoked");
	console.log("Account is now secured with admin-only access");
}

// Revoke inactive agents
async function revokeInactiveAgents(
	agents: Array<{
		capId: string;
		address: string;
		lastActive: number;
	}>,
	inactivityThresholdDays: number = 30,
) {
	const now = Date.now();
	const thresholdMs = inactivityThresholdDays * 86400000;

	const inactiveAgents = agents.filter(
		(agent) => now - agent.lastActive > thresholdMs,
	);

	if (inactiveAgents.length === 0) {
		console.log("No inactive agents to revoke");
		return null;
	}

	console.log(`Found ${inactiveAgents.length} inactive agents`);

	const tx = new Transaction();

	for (const agent of inactiveAgents) {
		const daysInactive = Math.floor((now - agent.lastActive) / 86400000);
		console.log(
			`  Revoking ${agent.address} (inactive for ${daysInactive} days)`,
		);

		const { tx: revokeTx } = await account.getRevokeAgentWalletTx({
			accountCapId: agent.capId,
			tx,
		});
	}

	return tx;
}

// Rotate agent wallet (revoke old, grant new)
async function rotateAgentWallet(
	oldAgentCapId: string,
	newAgentAddress: string,
) {
	console.log("Rotating agent wallet...");

	const tx = new Transaction();

	// Step 1: Revoke old agent
	const { tx: revokeTx } = await account.getRevokeAgentWalletTx({
		accountCapId: oldAgentCapId,
		tx,
	});

	console.log("  Step 1: Old agent revoked");

	// Step 2: Grant to new agent
	const { tx: grantTx } = await account.getGrantAgentWalletTx({
		recipientAddress: newAgentAddress,
		tx,
	});

	console.log("  Step 2: New agent granted");

	await adminWallet.signAndExecuteTransaction({ transaction: tx });

	console.log("✓ Agent wallet rotation complete");
	console.log(`  New agent: ${newAgentAddress}`);
}

// Audit and revoke suspicious agents
async function auditAndRevokeAgents(
	agents: Array<{
		capId: string;
		address: string;
		totalTrades: number;
		totalVolume: number;
		lastTrade: number;
	}>,
) {
	const suspicious: string[] = [];

	for (const agent of agents) {
		// Check for suspicious patterns
		const avgTradeSize = agent.totalVolume / agent.totalTrades;
		const daysSinceLastTrade = (Date.now() - agent.lastTrade) / 86400000;

		if (avgTradeSize > 100000) {
			console.warn(
				`⚠️  ${agent.address}: Unusually large average trade size`,
			);
			suspicious.push(agent.capId);
		}

		if (agent.totalTrades > 1000 && daysSinceLastTrade > 7) {
			console.warn(
				`⚠️  ${agent.address}: High activity then sudden stop`,
			);
			suspicious.push(agent.capId);
		}
	}

	if (suspicious.length > 0) {
		console.log(`\nRevoking ${suspicious.length} suspicious agent wallets`);
		await revokeMultipleAgents(suspicious);
	} else {
		console.log("No suspicious agent activity detected");
	}
}

// Error handling
try {
	const { tx } = await account.getRevokeAgentWalletTx({
		accountCapId: "0xAGENT_CAP_ID",
	});

	await adminWallet.signAndExecuteTransaction({ transaction: tx });
	console.log("Agent wallet successfully revoked");
} catch (error) {
	if (error.message.includes("not supported by vault")) {
		console.error(
			"Agent wallet revocation not available for vault accounts",
		);
	} else {
		console.error("Failed to revoke agent wallet:", error);
	}
}
```

**Use Cases:**

1. **Security**: Revoke compromised or suspicious agent wallets
2. **Lifecycle Management**: Remove inactive or retired trading bots
3. **Access Control**: Update permissions when roles change
4. **Emergency Response**: Quickly disable all agents in case of issues
5. **Rotation**: Regularly rotate agent credentials for security

***

### Collateral Transaction Methods

#### `getDepositCollateralTx`

```typescript
async getDepositCollateralTx(inputs: {
  tx?: Transaction;
  isSponsoredTx?: boolean;
} & (
  | { depositAmount: Balance }
  | { depositCoinArg: TransactionObjectArgument }
)): Promise<{ tx: Transaction }>
```

Build a `deposit-collateral` transaction to add collateral to this account.

**What This Does:**

Deposits collateral from the wallet into the Perpetuals account, increasing available collateral for trading.

**Important:**

* **Only supported for direct accounts**, not vault accounts
* For vaults, use `PerpetualsVault.getAdminDepositTx()` instead
* Throws error if called on a vault account

**Parameters:**

* **`tx`** (optional): `Transaction`
  * Existing transaction to extend
  * If omitted, creates new transaction
* **`isSponsoredTx`** (optional): `boolean`
  * Whether transaction is gas-sponsored
* **Deposit Amount** (choose one):
  * **`depositAmount`**: `Balance` (bigint)
    * Amount to deposit in collateral units
    * API will select/merge coins as needed
  * **`depositCoinArg`**: `TransactionObjectArgument`
    * Transaction coin argument from previous commands
    * Use when building complex transactions

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Basic deposit
const { tx } = await account.getDepositCollateralTx({
	depositAmount: 10n * 1_000_000n, // 10 USDC
});

// Sign and execute
// const result = await wallet.signAndExecuteTransaction({ transaction: tx });

console.log("Deposit transaction built");

// Deposit with existing transaction
const existingTx = new Transaction();
// ... other commands

const { tx: depositTx } = await account.getDepositCollateralTx({
	depositAmount: 5n * 1_000_000n,
	tx: existingTx,
});

// Gas-sponsored deposit
const { tx: sponsoredTx } = await account.getDepositCollateralTx({
	depositAmount: 10n * 1_000_000n,
	isSponsoredTx: true,
});

// Deposit using coin from transaction
const coinTx = new Transaction();
const [coin] = coinTx.splitCoins(coinTx.gas, [10n * 1_000_000n]);

const { tx: coinDepositTx } = await account.getDepositCollateralTx({
	depositCoinArg: coin,
	tx: coinTx,
});

// Multiple deposits in one transaction
async function batchDeposit(amounts: bigint[]) {
	const tx = new Transaction();

	for (const amount of amounts) {
		const { tx: depositTx } = await account.getDepositCollateralTx({
			depositAmount: amount,
			tx,
		});
	}

	return tx;
}

// Conditional deposit based on account state
async function depositIfNeeded(targetCollateral: number) {
	const currentCollateral = account.collateral();

	if (currentCollateral < targetCollateral) {
		const needed = targetCollateral - currentCollateral;
		const depositAmount = BigInt(Math.ceil(needed * 1_000_000));

		console.log(`Depositing ${needed} USDC to reach target`);

		const { tx } = await account.getDepositCollateralTx({
			depositAmount,
		});

		return tx;
	}

	console.log("Collateral sufficient, no deposit needed");
	return null;
}

// Error handling
try {
	const { tx } = await account.getDepositCollateralTx({
		depositAmount: 10n * 1_000_000n,
	});
} catch (error) {
	if (error.message.includes("not supported for vaults")) {
		console.error("Cannot deposit to vault account directly");
		console.error("Use PerpetualsVault.getAdminDepositTx() instead");
	} else {
		console.error("Deposit failed:", error);
	}
}
```

**Use Cases:**

1. **Initial Funding**: Fund new account for trading
2. **Margin Top-Up**: Add collateral to avoid liquidation
3. **Position Scaling**: Increase collateral before opening larger positions
4. **Batch Funding**: Deposit multiple times in single transaction

***

#### `getWithdrawCollateralTx`

```typescript
async getWithdrawCollateralTx(inputs: {
  withdrawAmount: Balance;
  recipientAddress?: SuiAddress;
  tx?: Transaction;
}): Promise<{
  tx: Transaction;
  coinOutArg?: TransactionObjectArgument;
}>
```

Build a `withdraw-collateral` transaction to remove collateral from this account.

**What This Does:**

Withdraws free collateral from the Perpetuals account back to a wallet or makes it available as a transaction output.

**Important:**

* **Only supported for direct accounts**, not vault accounts
* For vaults, use `PerpetualsVault.getAdminWithdrawTx()` instead
* Can only withdraw available (unallocated) collateral
* Throws error if called on a vault account

**Parameters:**

* **`withdrawAmount`**: `Balance` (bigint)
  * Amount of collateral to withdraw
  * Must not exceed available collateral
* **`recipientAddress`** (optional): `SuiAddress`
  * Address to receive withdrawn coins
  * If provided: coins automatically transferred
  * If omitted: coins exposed as `coinOutArg` for further use
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction to sign and execute
* **`coinOutArg`** (optional): `TransactionObjectArgument`
  * Transaction argument for withdrawn coins
  * Only present if `recipientAddress` not provided
  * Can be used in subsequent transaction commands

**Example:**

```typescript
// Basic withdrawal with auto-transfer
const { tx } = await account.getWithdrawCollateralTx({
	withdrawAmount: 5n * 1_000_000n, // 5 USDC
	recipientAddress: "0xUSER_ADDRESS",
});

// Sign and execute
// const result = await wallet.signAndExecuteTransaction({ transaction: tx });

console.log("Withdrawal transaction built");

// Withdraw without recipient (get coin output)
const { tx: withdrawTx, coinOutArg } = await account.getWithdrawCollateralTx({
	withdrawAmount: 5n * 1_000_000n,
});

// Use withdrawn coin in subsequent commands
if (coinOutArg) {
	// Transfer to specific address
	withdrawTx.transferObjects([coinOutArg], "0xRECIPIENT");

	// Or split into multiple outputs
	const [coin1, coin2] = withdrawTx.splitCoins(coinOutArg, [
		2n * 1_000_000n,
		3n * 1_000_000n,
	]);

	withdrawTx.transferObjects([coin1], "0xRECIPIENT1");
	withdrawTx.transferObjects([coin2], "0xRECIPIENT2");
}

// Withdraw all available collateral
const availableCollateral = account.collateral();
const withdrawAll = BigInt(Math.floor(availableCollateral * 1_000_000));

const { tx: withdrawAllTx } = await account.getWithdrawCollateralTx({
	withdrawAmount: withdrawAll,
	recipientAddress: "0xUSER_ADDRESS",
});

console.log(`Withdrawing all ${availableCollateral} USDC`);

// Conditional withdrawal
async function withdrawExcess(targetCollateral: number) {
	const currentCollateral = account.collateral();

	if (currentCollateral > targetCollateral) {
		const excess = currentCollateral - targetCollateral;
		const withdrawAmount = BigInt(Math.floor(excess * 1_000_000));

		console.log(`Withdrawing excess ${excess} USDC`);

		const { tx } = await account.getWithdrawCollateralTx({
			withdrawAmount,
			recipientAddress: "0xUSER_ADDRESS",
		});

		return tx;
	}

	console.log("No excess collateral to withdraw");
	return null;
}

// Validate withdrawal amount
function validateWithdrawal(requestedAmount: number): boolean {
	const available = account.collateral();

	if (requestedAmount > available) {
		console.error(
			`Cannot withdraw ${requestedAmount} (only ${available} available)`,
		);
		return false;
	}

	if (requestedAmount <= 0) {
		console.error("Withdrawal amount must be positive");
		return false;
	}

	return true;
}

// Safe withdrawal with validation
async function safeWithdraw(amount: number, recipient: SuiAddress) {
	if (!validateWithdrawal(amount)) {
		return null;
	}

	const withdrawAmount = BigInt(Math.floor(amount * 1_000_000));

	try {
		const { tx } = await account.getWithdrawCollateralTx({
			withdrawAmount,
			recipientAddress: recipient,
		});

		console.log(`✓ Withdrawal of ${amount} USDC ready`);
		return tx;
	} catch (error) {
		console.error("Withdrawal failed:", error);
		return null;
	}
}

// Withdraw and swap pattern
async function withdrawAndSwap(withdrawAmount: bigint, targetCoin: string) {
	// Withdraw without recipient to get coin
	const { tx, coinOutArg } = await account.getWithdrawCollateralTx({
		withdrawAmount,
	});

	if (!coinOutArg) {
		throw new Error("No coin output received");
	}

	// Add swap command to same transaction
	// const swappedCoin = tx.moveCall({
	//   target: `${DEX_PACKAGE}::router::swap`,
	//   arguments: [coinOutArg, targetCoin],
	// });

	// Transfer swapped coin to user
	// tx.transferObjects([swappedCoin], "0xUSER_ADDRESS");

	return tx;
}
```

**Use Cases:**

1. **Profit Taking**: Withdraw profits after successful trades
2. **Portfolio Rebalancing**: Move funds between accounts
3. **Margin Reduction**: Reduce collateral when over-capitalized
4. **Complex Flows**: Withdraw and immediately use in other protocols

***

#### `getAllocateCollateralTx`

```typescript
async getAllocateCollateralTx(inputs: {
  marketId: PerpetualsMarketId;
  allocateAmount: Balance;
  tx?: Transaction;
}): Promise<{ tx: Transaction }>
```

Build an `allocate-collateral` transaction to move collateral from general account balance into a specific market.

**What This Does:**

Allocates (locks) collateral to a specific market/clearing house, making it available for trading in that market. This is typically done automatically during order placement, but can be done manually for advanced use cases.

**Important:**

* Works for both direct accounts and vault accounts
* Allocated collateral is locked to that market
* Can improve margin calculations for existing positions

**Parameters:**

* **`marketId`**: `PerpetualsMarketId`
  * Market to allocate collateral to
  * Must be a valid market ID
* **`allocateAmount`**: `Balance` (bigint)
  * Amount of collateral to allocate
  * Must not exceed available collateral
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Allocate collateral to a market
const { tx } = await account.getAllocateCollateralTx({
	marketId: "0xMARKET_ID",
	allocateAmount: 10n * 1_000_000n, // 10 USDC
});

// Sign and execute
// const result = await wallet.signAndExecuteTransaction({ transaction: tx });

console.log("Allocation transaction built");

// Allocate to multiple markets
async function allocateToMarkets(
	allocations: Array<{ marketId: string; amount: bigint }>,
) {
	const tx = new Transaction();

	for (const { marketId, amount } of allocations) {
		const { tx: allocTx } = await account.getAllocateCollateralTx({
			marketId,
			allocateAmount: amount,
			tx,
		});
	}

	console.log(`Allocated to ${allocations.length} markets`);
	return tx;
}

// Usage
await allocateToMarkets([
	{ marketId: "0xBTC_MARKET", amount: 10n * 1_000_000n },
	{ marketId: "0xETH_MARKET", amount: 5n * 1_000_000n },
	{ marketId: "0xSUI_MARKET", amount: 3n * 1_000_000n },
]);

// Pre-allocate before trading
async function prepareForTrading(
	marketId: string,
	targetLeverage: number,
	positionSize: number,
	indexPrice: number,
) {
	// Calculate required collateral
	const positionValue = positionSize * indexPrice;
	const requiredCollateral = positionValue / targetLeverage;
	const allocateAmount = BigInt(Math.ceil(requiredCollateral * 1_000_000));

	console.log(
		`Allocating ${requiredCollateral} USDC for ${positionSize} position at ${targetLeverage}x`,
	);

	const { tx } = await account.getAllocateCollateralTx({
		marketId,
		allocateAmount,
	});

	return tx;
}

// Validate allocation
function validateAllocation(amount: number): boolean {
	const available = account.collateral();

	if (amount > available) {
		console.error(
			`Cannot allocate ${amount} (only ${available} available)`,
		);
		return false;
	}

	return true;
}

// Safe allocation with validation
async function safeAllocate(
	marketId: string,
	amount: number,
): Promise<Transaction | null> {
	if (!validateAllocation(amount)) {
		return null;
	}

	const allocateAmount = BigInt(Math.floor(amount * 1_000_000));

	try {
		const { tx } = await account.getAllocateCollateralTx({
			marketId,
			allocateAmount,
		});

		console.log(`✓ Allocated ${amount} USDC to market ${marketId}`);
		return tx;
	} catch (error) {
		console.error("Allocation failed:", error);
		return null;
	}
}

// Rebalance allocations across markets
async function rebalanceAllocations(targetAllocations: Record<string, number>) {
	const tx = new Transaction();

	// Get current positions to determine current allocations
	for (const position of account.account.positions) {
		const targetAlloc = targetAllocations[position.marketId] || 0;
		const currentAlloc = position.collateral;
		const difference = targetAlloc - currentAlloc;

		if (difference > 0) {
			// Need to allocate more
			const { tx: allocTx } = await account.getAllocateCollateralTx({
				marketId: position.marketId,
				allocateAmount: BigInt(Math.floor(difference * 1_000_000)),
				tx,
			});
		} else if (difference < 0) {
			// Need to deallocate
			const { tx: deallocTx } = await account.getDeallocateCollateralTx({
				marketId: position.marketId,
				deallocateAmount: BigInt(
					Math.floor(Math.abs(difference) * 1_000_000),
				),
				tx,
			});
		}
	}

	return tx;
}
```

**Use Cases:**

1. **Position Preparation**: Allocate before placing large orders
2. **Margin Management**: Manually control market-specific collateral
3. **Multi-Market Strategy**: Pre-allocate to multiple markets
4. **Risk Isolation**: Separate collateral across markets

***

#### `getDeallocateCollateralTx`

```typescript
async getDeallocateCollateralTx(inputs: {
  marketId: PerpetualsMarketId;
  deallocateAmount: Balance;
  tx?: Transaction;
}): Promise<{ tx: Transaction }>
```

Build a `deallocate-collateral` transaction to move collateral from a specific market back to general account balance.

**What This Does:**

Deallocates (unlocks) collateral from a specific market, returning it to the account's available balance. This is the opposite of `getAllocateCollateralTx`.

**Important:**

* Works for both direct accounts and vault accounts
* Can only deallocate free collateral not backing positions/orders
* May affect margin ratios for positions in that market

**Parameters:**

* **`marketId`**: `PerpetualsMarketId`
  * Market to deallocate collateral from
* **`deallocateAmount`**: `Balance` (bigint)
  * Amount of collateral to deallocate
  * Must not exceed free collateral in that market
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Deallocate collateral from a market
const { tx } = await account.getDeallocateCollateralTx({
	marketId: "0xMARKET_ID",
	deallocateAmount: 5n * 1_000_000n, // 5 USDC
});

// Sign and execute
// const result = await wallet.signAndExecuteTransaction({ transaction: tx });

console.log("Deallocation transaction built");

// Deallocate from multiple markets
async function deallocateFromMarkets(
	deallocations: Array<{ marketId: string; amount: bigint }>,
) {
	const tx = new Transaction();

	for (const { marketId, amount } of deallocations) {
		const { tx: deallocTx } = await account.getDeallocateCollateralTx({
			marketId,
			deallocateAmount: amount,
			tx,
		});
	}

	console.log(`Deallocated from ${deallocations.length} markets`);
	return tx;
}

// Deallocate all free collateral from a market
async function deallocateAllFromMarket(marketId: string) {
	const position = account.positionForMarketId({ marketId });

	if (!position) {
		console.log("No position in this market");
		return null;
	}

	const freeCollateral = position.freeCollateral;

	if (freeCollateral <= 0) {
		console.log("No free collateral to deallocate");
		return null;
	}

	const deallocateAmount = BigInt(Math.floor(freeCollateral * 1_000_000));

	console.log(`Deallocating all free collateral: ${freeCollateral} USDC`);

	const { tx } = await account.getDeallocateCollateralTx({
		marketId,
		deallocateAmount,
	});

	return tx;
}

// Consolidate collateral after closing positions
async function consolidateCollateral() {
	const tx = new Transaction();

	for (const position of account.account.positions) {
		// If position is closed (no size), deallocate all collateral
		if (position.baseAssetAmount === 0 && position.collateral > 0) {
			const deallocateAmount = BigInt(
				Math.floor(position.collateral * 1_000_000),
			);

			console.log(
				`Consolidating ${position.collateral} USDC from ${position.marketId}`,
			);

			const { tx: deallocTx } = await account.getDeallocateCollateralTx({
				marketId: position.marketId,
				deallocateAmount,
				tx,
			});
		}
	}

	return tx;
}

// Rebalance collateral for leverage adjustment
async function adjustLeverageViaCollateral(
	marketId: string,
	targetLeverage: number,
) {
	const position = account.positionForMarketId({ marketId });

	if (!position || position.baseAssetAmount === 0) {
		console.log("No position to adjust");
		return null;
	}

	const currentLeverage = position.leverage;
	const positionValue = Math.abs(
		position.baseAssetAmount * position.entryPrice,
	);
	const targetCollateral = positionValue / targetLeverage;
	const currentCollateral = position.collateral;
	const difference = targetCollateral - currentCollateral;

	console.log(
		`Adjusting leverage from ${currentLeverage}x to ${targetLeverage}x`,
	);
	console.log(`Current collateral: ${currentCollateral}`);
	console.log(`Target collateral: ${targetCollateral}`);

	if (difference > 0) {
		// Need to allocate more
		const allocateAmount = BigInt(Math.ceil(difference * 1_000_000));
		return await account.getAllocateCollateralTx({
			marketId,
			allocateAmount,
		});
	} else if (difference < 0) {
		// Need to deallocate
		const deallocateAmount = BigInt(
			Math.floor(Math.abs(difference) * 1_000_000),
		);
		return await account.getDeallocateCollateralTx({
			marketId,
			deallocateAmount,
		});
	}

	console.log("Already at target leverage");
	return null;
}

// Safety check before deallocation
async function safeDeallocate(
	marketId: string,
	amount: number,
): Promise<Transaction | null> {
	const position = account.positionForMarketId({ marketId });

	if (!position) {
		console.error("No position in this market");
		return null;
	}

	if (amount > position.freeCollateral) {
		console.error(
			`Cannot deallocate ${amount} (only ${position.freeCollateral} free)`,
		);
		return null;
	}

	const deallocateAmount = BigInt(Math.floor(amount * 1_000_000));

	try {
		const { tx } = await account.getDeallocateCollateralTx({
			marketId,
			deallocateAmount,
		});

		console.log(`✓ Deallocated ${amount} USDC from market`);
		return tx;
	} catch (error) {
		console.error("Deallocation failed:", error);
		return null;
	}
}
```

**Use Cases:**

1. **Collateral Consolidation**: Move free collateral to main balance
2. **Leverage Reduction**: Free up collateral by reducing leverage
3. **Market Exit**: Deallocate after closing positions
4. **Portfolio Rebalancing**: Reallocate collateral across markets

***

#### `getTransferCollateralTx`

```typescript
async getTransferCollateralTx(inputs: {
  transferAmount: Balance;
  toAccountId: PerpetualsAccountId;
  tx?: Transaction;
}): Promise<{ tx: Transaction }>
```

Build a `transfer-collateral` transaction to move collateral between two Perpetuals accounts.

**What This Does:**

Transfers collateral from this account to another Perpetuals account. Both accounts must use the same collateral type.

**Important:**

* **Only supported for direct accounts**, NOT vault accounts
* Both accounts must use the same collateral coin type
* Throws error if called on a vault account
* Requires sufficient available collateral

**Parameters:**

* **`transferAmount`**: `Balance` (bigint)
  * Amount of collateral to transfer
  * Must not exceed available collateral
* **`toAccountId`**: `PerpetualsAccountId` (bigint)
  * Destination account ID
  * Must be a valid Perpetuals account with matching collateral type
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Transfer collateral to another account
const { tx } = await account.getTransferCollateralTx({
	transferAmount: 10n * 1_000_000n, // 10 USDC
	toAccountId: 456n, // Destination account ID
});

// Sign and execute
// const result = await wallet.signAndExecuteTransaction({ transaction: tx });

console.log("Transfer transaction built");

// Transfer all available collateral
const availableCollateral = account.collateral();
const transferAll = BigInt(Math.floor(availableCollateral * 1_000_000));

const { tx: transferAllTx } = await account.getTransferCollateralTx({
	transferAmount: transferAll,
	toAccountId: 456n,
});

console.log(`Transferring all ${availableCollateral} USDC`);

// Multi-account funding pattern
async function fundSubAccounts(
	subAccountIds: bigint[],
	amountPerAccount: number,
) {
	const tx = new Transaction();
	const transferAmount = BigInt(Math.floor(amountPerAccount * 1_000_000));

	for (const toAccountId of subAccountIds) {
		const { tx: transferTx } = await account.getTransferCollateralTx({
			transferAmount,
			toAccountId,
			tx,
		});
	}

	console.log(
		`Funded ${subAccountIds.length} sub-accounts with ${amountPerAccount} USDC each`,
	);
	return tx;
}

// Rebalance between accounts
async function rebalanceAccounts(
	fromAccount: PerpetualsAccount,
	toAccount: PerpetualsAccount,
	targetBalance: number,
) {
	const fromBalance = fromAccount.collateral();
	const toBalance = toAccount.collateral();

	const totalBalance = fromBalance + toBalance;
	const fromTarget = totalBalance / 2;

	if (fromBalance > fromTarget) {
		const excess = fromBalance - fromTarget;
		const transferAmount = BigInt(Math.floor(excess * 1_000_000));

		console.log(`Transferring ${excess} USDC to balance accounts`);

		const { tx } = await fromAccount.getTransferCollateralTx({
			transferAmount,
			toAccountId: toAccount.accountId(),
		});

		return tx;
	}

	console.log("Accounts already balanced");
	return null;
}

// Validate transfer
function validateTransfer(amount: number, toAccountId: bigint): boolean {
	const available = account.collateral();

	if (amount > available) {
		console.error(
			`Cannot transfer ${amount} (only ${available} available)`,
		);
		return false;
	}

	if (amount <= 0) {
		console.error("Transfer amount must be positive");
		return false;
	}

	if (toAccountId === account.accountId()) {
		console.error("Cannot transfer to same account");
		return false;
	}

	return true;
}

// Safe transfer with validation
async function safeTransfer(
	amount: number,
	toAccountId: bigint,
): Promise<Transaction | null> {
	if (!validateTransfer(amount, toAccountId)) {
		return null;
	}

	try {
		const transferAmount = BigInt(Math.floor(amount * 1_000_000));

		const { tx } = await account.getTransferCollateralTx({
			transferAmount,
			toAccountId,
		});

		console.log(
			`✓ Transfer of ${amount} USDC to account ${toAccountId} ready`,
		);
		return tx;
	} catch (error) {
		if (error.message.includes("not supported by vault")) {
			console.error("Cannot transfer from vault account");
		} else {
			console.error("Transfer failed:", error);
		}
		return null;
	}
}

// Emergency fund consolidation
async function consolidateToMainAccount(
	subAccounts: PerpetualsAccount[],
	mainAccountId: bigint,
) {
	const transactions: Transaction[] = [];

	for (const subAccount of subAccounts) {
		const available = subAccount.collateral();

		if (available > 0) {
			const transferAmount = BigInt(Math.floor(available * 1_000_000));

			console.log(
				`Transferring ${available} from account ${subAccount.accountId()}`,
			);

			const { tx } = await subAccount.getTransferCollateralTx({
				transferAmount,
				toAccountId: mainAccountId,
			});

			transactions.push(tx);
		}
	}

	console.log(`Consolidated ${transactions.length} sub-accounts`);
	return transactions;
}

// Account migration pattern
async function migrateToNewAccount(
	oldAccount: PerpetualsAccount,
	newAccountId: bigint,
) {
	// 1. Close all positions in old account
	// 2. Deallocate all collateral
	// 3. Transfer to new account

	const available = oldAccount.collateral();
	const transferAmount = BigInt(Math.floor(available * 1_000_000));

	console.log(`Migrating ${available} USDC to new account ${newAccountId}`);

	const { tx } = await oldAccount.getTransferCollateralTx({
		transferAmount,
		toAccountId: newAccountId,
	});

	return tx;
}
```

**Use Cases:**

1. **Account Consolidation**: Move funds between user accounts
2. **Sub-Account Management**: Fund trading sub-accounts
3. **Account Migration**: Move to new account
4. **Emergency Transfers**: Quickly move funds for risk management

***

### Order Transaction Methods

#### `getPlaceMarketOrderTx`

```typescript
async getPlaceMarketOrderTx(inputs: SdkPerpetualsPlaceMarketOrderInputs): Promise<{ tx: Transaction }>
```

Build a `place-market-order` transaction for opening or closing positions.

{% hint style="info" %}
Works for both direct accounts and vault accounts.
{% endhint %}

{% hint style="info" %}
Can attach SL/TP stop orders via `slTp` parameter.
{% endhint %}

**What This Does:**

Places a market order that executes immediately at the best available price. This is the primary method for:

* Opening new positions
* Adding to existing positions
* Closing positions (with `reduceOnly: true`)

**Parameters (via `SdkPerpetualsPlaceMarketOrderInputs`):**

* **`marketId`**: `PerpetualsMarketId`
  * Market to trade in
* **`side`**: `PerpetualsOrderSide`
  * `PerpetualsOrderSide.Bid` = Buy/Long
  * `PerpetualsOrderSide.Ask` = Sell/Short
* **`size`**: `bigint`
  * Order size in base asset units (scaled by `Casting.Fixed.fixedOneN9`)
  * Must be multiple of lot size
* **`collateralChange`**: `number`
  * Collateral to add (positive) or remove (negative)
  * Used for position margin adjustment
* **`reduceOnly`**: `boolean`
  * `true`: Can only reduce position size
  * `false`: Can open or increase position
* **`leverage`** (optional): `number`
  * Target leverage for position
  * If omitted, uses existing position leverage
* **`slTp`** (optional): Stop-loss/take-profit parameters
  * Attaches SL/TP orders to the trade
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

{% hint style="info" %}
Automatically derives `hasPosition` from account state.
{% endhint %}

**Returns:**

Object containing:

* **`tx`**: `Transaction` - Transaction ready to sign and execute

**Example:**

```typescript
// Open long position
const { tx } = await account.getPlaceMarketOrderTx({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9, // 1 BTC
	collateralChange: 5000, // Add 5000 USDC
	reduceOnly: false,
	leverage: 5,
});

// Execute
// await wallet.signAndExecuteTransaction({ transaction: tx });

// Close position (reduce only)
const position = account.positionForMarketId({ marketId: "0xMARKET_ID" });
const closeSide =
	position!.baseAssetAmount > 0
		? PerpetualsOrderSide.Ask
		: PerpetualsOrderSide.Bid;

const { tx: closeTx } = await account.getPlaceMarketOrderTx({
	marketId: "0xMARKET_ID",
	side: closeSide,
	size: BigInt(
		Math.abs(position!.baseAssetAmount * Casting.Fixed.fixedOneN9),
	),
	collateralChange: 0,
	reduceOnly: true,
});

// With SL/TP
const { tx: withSlTpTx } = await account.getPlaceMarketOrderTx({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9,
	collateralChange: 5000,
	reduceOnly: false,
	slTp: {
		stopLossIndexPrice: 40000, // Stop loss at $40k
		takeProfitIndexPrice: 50000, // Take profit at $50k
	},
});
```

***

#### `getPlaceLimitOrderTx`

```typescript
async getPlaceLimitOrderTx(inputs: SdkPerpetualsPlaceLimitOrderInputs): Promise<{ tx: Transaction }>
```

Build a `place-limit-order` transaction for limit orders.

**Example:**

```typescript
const { tx } = await account.getPlaceLimitOrderTx({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9,
	price: 42000,
	collateralChange: 5000,
	reduceOnly: false,
	orderType: PerpetualsOrderType.PostOnly,
	expiration: Date.now() + 86400000, // 1 day
});
```

***

#### `getPlaceScaleOrderTx`

```typescript
async getPlaceScaleOrderTx(inputs: SdkPerpetualsPlaceScaleOrderInputs): Promise<{ tx: Transaction }>
```

Build a `place-scale-order` transaction that distributes a total size across multiple limit orders evenly spaced between a start and end price.

**Parameters:**

* **`marketId`**: `PerpetualsMarketId`
  * Target market
* **`side`**: `PerpetualsOrderSide`
  * Order side (`Bid` = long, `Ask` = short)
* **`totalSize`**: `bigint`
  * Total size distributed across all orders (scaled by 1e9)
* **`startPrice`**: `bigint`
  * Starting price of the range (inclusive, scaled by 1e9)
* **`endPrice`**: `bigint`
  * Ending price of the range (inclusive, scaled by 1e9)
* **`numberOfOrders`**: `number`
  * Number of limit orders to place across the range
* **`orderType`**: `PerpetualsOrderType`
  * Order type (e.g. `Standard`, `PostOnly`, `ImmediateOrCancel`, `FillOrKill`)
* **`collateralChange`**: `number`
  * Collateral change associated with the order
* **`hasPosition`**: `boolean`
  * Whether the account already has a position in this market
* **`reduceOnly`**: `boolean`
  * If true, orders can only reduce an existing position
* **`cancelSlTp`**: `boolean`
  * True if position is closed
* **`sizeSkew`** (optional): `number`
  * Size ratio between last and first order. `1.0` = uniform distribution, `2.0` = last order is 2x the size of the first
* **`leverage`** (optional): `number`
  * Leverage override
* **`expiryTimestamp`** (optional): `bigint`
  * Expiration timestamp in milliseconds since epoch
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Example:**

```typescript
// Place 5 buy orders spread from $40,000 to $42,000
const { tx } = await account.getPlaceScaleOrderTx({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	totalSize: 5n * Casting.Fixed.fixedOneN9, // 5 units total
	startPrice: 40_000n * Casting.Fixed.fixedOneN9,
	endPrice: 42_000n * Casting.Fixed.fixedOneN9,
	numberOfOrders: 5,
	orderType: PerpetualsOrderType.PostOnly,
	collateralChange: 25000,
	hasPosition: false,
	reduceOnly: false,
	cancelSlTp: false,
});

// Scale order with size skew (larger orders at lower prices)
const { tx: skewedTx } = await account.getPlaceScaleOrderTx({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	totalSize: 10n * Casting.Fixed.fixedOneN9,
	startPrice: 38_000n * Casting.Fixed.fixedOneN9,
	endPrice: 42_000n * Casting.Fixed.fixedOneN9,
	numberOfOrders: 10,
	orderType: PerpetualsOrderType.Standard,
	collateralChange: 50000,
	hasPosition: true,
	reduceOnly: false,
	cancelSlTp: false,
	sizeSkew: 2.0, // Last order is 2x the size of the first
	leverage: 5,
});
```

***

#### `getCancelAndPlaceOrdersTx`

```typescript
async getCancelAndPlaceOrdersTx(inputs: SdkPerpetualsCancelAndPlaceOrdersInputs): Promise<{ tx: Transaction }>
```

Build a `cancel-and-place-orders` transaction that atomically cancels existing orders and places new ones in a single transaction. Useful for rebalancing order grids or replacing stale orders without intermediate exposure.

**Parameters:**

* **`marketId`**: `PerpetualsMarketId`
  * Target market
* **`orderIdsToCancle`**: `PerpetualsOrderId[]`
  * Order IDs to cancel
* **`ordersToPlace`**: `ApiPerpetualsOrderToPlace[]`
  * New orders to place after cancellation. Each order has:
    * `side`: `PerpetualsOrderSide` — order side
    * `price`: `bigint` — limit price (scaled by 1e9)
    * `size`: `bigint` — order size (scaled by 1e9)
* **`orderType`**: `PerpetualsOrderType`
  * Order type for the new orders
* **`reduceOnly`**: `boolean`
  * If true, placed orders can only reduce an existing position
* **`hasPosition`**: `boolean`
  * Whether the account already has a position in this market
* **`leverage`** (optional): `number`
  * Leverage override
* **`expiryTimestamp`** (optional): `bigint`
  * Expiration timestamp in milliseconds since epoch
* **`tx`** (optional): `Transaction`
  * Existing transaction to extend

**Example:**

```typescript
// Cancel two stale orders and replace with new ones
const { tx } = await account.getCancelAndPlaceOrdersTx({
	marketId: "0xMARKET_ID",
	orderIdsToCancle: [12345n, 67890n],
	ordersToPlace: [
		{
			side: PerpetualsOrderSide.Bid,
			price: 41_000n * Casting.Fixed.fixedOneN9,
			size: 1n * Casting.Fixed.fixedOneN9,
		},
		{
			side: PerpetualsOrderSide.Bid,
			price: 40_500n * Casting.Fixed.fixedOneN9,
			size: 1n * Casting.Fixed.fixedOneN9,
		},
		{
			side: PerpetualsOrderSide.Ask,
			price: 43_000n * Casting.Fixed.fixedOneN9,
			size: 1n * Casting.Fixed.fixedOneN9,
		},
	],
	orderType: PerpetualsOrderType.PostOnly,
	reduceOnly: false,
	hasPosition: true,
	leverage: 5,
});
```

***

#### `getCancelOrdersTx`

```typescript
async getCancelOrdersTx(inputs: {
  tx?: Transaction;
  marketIdsToData: Record<PerpetualsMarketId, {
    orderIds: PerpetualsOrderId[];
    collateralChange: number;
    leverage: number;
  }>;
}): Promise<{ tx: Transaction }>
```

Build a `cancel-orders` transaction to cancel pending orders.

**Example:**

```typescript
const { tx } = await account.getCancelOrdersTx({
	marketIdsToData: {
		"0xMARKET_ID": {
			orderIds: [12345n, 67890n],
			collateralChange: -1000,
			leverage: 5,
		},
	},
});
```

***

#### `getCancelStopOrdersTx`

```typescript
async getCancelStopOrdersTx(inputs: {
  tx?: Transaction;
  stopOrderIds: ObjectId[];
}): Promise<{ tx: Transaction }>
```

Cancel stop-order tickets by their object IDs.

**Example:**

```typescript
const { tx } = await account.getCancelStopOrdersTx({
	stopOrderIds: ["0xSTOP_ORDER_1", "0xSTOP_ORDER_2"],
});
```

***

#### `getPlaceStopOrdersTx`

```typescript
async getPlaceStopOrdersTx(inputs: SdkPerpetualsPlaceStopOrdersInputs): Promise<{ tx: Transaction }>
```

Place one or more stop orders in a single transaction.

**Example:**

```typescript
const { tx } = await account.getPlaceStopOrdersTx({
	stopOrders: [
		{
			marketId: "0xMARKET_ID",
			side: PerpetualsOrderSide.Ask,
			size: 1n * Casting.Fixed.fixedOneN9,
			triggerPrice: 40000,
			limitPrice: 39900,
		},
	],
});
```

***

#### `getPlaceSlTpOrdersTx`

```typescript
async getPlaceSlTpOrdersTx(inputs: SdkPerpetualsPlaceSlTpOrdersInputs): Promise<{ tx: Transaction }>
```

Place SL/TP orders for an existing position.

{% hint style="info" %}
Requires an existing position in the market.
{% endhint %}

**Example:**

```typescript
const { tx } = await account.getPlaceSlTpOrdersTx({
	marketId: "0xMARKET_ID",
	stopLossIndexPrice: 40000,
	takeProfitIndexPrice: 50000,
});
```

***

#### `getEditStopOrdersTx`

```typescript
async getEditStopOrdersTx(inputs: {
  stopOrders: StopOrderUpdate[];
  tx?: Transaction;
}): Promise<{ tx: Transaction }>
```

Edit existing stop orders.

***

#### `getSetLeverageTx`

```typescript
async getSetLeverageTx(inputs: {
  tx?: Transaction;
  leverage: number;
  collateralChange: number;
  marketId: PerpetualsMarketId;
}): Promise<{ tx: Transaction }>
```

Update leverage for a position in a market.

**Example:**

```typescript
const { tx } = await account.getSetLeverageTx({
	marketId: "0xMARKET_ID",
	leverage: 10,
	collateralChange: -1000, // Remove 1000 USDC
});
```

***

### Stop Order Methods

#### `getStopOrdersMessageToSign`

```typescript
getStopOrdersMessageToSign(inputs?: {
  marketIds: PerpetualsMarketId[];
}): {
  action: string;
  account_id: string;
  clearing_house_ids: string[];
}
```

Build a deterministic message for signing when querying stop orders.

**What This Does:**

Creates an off-chain authentication message that must be signed to prove account ownership when fetching stop order data.

**Workflow:**

1. Call this method to get message
2. Sign message with wallet
3. Pass signed message to `getStopOrderDatas()`

**Example:**

```typescript
// Step 1: Get message to sign
const message = account.getStopOrdersMessageToSign({
	marketIds: ["0xMARKET_ID"],
});

console.log("Message to sign:", message);
// {
//   action: "GET_STOP_ORDERS",
//   account_id: "123",
//   clearing_house_ids: ["0xMARKET_ID"]
// }

// Step 2: Sign with wallet
const messageBytes = new TextEncoder().encode(JSON.stringify(message));
const { signature } = await wallet.signMessage({
	message: messageBytes,
});

// Step 3: Fetch stop orders
const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature,
	marketIds: ["0xMARKET_ID"],
});

console.log(`Found ${stopOrderDatas.length} stop orders`);
```

***

#### `nonSlTpStopOrderDatas`

```typescript
nonSlTpStopOrderDatas(inputs: {
  stopOrderDatas: PerpetualsStopOrderData[];
}): PerpetualsStopOrderData[] | undefined
```

Filter stop orders to only include non-SL/TP orders.

**What This Does:**

Filters out all SL/TP stop orders from a list, returning only regular stop orders. A stop order is considered SL/TP if it appears in the combined set of SL/TP orders across all markets.

**Parameters:**

* **`stopOrderDatas`**: `PerpetualsStopOrderData[]`
  * Full array of stop order tickets to filter

**Returns:**

* `PerpetualsStopOrderData[] | undefined`
  * Array of non-SL/TP stop orders
  * `undefined` if no non-SL/TP orders exist

**Example:**

```typescript
// Get all stop orders
const message = account.getStopOrdersMessageToSign();
const messageBytes = new TextEncoder().encode(JSON.stringify(message));
const { signature } = await wallet.signMessage({ message: messageBytes });

const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature,
});

// Filter to only non-SL/TP orders
const regularStopOrders = account.nonSlTpStopOrderDatas({ stopOrderDatas });

if (regularStopOrders) {
	console.log(`Found ${regularStopOrders.length} regular stop orders`);

	for (const order of regularStopOrders) {
		console.log(`Stop Order ${order.objectId}:`);
		console.log(`  Market: ${order.marketId}`);
		console.log(`  Side: ${order.side}`);
		console.log(`  Size: ${Number(order.size) / Casting.Fixed.fixedOneN9}`);
		console.log(`  Trigger Price: ${order.triggerPrice}`);
	}
} else {
	console.log("No regular stop orders found");
}

// Cancel all regular stop orders
if (regularStopOrders) {
	const stopOrderIds = regularStopOrders.map((o) => o.objectId);

	const { tx } = await account.getCancelStopOrdersTx({
		stopOrderIds,
	});

	console.log(`Canceling ${stopOrderIds.length} regular stop orders`);
	// Execute transaction
}

// Display stop order breakdown
function categorizeStopOrders(stopOrderDatas: PerpetualsStopOrderData[]) {
	const regularOrders = account.nonSlTpStopOrderDatas({ stopOrderDatas });
	const slTpOrders = account.slTpStopOrderDatas({ stopOrderDatas });

	console.log(`=== Stop Order Breakdown ===`);
	console.log(`Total: ${stopOrderDatas.length}`);
	console.log(`Regular: ${regularOrders?.length || 0}`);
	console.log(`SL/TP: ${slTpOrders?.length || 0}`);
}

// Filter and manage by type
async function manageStopOrders() {
	// Get all stop orders
	const message = account.getStopOrdersMessageToSign();
	const { stopOrderDatas } = await account.getStopOrderDatas({
		bytes: JSON.stringify(message),
		signature: "...",
	});

	// Get regular orders
	const regularOrders = account.nonSlTpStopOrderDatas({ stopOrderDatas });

	// Get SL/TP orders
	const slTpOrders = account.slTpStopOrderDatas({ stopOrderDatas });

	console.log(`Managing ${stopOrderDatas.length} total stop orders`);
	console.log(`  Regular orders: ${regularOrders?.length || 0}`);
	console.log(`  SL/TP orders: ${slTpOrders?.length || 0}`);

	// Process each type differently
	if (regularOrders) {
		for (const order of regularOrders) {
			console.log(`Processing regular stop order: ${order.objectId}`);
			// Custom logic for regular stop orders
		}
	}

	if (slTpOrders) {
		for (const order of slTpOrders) {
			console.log(`Processing SL/TP order: ${order.objectId}`);
			// Custom logic for SL/TP orders
		}
	}
}
```

**Use Cases:**

1. **Order Management**: Separate regular stop orders from SL/TP for different handling
2. **UI Display**: Show different UI sections for different order types
3. **Batch Operations**: Cancel or edit specific order types
4. **Analytics**: Analyze regular stop order patterns

***

### SL/TP Methods

#### `slTpStopOrderDatas`

```typescript
slTpStopOrderDatas(inputs: {
  stopOrderDatas: PerpetualsStopOrderData[];
}): PerpetualsStopOrderData[] | undefined
```

Extract all SL/TP-style stop orders across all markets for this account.

**What This Does:**

Identifies and returns all stop orders that function as stop-loss or take-profit orders. These are stop orders that:

* Have an `slTp` payload
* Target the opposite side of the current position
* Have either `stopLossIndexPrice` or `takeProfitIndexPrice` set

**SL/TP Types:**

* **Full SL/TP**: Size >= `Casting.i64MaxBigInt` (close entire position)
* **Partial SL/TP**: Size < `Casting.i64MaxBigInt` (close partial position)

**Parameters:**

* **`stopOrderDatas`**: `PerpetualsStopOrderData[]`
  * Full list of stop order tickets

**Returns:**

* `PerpetualsStopOrderData[] | undefined`
  * Array of all SL/TP stop orders across all markets
  * `undefined` if no SL/TP orders exist

**Example:**

```typescript
// Get all stop orders
const message = account.getStopOrdersMessageToSign();
const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature: "...",
});

// Extract all SL/TP orders
const slTpOrders = account.slTpStopOrderDatas({ stopOrderDatas });

if (slTpOrders) {
	console.log(`Found ${slTpOrders.length} SL/TP orders`);

	for (const order of slTpOrders) {
		console.log(`\nSL/TP Order ${order.objectId}:`);
		console.log(`  Market: ${order.marketId}`);
		console.log(`  Side: ${order.side}`);

		const isFull = order.size >= Casting.i64MaxBigInt;
		console.log(`  Type: ${isFull ? "Full" : "Partial"}`);

		if (!isFull) {
			console.log(
				`  Size: ${Number(order.size) / Casting.Fixed.fixedOneN9}`,
			);
		}

		if (order.slTp?.stopLossIndexPrice) {
			console.log(`  Stop Loss: $${order.slTp.stopLossIndexPrice}`);
		}

		if (order.slTp?.takeProfitIndexPrice) {
			console.log(`  Take Profit: $${order.slTp.takeProfitIndexPrice}`);
		}
	}
} else {
	console.log("No SL/TP orders found");
}

// Count full vs partial SL/TP orders
function analyzeSLTPOrders(stopOrderDatas: PerpetualsStopOrderData[]) {
	const slTpOrders = account.slTpStopOrderDatas({ stopOrderDatas });

	if (!slTpOrders) {
		console.log("No SL/TP orders");
		return;
	}

	let fullCount = 0;
	let partialCount = 0;
	let stopLossCount = 0;
	let takeProfitCount = 0;

	for (const order of slTpOrders) {
		if (order.size >= Casting.i64MaxBigInt) {
			fullCount++;
		} else {
			partialCount++;
		}

		if (order.slTp?.stopLossIndexPrice) stopLossCount++;
		if (order.slTp?.takeProfitIndexPrice) takeProfitCount++;
	}

	console.log(`=== SL/TP Analysis ===`);
	console.log(`Total SL/TP Orders: ${slTpOrders.length}`);
	console.log(`  Full Position: ${fullCount}`);
	console.log(`  Partial Position: ${partialCount}`);
	console.log(`  Stop Loss: ${stopLossCount}`);
	console.log(`  Take Profit: ${takeProfitCount}`);
}

// Cancel all SL/TP orders
async function cancelAllSLTPOrders() {
	const message = account.getStopOrdersMessageToSign();
	const { stopOrderDatas } = await account.getStopOrderDatas({
		bytes: JSON.stringify(message),
		signature: "...",
	});

	const slTpOrders = account.slTpStopOrderDatas({ stopOrderDatas });

	if (!slTpOrders || slTpOrders.length === 0) {
		console.log("No SL/TP orders to cancel");
		return null;
	}

	const stopOrderIds = slTpOrders.map((o) => o.objectId);

	console.log(`Canceling ${stopOrderIds.length} SL/TP orders`);

	const { tx } = await account.getCancelStopOrdersTx({
		stopOrderIds,
	});

	return tx;
}

// Update SL/TP prices across all positions
async function updateAllSLTPPrices(
	newStopLossPercent: number,
	newTakeProfitPercent: number,
) {
	const message = account.getStopOrdersMessageToSign();
	const { stopOrderDatas } = await account.getStopOrderDatas({
		bytes: JSON.stringify(message),
		signature: "...",
	});

	const slTpOrders = account.slTpStopOrderDatas({ stopOrderDatas });

	if (!slTpOrders) {
		console.log("No existing SL/TP orders");
		return;
	}

	// Group by market
	const ordersByMarket = new Map<string, PerpetualsStopOrderData[]>();
	for (const order of slTpOrders) {
		const existing = ordersByMarket.get(order.marketId) || [];
		ordersByMarket.set(order.marketId, [...existing, order]);
	}

	// Update each market's SL/TP
	for (const [marketId, orders] of ordersByMarket) {
		const position = account.positionForMarketId({ marketId });
		if (!position) continue;

		const entryPrice = position.entryPrice;
		const isLong = position.baseAssetAmount > 0;

		const newStopLoss = isLong
			? entryPrice * (1 - newStopLossPercent)
			: entryPrice * (1 + newStopLossPercent);

		const newTakeProfit = isLong
			? entryPrice * (1 + newTakeProfitPercent)
			: entryPrice * (1 - newTakeProfitPercent);

		console.log(`\nUpdating ${marketId}:`);
		console.log(`  Entry: $${entryPrice}`);
		console.log(`  New SL: $${newStopLoss.toFixed(2)}`);
		console.log(`  New TP: $${newTakeProfit.toFixed(2)}`);

		// Cancel old orders and place new ones
		const orderIds = orders.map((o) => o.objectId);
		await account.getCancelStopOrdersTx({ stopOrderIds: orderIds });

		await account.getPlaceSlTpOrdersTx({
			marketId,
			stopLossIndexPrice: newStopLoss,
			takeProfitIndexPrice: newTakeProfit,
		});
	}
}
```

**Use Cases:**

1. **Risk Management**: Monitor and manage all SL/TP orders
2. **Position Protection**: Ensure all positions have SL/TP coverage
3. **Batch Updates**: Update SL/TP prices across all positions
4. **Analytics**: Analyze SL/TP order distribution

***

#### `nonSlTpStopOrderDatasForPosition`

```typescript
nonSlTpStopOrderDatasForPosition(inputs: {
  marketId: PerpetualsMarketId;
  stopOrderDatas: PerpetualsStopOrderData[];
}): PerpetualsStopOrderData[] | undefined
```

Filter stop orders for a single market to only include non-SL/TP orders.

**What This Does:**

Returns regular (non-SL/TP) stop orders for a specific market. Uses `slTpStopOrderDatasForPosition` internally to identify SL/TP orders, then filters them out.

**Parameters:**

* **`marketId`**: `PerpetualsMarketId`
  * Market ID to filter for
* **`stopOrderDatas`**: `PerpetualsStopOrderData[]`
  * Full list of stop orders

**Returns:**

* `PerpetualsStopOrderData[] | undefined`
  * Non-SL/TP stop orders for the market
  * `undefined` if no position exists or no regular orders found

**Example:**

```typescript
// Get stop orders for specific market
const message = account.getStopOrdersMessageToSign({
	marketIds: ["0xMARKET_ID"],
});

const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature: "...",
	marketIds: ["0xMARKET_ID"],
});

// Get regular stop orders for this market
const regularOrders = account.nonSlTpStopOrderDatasForPosition({
	marketId: "0xMARKET_ID",
	stopOrderDatas,
});

if (regularOrders) {
	console.log(`Found ${regularOrders.length} regular stop orders for market`);

	for (const order of regularOrders) {
		console.log(`Order ${order.objectId}:`);
		console.log(`  Trigger: $${order.triggerPrice}`);
		console.log(`  Limit: $${order.limitPrice}`);
	}
}

// Manage market-specific stop orders
async function manageMarketStopOrders(marketId: string) {
	const message = account.getStopOrdersMessageToSign({
		marketIds: [marketId],
	});
	const { stopOrderDatas } = await account.getStopOrderDatas({
		bytes: JSON.stringify(message),
		signature: "...",
		marketIds: [marketId],
	});

	// Get regular orders
	const regularOrders = account.nonSlTpStopOrderDatasForPosition({
		marketId,
		stopOrderDatas,
	});

	// Get SL/TP orders
	const { fullSlTpOrder, partialSlTpOrders } =
		account.slTpStopOrderDatasForPosition({
			marketId,
			stopOrderDatas,
		});

	console.log(`=== Market ${marketId} Stop Orders ===`);
	console.log(`Regular: ${regularOrders?.length || 0}`);
	console.log(`Full SL/TP: ${fullSlTpOrder ? 1 : 0}`);
	console.log(`Partial SL/TP: ${partialSlTpOrders?.length || 0}`);

	return {
		regularOrders,
		fullSlTpOrder,
		partialSlTpOrders,
	};
}
```

**Use Cases:**

1. **Market-Specific Management**: Handle regular stop orders for one market
2. **UI Filtering**: Display regular vs SL/TP orders separately
3. **Order Cleanup**: Cancel specific types of orders per market

***

#### `slTpStopOrderDatasForLimitOrder`

```typescript
slTpStopOrderDatasForLimitOrder(inputs: {
  stopOrderDatas: PerpetualsStopOrderData[];
  limitOrderId: PerpetualsOrderId;
}): {
  fullSlTpOrder: PerpetualsStopOrderData | undefined;
  partialSlTpOrders: PerpetualsStopOrderData[] | undefined;
}
```

Categorize SL/TP stop orders attached to a specific limit order.

**What This Does:**

Finds SL/TP stop orders that are attached to a specific limit order, separating them into full and partial orders.

**Parameters:**

* **`stopOrderDatas`**: `PerpetualsStopOrderData[]`
  * Full list of stop orders
* **`limitOrderId`**: `PerpetualsOrderId`
  * Limit order ID to find attached SL/TP for

**Returns:**

Object containing:

* **`fullSlTpOrder`**: `PerpetualsStopOrderData | undefined`
  * Full position SL/TP order (size >= `Casting.i64MaxBigInt`)
* **`partialSlTpOrders`**: `PerpetualsStopOrderData[] | undefined`
  * Partial position SL/TP orders (size < `Casting.i64MaxBigInt`)

**Example:**

```typescript
// Find SL/TP for a specific limit order
const limitOrderId = 12345n;

const message = account.getStopOrdersMessageToSign();
const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature: "...",
});

const { fullSlTpOrder, partialSlTpOrders } =
	account.slTpStopOrderDatasForLimitOrder({
		stopOrderDatas,
		limitOrderId,
	});

console.log(`SL/TP for limit order ${limitOrderId}:`);

if (fullSlTpOrder) {
	console.log(`  Full SL/TP active`);
	if (fullSlTpOrder.slTp?.stopLossIndexPrice) {
		console.log(`    Stop Loss: $${fullSlTpOrder.slTp.stopLossIndexPrice}`);
	}
	if (fullSlTpOrder.slTp?.takeProfitIndexPrice) {
		console.log(
			`    Take Profit: $${fullSlTpOrder.slTp.takeProfitIndexPrice}`,
		);
	}
}

if (partialSlTpOrders && partialSlTpOrders.length > 0) {
	console.log(`  Partial SL/TP: ${partialSlTpOrders.length} orders`);
	partialSlTpOrders.forEach((order, i) => {
		console.log(
			`    ${i + 1}. Size: ${Number(order.size) / Casting.Fixed.fixedOneN9}`,
		);
	});
}

// Manage limit order SL/TP
async function manageLimitOrderSLTP(limitOrderId: bigint) {
	const message = account.getStopOrdersMessageToSign();
	const { stopOrderDatas } = await account.getStopOrderDatas({
		bytes: JSON.stringify(message),
		signature: "...",
	});

	const { fullSlTpOrder, partialSlTpOrders } =
		account.slTpStopOrderDatasForLimitOrder({
			stopOrderDatas,
			limitOrderId,
		});

	// Cancel existing SL/TP
	const orderIds: string[] = [];
	if (fullSlTpOrder) orderIds.push(fullSlTpOrder.objectId);
	if (partialSlTpOrders) {
		orderIds.push(...partialSlTpOrders.map((o) => o.objectId));
	}

	if (orderIds.length > 0) {
		console.log(`Canceling ${orderIds.length} existing SL/TP orders`);
		await account.getCancelStopOrdersTx({ stopOrderIds: orderIds });
	}

	// Place new SL/TP
	// ... custom logic
}
```

**Use Cases:**

1. **Limit Order Management**: Track SL/TP attached to limit orders
2. **Order Updates**: Update SL/TP when limit order fills
3. **Risk Tracking**: Monitor protection on pending orders

***

### Preview Methods

#### `getPlaceMarketOrderPreview`

```typescript
async getPlaceMarketOrderPreview(
  inputs: SdkPerpetualsPlaceMarketOrderPreviewInputs,
  abortSignal?: AbortSignal
): Promise<ApiPerpetualsPreviewPlaceOrderResponse>
```

Preview market order effects without building a transaction.

**Returns:** Either `{ error: string }` or preview object with:

* `updatedPosition`: Simulated position after order
* `slippage`: Expected slippage
* `executionPrice`: Average execution price
* `filledSize`, `postedSize`: Order fill amounts
* `collateralChange`: Actual collateral change

**Example:**

```typescript
const preview = await account.getPlaceMarketOrderPreview({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9,
	collateralChange: 5000,
	reduceOnly: false,
	leverage: 5,
});

if ("error" in preview) {
	console.error(preview.error);
} else {
	console.log(`Execution Price: $${preview.executionPrice}`);
	console.log(`Slippage: ${preview.slippage * 100}%`);
	console.log(
		`Filled: ${Number(preview.filledSize) / Casting.Fixed.fixedOneN9}`,
	);
}
```

***

#### `getPlaceLimitOrderPreview`

```typescript
async getPlaceLimitOrderPreview(
  inputs: SdkPerpetualsPlaceLimitOrderPreviewInputs,
  abortSignal?: AbortSignal
): Promise<ApiPerpetualsPreviewPlaceOrderResponse>
```

Preview limit order effects.

**Example:**

```typescript
const preview = await account.getPlaceLimitOrderPreview({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9,
	price: 42000,
	collateralChange: 5000,
	reduceOnly: false,
});
```

***

#### `getPlaceScaleOrderPreview`

```typescript
async getPlaceScaleOrderPreview(
  inputs: SdkPerpetualsPlaceScaleOrderPreviewInputs,
  abortSignal?: AbortSignal
): Promise<ApiPerpetualsPreviewPlaceOrderResponse>
```

Preview the effects of placing a scale order without building a transaction.

**Parameters:**

* **`marketId`**: `PerpetualsMarketId`
  * Target market
* **`side`**: `PerpetualsOrderSide`
  * Order side (`Bid` = long, `Ask` = short)
* **`totalSize`**: `bigint`
  * Total size distributed across all orders (scaled by 1e9)
* **`startPrice`**: `bigint`
  * Starting price of the range (inclusive, scaled by 1e9)
* **`endPrice`**: `bigint`
  * Ending price of the range (inclusive, scaled by 1e9)
* **`numberOfOrders`**: `number`
  * Number of limit orders to place across the range
* **`orderType`**: `PerpetualsOrderType`
  * Order type (e.g. `Standard`, `PostOnly`)
* **`reduceOnly`**: `boolean`
  * If true, orders can only reduce an existing position
* **`sizeSkew`** (optional): `number`
  * Size ratio between last and first order. `1.0` = uniform, `2.0` = last is 2x first
* **`leverage`** (optional): `number`
  * Leverage override
* **`expiryTimestamp`** (optional): `bigint`
  * Expiration timestamp in milliseconds since epoch
* **`abortSignal`** (optional): `AbortSignal`
  * Signal to cancel the request

**Returns:**

`ApiPerpetualsPreviewPlaceOrderResponse` — same shape as market/limit order previews (execution price, filled/posted size, slippage, updated position, etc.), or `{ error: string }` on failure.

**Example:**

```typescript
const preview = await account.getPlaceScaleOrderPreview({
	marketId: "0xMARKET_ID",
	side: PerpetualsOrderSide.Bid,
	totalSize: 5n * Casting.Fixed.fixedOneN9,
	startPrice: 40_000n * Casting.Fixed.fixedOneN9,
	endPrice: 42_000n * Casting.Fixed.fixedOneN9,
	numberOfOrders: 5,
	orderType: PerpetualsOrderType.PostOnly,
	reduceOnly: false,
});

if (!("error" in preview)) {
	console.log(`Execution Price: $${preview.executionPrice}`);
	console.log(
		`Filled: ${Number(preview.filledSize) / Casting.Fixed.fixedOneN9}`,
	);
	console.log(
		`Posted: ${Number(preview.postedSize) / Casting.Fixed.fixedOneN9}`,
	);
}
```

***

#### `getCancelOrdersPreview`

```typescript
async getCancelOrdersPreview(
  inputs: SdkPerpetualsCancelOrdersPreviewInputs,
  abortSignal?: AbortSignal
): Promise<ApiPerpetualsPreviewCancelOrdersResponse>
```

Preview effects of canceling orders.

**Example:**

```typescript
const preview = await account.getCancelOrdersPreview({
	marketIdsToData: {
		"0xMARKET_ID": {
			orderIds: [12345n],
			collateralChange: -1000,
			leverage: 5,
		},
	},
});
```

***

#### `getSetLeveragePreview`

```typescript
async getSetLeveragePreview(
  inputs: {
    marketId: PerpetualsMarketId;
    leverage: number;
  },
  abortSignal?: AbortSignal
): Promise<{
  updatedPosition: PerpetualsPosition;
  collateralChange: number;
} | {
  error: string;
}>
```

Preview leverage change effects.

**Example:**

```typescript
const preview = await account.getSetLeveragePreview({
	marketId: "0xMARKET_ID",
	leverage: 10,
});

if (!("error" in preview)) {
	console.log(`New leverage: ${preview.updatedPosition.leverage}x`);
	console.log(`Collateral change: ${preview.collateralChange}`);
}
```

***

#### `getEditCollateralPreview`

```typescript
async getEditCollateralPreview(
  inputs: {
    marketId: PerpetualsMarketId;
    collateralChange: Balance;
  },
  abortSignal?: AbortSignal
): Promise<{
  updatedPosition: PerpetualsPosition;
  collateralChange: number;
} | {
  error: string;
}>
```

Preview allocate/deallocate collateral effects.

**Example:**

```typescript
// Preview allocation (positive change)
const allocPreview = await account.getEditCollateralPreview({
	marketId: "0xMARKET_ID",
	collateralChange: 1000n * 1_000_000n,
});

// Preview deallocation (negative change)
const deallocPreview = await account.getEditCollateralPreview({
	marketId: "0xMARKET_ID",
	collateralChange: -500n * 1_000_000n,
});
```

***

### Data Query Methods

#### `getOrderDatas`

```typescript
async getOrderDatas(): Promise<ApiPerpetualsAccountOrderDatasResponse>
```

Fetch latest metadata for pending orders.

**What This Returns:**

Current order data for all pending orders in the account, useful for refreshing order state.

**Example:**

```typescript
const { orderDatas } = await account.getOrderDatas();

console.log(`Found ${orderDatas.length} pending orders`);

for (const orderData of orderDatas) {
	console.log(`Order ${orderData.orderId}:`);
	console.log(
		`  Size: ${Number(orderData.currentSize) / Casting.Fixed.fixedOneN9}`,
	);
	console.log(`  Market: ${orderData.marketId}`);
}
```

***

#### `getStopOrderDatas`

```typescript
async getStopOrderDatas(inputs: {
  bytes: string;
  signature: string;
  marketIds?: PerpetualsMarketId[];
}): Promise<ApiPerpetualsStopOrderDatasResponse>
```

Fetch stop order ticket data using signed authentication.

**Example:**

```typescript
// Get message and sign it
const message = account.getStopOrdersMessageToSign();
const messageBytes = new TextEncoder().encode(JSON.stringify(message));
const { signature } = await wallet.signMessage({ message: messageBytes });

// Fetch stop orders
const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature,
});

console.log(`Found ${stopOrderDatas.length} stop orders`);
```

***

#### `getCollateralHistory`

```typescript
async getCollateralHistory(inputs: {
  beforeTimestampCursor?: string;
  limit?: number;
}): Promise<ApiPerpetualsAccountCollateralHistoryResponse>
```

Fetch paginated collateral change history.

**Example:**

```typescript
const { collateralHistory, nextBeforeTimestampCursor } =
	await account.getCollateralHistory({
		limit: 50,
	});

console.log(`Fetched ${collateralHistory.length} collateral changes`);

for (const change of collateralHistory) {
	console.log(
		`${new Date(change.timestamp).toISOString()}: ${change.amount} ${change.type}`,
	);
}

// Fetch next page
if (nextBeforeTimestampCursor) {
	const nextPage = await account.getCollateralHistory({
		beforeTimestampCursor: nextBeforeTimestampCursor,
		limit: 50,
	});
}
```

***

#### `getOrderHistory`

```typescript
async getOrderHistory(inputs: {
  beforeTimestampCursor?: string;
  limit?: number;
}): Promise<ApiPerpetualsAccountOrderHistoryResponse>
```

Fetch paginated order history.

**Example:**

```typescript
const { orderHistory, nextBeforeTimestampCursor } =
	await account.getOrderHistory({
		limit: 50,
	});

console.log(`Fetched ${orderHistory.length} historical orders`);
```

***

#### `getMarginHistory`

```typescript
async getMarginHistory(inputs: {
  fromTimestamp: Timestamp;
  toTimestamp: Timestamp;
  intervalMs: number;
}): Promise<ApiPerpetualsAccountMarginHistoryResponse>
```

Fetch historical margin snapshots for charting.

**Example:**

```typescript
const now = Date.now();
const oneDayAgo = now - 86400000;

const { marginHistoryDatas } = await account.getMarginHistory({
	fromTimestamp: oneDayAgo,
	toTimestamp: now,
	intervalMs: 3600000, // 1 hour intervals
});

console.log(`Fetched ${marginHistoryDatas.length} margin snapshots`);

for (const snapshot of marginHistoryDatas) {
	console.log(
		`${new Date(snapshot.timestamp).toISOString()}: Equity = ${snapshot.totalEquity}`,
	);
}
```

***

### Helper Methods

#### `positionForMarketId`

```typescript
positionForMarketId(inputs: {
  marketId: PerpetualsMarketId;
}): PerpetualsPosition | undefined
```

Find position for a specific market.

**Example:**

```typescript
const position = account.positionForMarketId({
	marketId: "0xMARKET_ID",
});

if (position) {
	console.log(`Position size: ${position.baseAssetAmount}`);
	console.log(`Entry price: $${position.entryPrice}`);
	console.log(`PnL: $${position.unrealizedPnlUsd}`);
} else {
	console.log("No position in this market");
}
```

***

#### `slTpStopOrderDatasForPosition`

```typescript
slTpStopOrderDatasForPosition(inputs: {
  marketId: PerpetualsMarketId;
  stopOrderDatas: PerpetualsStopOrderData[];
}): {
  fullSlTpOrder: PerpetualsStopOrderData | undefined;
  partialSlTpOrders: PerpetualsStopOrderData[] | undefined;
}
```

Extract SL/TP orders for a position.

**Example:**

```typescript
// Get stop orders
const message = account.getStopOrdersMessageToSign();
const { stopOrderDatas } = await account.getStopOrderDatas({
	bytes: JSON.stringify(message),
	signature: "...",
});

// Extract SL/TP
const { fullSlTpOrder, partialSlTpOrders } =
	account.slTpStopOrderDatasForPosition({
		marketId: "0xMARKET_ID",
		stopOrderDatas,
	});

if (fullSlTpOrder) {
	console.log("Full position SL/TP active");
}
if (partialSlTpOrders && partialSlTpOrders.length > 0) {
	console.log(`${partialSlTpOrders.length} partial SL/TP orders`);
}
```

***

#### `collateral`

```typescript
collateral(): number
```

Get available collateral.

**Example:**

```typescript
const available = account.collateral();
console.log(`Available collateral: ${available} USDC`);
```

***

#### `isVault`

```typescript
isVault(): boolean
```

Check if account is vault-backed.

**Example:**

```typescript
if (account.isVault()) {
	console.log("This is a vault account");
} else {
	console.log("This is a direct account");
}
```

***

#### `ownerAddress`

```typescript
ownerAddress(): SuiAddress
```

Get owner wallet address.

***

#### `accountObjectId`

```typescript
accountObjectId(): ObjectId
```

Get account object ID.

***

#### `accountId`

```typescript
accountId(): PerpetualsAccountId
```

Get numeric account ID.

***

#### `accountCapId`

```typescript
accountCapId(): ObjectId
```

Get account cap object ID (direct accounts only).

***

### Complete Usage Examples

#### Example 1: Complete Trading Flow

```typescript
// Initialize
const afSdk = new Aftermath("MAINNET");
await afSdk.init();
const perps = afSdk.Perpetuals();

// Get account
const { accounts: caps } = await perps.getOwnedAccountCaps({
	walletAddress: "0xUSER",
});
const { account } = await perps.getAccount({ accountCap: caps[0] });

// Preview order
const preview = await account.getPlaceMarketOrderPreview({
	marketId: "0xMARKET",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9,
	collateralChange: 5000,
	reduceOnly: false,
	leverage: 5,
});

if ("error" in preview) throw new Error(preview.error);

// Check slippage
if (preview.slippage > 0.01) {
	console.warn("High slippage!");
}

// Place order with SL/TP
const { tx } = await account.getPlaceMarketOrderTx({
	marketId: "0xMARKET",
	side: PerpetualsOrderSide.Bid,
	size: 1n * Casting.Fixed.fixedOneN9,
	collateralChange: 5000,
	reduceOnly: false,
	slTp: {
		stopLossIndexPrice: 40000,
		takeProfitIndexPrice: 50000,
	},
});

// Execute
await wallet.signAndExecuteTransaction({ transaction: tx });
```

#### Example 2: Position Management

```typescript
// Monitor positions
for (const position of account.account.positions) {
	console.log(`Market: ${position.marketId}`);
	console.log(`  Size: ${position.baseAssetAmount}`);
	console.log(`  PnL: $${position.unrealizedPnlUsd}`);
	console.log(`  Margin Ratio: ${position.marginRatio * 100}%`);

	// Check if near liquidation
	const maintenanceRatio = 0.03; // Example
	if (position.marginRatio < maintenanceRatio * 1.2) {
		console.warn("⚠️  Position near liquidation!");
	}
}
```

#### Example 3: Risk Management

```typescript
class RiskManager {
	constructor(private account: PerpetualsAccount) {}

	async checkAndAdjust() {
		for (const position of this.account.account.positions) {
			// Check margin
			if (position.marginRatio < 0.05) {
				await this.addCollateral(position.marketId, 1000);
			}

			// Check PnL
			const pnlPercent =
				position.unrealizedPnlUsd / position.collateralUsd;
			if (pnlPercent < -0.2) {
				await this.closePosition(position.marketId);
			}
		}
	}

	async addCollateral(marketId: string, amount: number) {
		const { tx } = await this.account.getAllocateCollateralTx({
			marketId,
			allocateAmount: BigInt(amount * 1_000_000),
		});
		// Execute tx
	}

	async closePosition(marketId: string) {
		const position = this.account.positionForMarketId({ marketId });
		if (!position) return;

		const closeSide =
			position.baseAssetAmount > 0
				? PerpetualsOrderSide.Ask
				: PerpetualsOrderSide.Bid;

		const { tx } = await this.account.getPlaceMarketOrderTx({
			marketId,
			side: closeSide,
			size: BigInt(
				Math.abs(position.baseAssetAmount * Casting.Fixed.fixedOneN9),
			),
			collateralChange: 0,
			reduceOnly: true,
		});
		// Execute tx
	}
}
```
