Builder Codes
Builder Codes (DBC) let integrators earn fees by routing flow through their application. The system is built on top of Swift: when a user places a Swift order through your app, you include a builderIdx and builderFee in the signed order message, and fees are automatically settled to your revenue-share account.
Note: Builder Codes are currently limited to Swift orders only.
The workflow has 3 steps:
- Builder initializes a revenue-share account
- User creates an escrow account for tracking approved builders and fees
- User approves the builder with a maximum fee cap
Setup
Create and subscribe separate DriftClient instances for the builder and user authorities:
import { DriftClient } from "@drift-labs/sdk";
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
// Initialize connection
const connection = new Connection("https://api.mainnet-beta.solana.com");
// Builder wallet (revenue share provider)
const builderWallet = Keypair.fromSecretKey(/* builder secret key */);
const builderAuthority = builderWallet.publicKey;
// User wallet (end user)
const userWallet = Keypair.fromSecretKey(/* user secret key */);
const takerAuthority = userWallet.publicKey;
// Builder client
const builderClient = new DriftClient({
connection,
wallet: builderWallet,
env: "mainnet-beta"
});
await builderClient.subscribe();
// User client
const userClient = new DriftClient({
connection,
wallet: userWallet,
env: "mainnet-beta"
});
await userClient.subscribe();Example Builder codes setupReference ↗
Example Builder codes setupReference ↗Builder codes setup.SDK Usage
Builder: Initialize Revenue Share
Create the builder’s onchain revenue-share configuration account. This is a one-time setup step that must be completed before the builder can receive fees:
await builderClient.initializeRevenueShare(builderAuthority);Method DriftClient.initializeRevenueShareReference ↗
Method DriftClient.initializeRevenueShareReference ↗| Parameter | Type | Required |
|---|---|---|
authority | PublicKey | Yes |
txParams | TxParams | No |
| Returns |
|---|
Promise<string> |
User: Initialize Escrow
Create the user’s revenue-share escrow account used for builder fee routing. The numOrders parameter controls how many concurrent approved builders the account can hold. Set this to at least 8 since users can have multiple subaccounts with open orders:
// numOrders should be >= 8 to accommodate multiple subaccounts
await userClient.initializeRevenueShareEscrow(takerAuthority, 16);Method DriftClient.initializeRevenueShareEscrowReference ↗
Method DriftClient.initializeRevenueShareEscrowReference ↗| Parameter | Type | Required |
|---|---|---|
authority | PublicKey | Yes |
numOrders | number | Yes |
txParams | TxParams | No |
| Returns |
|---|
Promise<string> |
User: Approve a Builder (Max Fee)
Approve a builder for this user and set the maximum fee they can charge. The builderIdx in the signed order message references the position of this approval in the user’s escrow account:
// max fee is expressed in tenths of a basis point (100 = 10 bps, 200 = 20 bps)
await userClient.changeApprovedBuilder(builderAuthority, 200, true);Method DriftClient.changeApprovedBuilderReference ↗
Method DriftClient.changeApprovedBuilderReference ↗| Parameter | Type | Required |
|---|---|---|
builder | PublicKeyThe public key of the builder to add or update. | Yes |
maxFeeTenthBps | numberThe maximum fee tenth bps to set for the builder. | Yes |
add | booleanWhether to add or update the builder. If the builder already exists, `add = true` will update the `maxFeeTenthBps`, otherwise it will add the builder. If `add = false`, the builder's `maxFeeTenthBps` will be set to 0. | Yes |
txParams | TxParamsThe transaction parameters to use for the transaction. | No |
| Returns |
|---|
Promise<string> |
Order Placement (Builder adds fee to Swift order)
When your app constructs a Swift order on behalf of a user, include builderIdx and builderFeeTenthBps in the signed message. The builderIdx references the index of your approval in the user’s RevenueShareEscrow.approved_builders list:
import { generateSignedMsgUuid } from "@drift-labs/sdk";
const slot = await takerClient.connection.getSlot();
const orderMessage = {
signedMsgOrderParams: marketOrderParams,
subAccountId: takerClient.activeSubAccountId,
slot: new BN(slot),
uuid: generateSignedMsgUuid(),
stopLossOrderParams: null,
takeProfitOrderParams: null,
// Builder fee fields, added by the builder's app UI
builderIdx: 0, // index in taker's approved_builders list
builderFeeTenthBps: 50, // fee for this order: 5 bps (50 * 0.1bps)
};
const { orderParams: message, signature } =
takerClient.signSignedMsgOrderParamsMessage(orderMessage);
// Submit to Swift API as normal (see Swift docs)Example Builder codes order placementReference ↗
Example Builder codes order placementReference ↗Builder codes order placement.The builder’s app constructs this signed message and submits it to the Swift server. The keeper then bundles the fill transaction, and fees are automatically settled to the builder’s revenue-share account upon fill.