Transaction and CLI Cookbook for DeepBook
Build common DeepBook programmable transaction blocks (PTBs) from reusable templates for both the sui client ptb CLI and the TypeScript SDK. The sui client ptb CLI needs @-prefixed object IDs, angle-bracket type arguments, and quoted arrays. These templates start with those syntax rules, which cause the most CLI errors, then cover coin operations, generic Move calls, and DeepBook flows.
CLI examples are verified against sui version 1.62.0. DeepBook Move argument order is verified against the DeepBookV3 sources. Generic TypeScript samples pass compile checks against @mysten/sui version 2.22.1. The DeepBook SDK samples follow the documented DeepBookV3 SDK usage. None are executed in this document, so dry-run each command before you rely on it.
Use sui client ptb --preview to print the PTB commands without executing, and --dry-run to estimate gas and catch errors before you sign. The --gas-budget values in these templates are examples. Use the --dry-run estimate to set your own budget.
How do I avoid common sui client ptb errors?
Most sui client ptb failures come from 3 formatting rules. Get these right and the rest follows.
The examples use shell variables such as $OBJECT_ID and $RECIPIENT. Set each one in your shell before you run a command, for example export RECIPIENT=0x.... Object ID, address, and package variables such as $OBJECT_ID, $RECIPIENT, and $DEEPBOOK hold 0x-prefixed hex values. Type variables such as $BASE, $QUOTE, and $COIN_TYPE hold full Move types, such as 0x2::sui::SUI. For DeepBook package IDs, pools, and coin types, see Contract Information.
Object IDs need an @ prefix
The CLI treats a bare 0x... value as a number, not an object. Prefix every object ID, address, and gas coin ID with @.
$ sui client ptb \
--transfer-objects "[@$OBJECT_ID]" @$RECIPIENT \
--gas-budget 10000000
Referencing $OBJECT_ID without @ makes the command fail to resolve the object.
Type arguments go in angle brackets
Type arguments belong in <...>, comma-delimited for multiple types. Quote the whole value so your shell does not interpret the brackets.
$ sui client ptb \
--move-call "$PACKAGE::vault::deposit" "<0x2::sui::SUI>" @$VAULT @$COIN \
--gas-budget 10000000
For 2 type arguments, use "<0x2::sui::SUI, $QUOTE_TYPE>".
Quote arrays so your shell does not expand them
In zsh and some other shells, [ ] triggers globbing. Wrap every array in quotes.
$ sui client ptb \
--split-coins gas "[1000, 5000]" \
--assign coins \
--transfer-objects "[coins.0, coins.1]" @$RECIPIENT \
--gas-budget 10000000
Use --assign to name a command result, then index into it with .0, .1, and so on. Later commands in the same PTB refer to the result by that name, as --transfer-objects does with coins.0 and coins.1 above.
How do I split, merge, and transfer coins?
- CLI
- TypeScript
Split 2 coins from the gas coin and transfer them:
$ sui client ptb \
--split-coins gas "[1000, 5000]" \
--assign coins \
--transfer-objects "[coins.0, coins.1]" @$RECIPIENT \
--gas-budget 10000000
Merge coins into a primary coin:
$ sui client ptb \
--merge-coins @$PRIMARY_COIN "[@$COIN_1, @$COIN_2]" \
--gas-budget 10000000
import { Transaction } from '@mysten/sui/transactions';
// Split from the gas coin and transfer the new coins.
const tx = new Transaction();
const [a, b] = tx.splitCoins(tx.gas, [1000, 5000]);
tx.transferObjects([a, b], RECIPIENT);
// Merge several coins into one.
const merge = new Transaction();
merge.mergeCoins(merge.object(PRIMARY_COIN), [merge.object(COIN_1), merge.object(COIN_2)]);
How do I make a Move call with object and type arguments?
- CLI
- TypeScript
$ sui client ptb \
--move-call "$PACKAGE::vault::deposit" "<0x2::sui::SUI>" @$VAULT 1000 \
--gas-budget 10000000
import { Transaction } from '@mysten/sui/transactions';
const tx = new Transaction();
tx.moveCall({
target: `${PACKAGE}::vault::deposit`,
typeArguments: ['0x2::sui::SUI'],
arguments: [tx.object(VAULT), tx.pure.u64(1000)],
});
How do I deposit and place a DeepBook order in one PTB?
For compile-checked SDK versions of these compositions, plus a three-legged lend, trade, and stake example, see Composing DeepBook transactions.
Get the DeepBookV3 package ID, pool, and coin types from Contract Information. Set DEEPBOOK to the DeepBookV3 package ID. Do not use the CLI deepbook name alias, which resolves to the legacy DeepBook address, not DeepBookV3.
In the SDK samples, string keys such as 'SUI_DBUSDC', 'DEEP_SUI', and 'DBUSDC' are pool and coin keys. Look them up in Contract Information and the DeepBookV3 SDK constants. 'MANAGER_1' is a balance manager key; see Balance Manager.
Placing an order requires a trade proof and takes 13 typed arguments. The TypeScript SDK generates the proof and encodes the arguments for you, so it is the recommended path. Deposit into the BalanceManager and place the order in the same transaction so both settle atomically.
- TypeScript (SDK)
- CLI
import { Transaction } from '@mysten/sui/transactions';
// `client` is a Sui client extended with the deepbook() plugin.
// See the DeepBookV3 SDK page for setup.
const tx = new Transaction();
// 1. Deposit into the balance manager.
tx.add(client.deepbook.balanceManager.depositIntoManager('MANAGER_1', 'DBUSDC', 100));
// 2. Place a limit bid in the same PTB.
tx.add(
client.deepbook.placeLimitOrder({
poolKey: 'SUI_DBUSDC',
balanceManagerKey: 'MANAGER_1',
clientOrderId: '1',
price: 2.5,
quantity: 10,
isBid: true,
payWithDeep: true,
}),
);
See Balance Manager and Orders for the full parameter set and cancel and modify calls.
Depositing into a BalanceManager is a single move call to balance_manager::deposit<T>(manager, coin):
$ sui client ptb \
--move-call "$DEEPBOOK::balance_manager::deposit" "<$COIN_TYPE>" @$MANAGER @$COIN \
--gas-budget 10000000
Placing an order from the CLI is impractical: pool::place_limit_order needs a TradeProof from balance_manager::generate_proof_as_owner plus 13 typed arguments (client order ID, order type, self-matching option, price, quantity, is_bid, pay_with_deep, expiration, the 0x6 clock, and the 2 pool type arguments). Use the TypeScript SDK for order placement.
How do I write a DeepBook flash loan PTB?
A flash loan returns a FlashLoan hot potato: a value that you must pass back to the pool in the same transaction, or the whole transaction aborts. borrow_flashloan_base returns 2 values: the borrowed Coin<Base> and the FlashLoan. In the CLI, --assign names both values together, and you index them as .0 and .1. return_flashloan_base takes the pool, the repaid coin, and the FlashLoan.
- TypeScript (SDK)
- CLI
import { Transaction } from '@mysten/sui/transactions';
const tx = new Transaction();
// Borrow base asset. `flashLoan` is the hot potato you must return.
const [base, flashLoan] = tx.add(client.deepbook.flashLoans.borrowBaseAsset('DEEP_SUI', 1000));
// ... use `base` here, for example swap it through another pool ...
// Repay in the same PTB. The remaining coin returns to you.
const remainder = tx.add(
client.deepbook.flashLoans.returnBaseAsset('DEEP_SUI', 1000, base, flashLoan),
);
tx.transferObjects([remainder], SENDER);
returnBaseAsset repays the borrowed amount from base. remainder holds whatever is left of base after repayment, and the last line transfers it to SENDER.
See Flash Loans for the quote-asset variants.
The borrow and return calls both take the 2 pool type arguments <$BASE, $QUOTE>:
$ sui client ptb \
--move-call "$DEEPBOOK::pool::borrow_flashloan_base" "<$BASE, $QUOTE>" @$POOL 1000 \
--assign loan \
--move-call "$OTHER_PKG::router::swap" "<$BASE, $QUOTE>" @$OTHER_POOL loan.0 \
--assign swapped \
--move-call "$DEEPBOOK::pool::return_flashloan_base" "<$BASE, $QUOTE>" @$POOL swapped loan.1 \
--gas-budget 20000000
loan.0 is the borrowed Coin<Base> and loan.1 is the FlashLoan. The middle move call stands in for whatever you do with the borrowed funds. The repaid coin passed to return_flashloan_base must cover the borrowed amount.
The flash loan CLI template above has its flag syntax verified against sui 1.62.0 and its argument order verified against the DeepBookV3 pool.move sources, but this document does not execute it end to end. Dry-run it with --dry-run against a real pool and coin types before you rely on it.
How do I verify a PTB before I execute it?
- Add
--previewto any command to print its PTB commands without executing. - Add
--dry-runto estimate gas and surface argument or type errors. - For DeepBook object IDs and coin and pool keys, see Contract Information and the DeepBookV3 SDK constants.