Swift (off-chain signed orders)
Swift is an extension to Velocity 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.
The Swift API host below (swift.velocity.exchange) is a provisional placeholder — Velocity’s production Swift endpoint had not been finalized/verified at the time this page was written. Confirm the real host before shipping against it.
Order flow:
- Define order parameters
- Sign the order message off-chain
- Submit to the Swift API (
https://swift.velocity.exchange/orders) - Keepers/market makers pick up the order and fill it on-chain
Step 1: Define order parameters
Set up a standard Velocity 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 "@velocity-exchange/sdk";
const marketIndex = 0; // SOL-PERP
const oracleInfo = velocityClient.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: velocityClient.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 VelocityClient’s wallet. This produces a serialized message and signature that the Swift API will verify:
import { generateSignedMsgUuid } from "@velocity-exchange/sdk";
const slot = await velocityClient.connection.getSlot();
const orderMessage = {
signedMsgOrderParams: orderParams,
subAccountId: velocityClient.activeSubAccountId,
slot: new BN(slot),
uuid: generateSignedMsgUuid(), // unique ID for deduplication
stopLossOrderParams: null,
takeProfitOrderParams: null,
};
const { orderParams: message, signature } =
velocityClient.signSignedMsgOrderParamsMessage(orderMessage);Method VelocityClient.signSignedMsgOrderParamsMessageReference ↗
Method VelocityClient.signSignedMsgOrderParamsMessageReference ↗| Parameter | Type | Required |
|---|---|---|
orderParamsMessage | SignedMsgOrderParamsMessage | SignedMsgOrderParamsDelegateMessageThe order message to sign; use `SignedMsgOrderParamsDelegateMessage`
when signing on behalf of a delegated authority (`delegateSigner: true`), otherwise
`SignedMsgOrderParamsMessage`. | Yes |
delegateSigner | booleanWhether `orderParamsMessage` is the delegate-signer variant; must match
the message's actual shape or encoding/decoding elsewhere will misinterpret the buffer. | No |
| Returns |
|---|
SignedMsgOrderParams |
Builder Codes attach the same way here: add builderIdx / builderFeeTenthBps to orderMessage alongside signedMsgOrderParams. Builder codes are not exclusive to Swift — the same fields also work on regular on-chain order placement.
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.velocity.exchange/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: velocityClient.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 VelocityClient 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 "@velocity-exchange/sdk";
// Derive the PDA for the signed message orders account
const pda = getSignedMsgUserAccountPublicKey(velocityClient.program.programId, authority);Function getSignedMsgUserAccountPublicKeyReference ↗
Function getSignedMsgUserAccountPublicKeyReference ↗Derives the `SignedMsgUserOrders` PDA (holds a user's pending swift/signed-message orders) from seeds `["SIGNED_MSG", authority]`.
| Parameter | Type | Required |
|---|---|---|
programId | PublicKeyDeployed velocity program id. | Yes |
authority | PublicKeyWallet pubkey (the user's main authority, not the sub-account) that owns the account. | Yes |
The `SignedMsgUserOrders` account's public key.
| Returns |
|---|
PublicKey |
// Initialize the signed message orders account for `authority`
// with space for 8 concurrent orders
const [txSig, signedMsgUserAccount] =
await velocityClient.initializeSignedMsgUserOrders(authority, 8);Method VelocityClient.initializeSignedMsgUserOrdersReference ↗
Method VelocityClient.initializeSignedMsgUserOrdersReference ↗| Parameter | Type | Required |
|---|---|---|
authority | PublicKeyAuthority the account is created for. | Yes |
numOrders | numberNumber of order-message slots to allocate; determines account rent/size. | Yes |
txParams | TxParamsOptional compute-unit/priority-fee overrides for the transaction. | 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 = velocityClient.decodeSignedMsgOrderParamsMessage(
Buffer.from(orderMessageHex, "hex"),
isDelegateSigner // true if the message was signed by a delegate
);Method VelocityClient.decodeSignedMsgOrderParamsMessageReference ↗
Method VelocityClient.decodeSignedMsgOrderParamsMessageReference ↗| Parameter | Type | Required |
|---|---|---|
encodedMessage | BufferThe borsh-encoded message bytes (as produced by `encodeSignedMsgOrderParamsMessage`). | Yes |
delegateSigner | booleanWhether to decode as the delegate-signer variant
(`SignedMsgOrderParamsDelegateMessage`) rather than the regular one. | 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 velocityClient.getPlaceSignedMsgTakerPerpOrderIxs(
{ orderParams: orderMessageHex, signature },
marketIndex,
takerInfo
);Method VelocityClient.getPlaceSignedMsgTakerPerpOrderIxsReference ↗
Method VelocityClient.getPlaceSignedMsgTakerPerpOrderIxsReference ↗| Parameter | Type | Required |
|---|---|---|
signedSignedMsgOrderParams | SignedMsgOrderParamsThe signed order payload. | Yes |
marketIndex | numberPerp market index the signed order targets. | Yes |
takerInfo | { taker: PublicKey; takerStats: PublicKey; takerUserAccount: UserAccount; signingAuthority: PublicKey; }Taker's account/authority info; see `placeSignedMsgTakerOrder`. | Yes |
precedingIxs | TransactionInstruction[]Instructions preceding these two in the final transaction (used only
to compute the ed25519-verify instruction's sysvar index). | No |
overrideCustomIxIndex | numberExplicit sysvar-instructions index override. | No |
| Returns |
|---|
Promise<TransactionInstruction[]> |
Build instructions to place a maker order and simultaneously fill a pending Swift taker order (atomic maker fill). If the taker’s order carries a builder code or the taker is referred with an escrow, pass their decoded RevenueShareEscrow as the trailing takerEscrow argument — see Fill-time enforcement:
// Used by market makers to fill a taker's Swift order with their own maker quote
const ixs = await velocityClient.getPlaceAndMakeSignedMsgPerpOrderIxs(
signedMsgOrderParams,
signedMsgOrderUuid,
takerInfo,
makerOrderParams,
subAccountId,
[], // precedingIxs
undefined, // overrideCustomIxIndex
takerEscrow // optional; required when the taker's order needs it
);Method VelocityClient.getPlaceAndMakeSignedMsgPerpOrderIxsReference ↗
Method VelocityClient.getPlaceAndMakeSignedMsgPerpOrderIxsReference ↗| Parameter | Type | Required |
|---|---|---|
signedSignedMsgOrderParams | SignedMsgOrderParamsThe taker's signed order payload. | Yes |
signedMsgOrderUuid | Uint8Array<ArrayBufferLike>UUID identifying the signed-msg order. | Yes |
takerInfo | { taker: PublicKey; takerStats: PublicKey; takerUserAccount: UserAccount; signingAuthority: PublicKey; }Taker's account/authority info. | Yes |
orderParams | OptionalOrderParamsMaker order to place; see `placeAndMakeSignedMsgPerpOrder` for field
precisions and required order shape. | Yes |
subAccountId | numberSub-account placing the maker order; defaults to the active sub-account. | No |
precedingIxs | TransactionInstruction[]Instructions preceding these in the final transaction (used only to
compute the ed25519-verify instruction's sysvar index). | No |
overrideCustomIxIndex | numberExplicit sysvar-instructions index override. | No |
takerEscrow | RevenueShareEscrowAccountSee `placeAndMakeSignedMsgPerpOrder`. | 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 "@velocity-exchange/sdk";
const uuid = generateSignedMsgUuid();Function generateSignedMsgUuidReference ↗
Function generateSignedMsgUuidReference ↗Generates a random 8-character uuid for tagging a signed-message (swift) order, matching the `uuid: Uint8Array` field expected on-chain/by the swift server.
8 raw bytes (the ASCII/UTF-8 encoding of an 8-character nanoid string).
| Returns |
|---|
Uint8Array<ArrayBufferLike> |
Hash a signature for use in order deduplication or indexing:
import { digestSignature } from "@velocity-exchange/sdk";
const hash = digestSignature(Uint8Array.from(signature));Function digestSignatureReference ↗
Function digestSignatureReference ↗Computes a base64-encoded SHA-256 digest of a signature, used as a compact, collision-resistant dedup/lookup key for signed messages (e.g. swift/signed-message orders) without storing the full signature.
| Parameter | Type | Required |
|---|---|---|
signature | Uint8Array<ArrayBufferLike>Raw signature bytes to hash. | Yes |
The base64-encoded SHA-256 digest.
| Returns |
|---|
string |
Derive the user stats account PDA for an authority:
import { getUserStatsAccountPublicKey } from "@velocity-exchange/sdk";
const userStats = getUserStatsAccountPublicKey(
velocityClient.program.programId,
authority
);Function getUserStatsAccountPublicKeyReference ↗
Function getUserStatsAccountPublicKeyReference ↗Derives the `UserStats` PDA (one per authority, shared across all of that authority's sub-accounts) from seeds `["user_stats", authority]`.
| Parameter | Type | Required |
|---|---|---|
programId | PublicKeyDeployed velocity program id. | Yes |
authority | PublicKeyWallet pubkey the stats account tracks. | Yes |
The `UserStats` account's public key.
| Returns |
|---|
PublicKey |