Swift (off-chain signed orders)
Swift is an extension to Drift that lets users place orders without submitting a transaction to the Solana network. Instead of paying gas and waiting for confirmation, users sign an order message off-chain and submit it to the Swift API. Keepers and market makers then bundle the signed message with their own transaction to fill the order on-chain.
This enables faster order placement, lower latency, and a gas-free experience for takers, while market makers still settle on-chain.
Order flow:
- Define order parameters
- Sign the order message off-chain
- Submit to the Swift API (
https://swift.drift.trade/orders) - Keepers/market makers pick up the order and fill it on-chain
Step 1: Define order parameters
Set up a standard Drift order. For Swift, you typically use a market order with auction parameters that give market makers a window to fill:
import {
getMarketOrderParams, MarketType, PositionDirection, isVariant
} from "@drift-labs/sdk";
const marketIndex = 0; // SOL-PERP
const oracleInfo = driftClient.getOracleDataForPerpMarket(marketIndex);
const direction = PositionDirection.LONG;
// Set auction price range around the current oracle price
const highPrice = oracleInfo.price.muln(101).divn(100); // oracle + 1%
const lowPrice = oracleInfo.price;
const orderParams = getMarketOrderParams({
marketIndex,
marketType: MarketType.PERP,
direction,
baseAssetAmount: driftClient.convertToPerpPrecision(0.1), // 0.1 SOL
auctionStartPrice: isVariant(direction, "long") ? lowPrice : highPrice,
auctionEndPrice: isVariant(direction, "long") ? highPrice : lowPrice,
auctionDuration: 50, // slots for market makers to compete
});Example Swift order setupReference ↗
Example Swift order setupReference ↗Swift order setup.Step 2: Sign the order message
Sign the order parameters off-chain using your DriftClient’s wallet. This produces a serialized message and signature that the Swift API will verify:
import { generateSignedMsgUuid } from "@drift-labs/sdk";
const slot = await driftClient.connection.getSlot();
const orderMessage = {
signedMsgOrderParams: orderParams,
subAccountId: driftClient.activeSubAccountId,
slot: new BN(slot),
uuid: generateSignedMsgUuid(), // unique ID for deduplication
stopLossOrderParams: null,
takeProfitOrderParams: null,
};
const { orderParams: message, signature } =
driftClient.signSignedMsgOrderParamsMessage(orderMessage);Method DriftClient.signSignedMsgOrderParamsMessageReference ↗
Method DriftClient.signSignedMsgOrderParamsMessageReference ↗| Parameter | Type | Required |
|---|---|---|
orderParamsMessage | SignedMsgOrderParamsMessage | SignedMsgOrderParamsDelegateMessage | Yes |
delegateSigner | boolean | No |
| Returns |
|---|
SignedMsgOrderParams |
Step 3: Submit to the Swift API
POST the signed message to the Swift endpoint. The API validates the signature and queues the order for keepers and market makers:
const swiftUrl = "https://swift.drift.trade/orders";
const response = await fetch(swiftUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
market_index: orderParams.marketIndex,
market_type: "perp",
message: message.toString("hex"),
signature: signature.toString("hex"),
taker_authority: driftClient.wallet.publicKey.toBase58(),
// signing_authority: delegatePublicKey.toBase58(), // only needed for delegate flows
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error("Swift error: " + response.status + " " + errorText);
}Example Swift API submitReference ↗
Example Swift API submitReference ↗Swift API submit.Delegate flows: When signing as a delegate for another account, also pass
signing_authority(the delegate’s public key) and ensuretaker_authorityis the account owner’s public key. Initialize the DriftClient withauthorityset to the owner’s key.
Signed message accounts (delegate flow)
For delegate accounts, you can initialize a SignedMsgUserOrders account to allow a delegate to place Swift orders on behalf of the owner:
import { getSignedMsgUserAccountPublicKey } from "@drift-labs/sdk";
// Derive the PDA for the signed message orders account
const pda = getSignedMsgUserAccountPublicKey(driftClient.program.programId, authority);Function getSignedMsgUserAccountPublicKeyReference ↗
Function getSignedMsgUserAccountPublicKeyReference ↗| Parameter | Type | Required |
|---|---|---|
programId | PublicKey | Yes |
authority | PublicKey | Yes |
| Returns |
|---|
PublicKey |
// Initialize the signed message orders account for `authority`
// with space for 8 concurrent orders
const [txSig, signedMsgUserAccount] =
await driftClient.initializeSignedMsgUserOrders(authority, 8);Method DriftClient.initializeSignedMsgUserOrdersReference ↗
Method DriftClient.initializeSignedMsgUserOrdersReference ↗| Parameter | Type | Required |
|---|---|---|
authority | PublicKey | Yes |
numOrders | number | Yes |
txParams | TxParams | No |
| Returns |
|---|
Promise<[string, PublicKey]> |
Decode signed messages
Decode a raw signed message (e.g., received from the Swift API or another source) back into structured order params:
const signedMessage = driftClient.decodeSignedMsgOrderParamsMessage(
Buffer.from(orderMessageHex, "hex"),
isDelegateSigner // true if the message was signed by a delegate
);Method DriftClient.decodeSignedMsgOrderParamsMessageReference ↗
Method DriftClient.decodeSignedMsgOrderParamsMessageReference ↗| Parameter | Type | Required |
|---|---|---|
encodedMessage | Buffer | Yes |
delegateSigner | boolean | No |
| Returns |
|---|
SignedMsgOrderParamsMessage | SignedMsgOrderParamsDelegateMessage |
Instruction builders (Swift taker + maker)
For advanced use cases (such as building keeper or market-maker bots), you can construct Swift fill instructions directly instead of using the HTTP API flow.
Build the taker-side instructions for placing a Swift order on-chain:
// Used by keeper bots to submit a taker's signed Swift order on-chain
const ixs = await driftClient.getPlaceSignedMsgTakerPerpOrderIxs(
{ orderParams: orderMessageHex, signature },
marketIndex,
takerInfo
);Method DriftClient.getPlaceSignedMsgTakerPerpOrderIxsReference ↗
Method DriftClient.getPlaceSignedMsgTakerPerpOrderIxsReference ↗| Parameter | Type | Required |
|---|---|---|
signedSignedMsgOrderParams | SignedMsgOrderParams | Yes |
marketIndex | number | Yes |
takerInfo | { taker: PublicKey; takerStats: PublicKey; takerUserAccount: UserAccount; signingAuthority: PublicKey; } | Yes |
precedingIxs | TransactionInstruction[] | No |
overrideCustomIxIndex | number | No |
| Returns |
|---|
Promise<TransactionInstruction[]> |
Build instructions to place a maker order and simultaneously fill a pending Swift taker order (atomic maker fill):
// Used by market makers to fill a taker's Swift order with their own maker quote
const ixs = await driftClient.getPlaceAndMakeSignedMsgPerpOrderIxs(
signedMsgOrderParams,
signedMsgOrderUuid,
takerInfo,
makerOrderParams
);Method DriftClient.getPlaceAndMakeSignedMsgPerpOrderIxsReference ↗
Method DriftClient.getPlaceAndMakeSignedMsgPerpOrderIxsReference ↗| Parameter | Type | Required |
|---|---|---|
signedSignedMsgOrderParams | SignedMsgOrderParams | Yes |
signedMsgOrderUuid | Uint8Array<ArrayBufferLike> | Yes |
takerInfo | { taker: PublicKey; takerStats: PublicKey; takerUserAccount: UserAccount; signingAuthority: PublicKey; } | Yes |
orderParams | OptionalOrderParams | Yes |
referrerInfo | ReferrerInfo | No |
subAccountId | number | No |
precedingIxs | TransactionInstruction[] | No |
overrideCustomIxIndex | number | No |
| Returns |
|---|
Promise<TransactionInstruction[]> |
Helper functions
Generate a unique UUID for a Swift order message. Each order must have a distinct UUID to prevent replay attacks:
import { generateSignedMsgUuid } from "@drift-labs/sdk";
const uuid = generateSignedMsgUuid();Function generateSignedMsgUuidReference ↗
Function generateSignedMsgUuidReference ↗| Returns |
|---|
Uint8Array<ArrayBufferLike> |
Hash a signature for use in order deduplication or indexing:
import { digestSignature } from "@drift-labs/sdk";
const hash = digestSignature(Uint8Array.from(signature));Function digestSignatureReference ↗
Function digestSignatureReference ↗| Parameter | Type | Required |
|---|---|---|
signature | Uint8Array<ArrayBufferLike> | Yes |
| Returns |
|---|
string |
Derive the user stats account PDA for an authority:
import { getUserStatsAccountPublicKey } from "@drift-labs/sdk";
const userStats = getUserStatsAccountPublicKey(
driftClient.program.programId,
authority
);Function getUserStatsAccountPublicKeyReference ↗
Function getUserStatsAccountPublicKeyReference ↗| Parameter | Type | Required |
|---|---|---|
programId | PublicKey | Yes |
authority | PublicKey | Yes |
| Returns |
|---|
PublicKey |