Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Delegate Accounts

A delegate is a separate keypair authorized to trade on behalf of your main account. Orders placed by a delegate are attributed to the delegator’s account — they share the same balances, positions, and margin.

Why use delegates

  • Security: your main wallet key stays in your wallet; the delegate key is the only secret you handle - if the delegate key is compromised, your main wallet remains untouched
  • Scoped access: delegates can only trade, but cannot deposit or withdraw
  • Revocable: delegate access can be removed anytime by your main account
  • Visibility: all trades made by delegates appear in the webapp UI under your account

Setup

1. Generate a keypair

Generate an ed25519 keypair locally. This will be your delegate key.

Solana CLI (easiest):

solana-keygen new --outfile delegate-key.json --no-bip39-passphrase
solana-keygen pubkey delegate-key.json

The generated file contains the 64-byte secret key (first 32 bytes are the private key, last 32 are the public key). The printed public key (base58) is what you register in the webapp.

Rust:

#![allow(unused)]
fn main() {
use ed25519_dalek::SigningKey;

let keypair = SigningKey::generate(&mut rand::thread_rng());
let public_key = hex::encode(keypair.verifying_key().to_bytes());
let private_key = hex::encode(keypair.to_bytes());

println!("public key:  {public_key}");   // register this in the webapp
println!("private key: {private_key}");   // use this to sign API transactions
}

Python:

from nacl.signing import SigningKey

keypair = SigningKey.generate()
public_key = keypair.verify_key.encode().hex()
private_key = keypair.encode().hex()

print(f"public key:  {public_key}")   # register this in the webapp
print(f"private key: {private_key}")   # use this to sign API transactions

Store the private key securely. You will need the public key for the next step.

2. Register the delegate in the webapp

  1. Sign in at app.bullet.xyz
  2. Navigate to More → Delegate Accounts
  3. Enter a name and your delegate’s public key
  4. Confirm — this signs a delegation transaction with your main wallet

3. Trade with the delegate key

Sign transactions with the delegate’s private key. The exchange resolves the delegate to your main account automatically — no special fields or flags needed.

#![allow(unused)]
fn main() {
// sign with the delegate keypair — order executes on the main account
let order_bytes = create_place_order_bytes(
    &delegate_keypair,
    chain_id,
    &chain_hash,
    market_id,
    orders,
);
}

See Transaction Signing for the full signing flow.

Note: For read endpoints (account info, balances, positions, open orders), always use your main account’s address — not the delegate’s. All state lives on the main account.

Capabilities

OperationDelegateMain wallet
Place / cancel ordersYesYes
DepositYesYes
WithdrawNoYes

Revoking a delegate

From the webapp, go to More → Delegate Accounts and remove the delegate. Revocation is immediate — the delegate key can no longer submit transactions for your account.

Limits

  • Up to 10 delegates per account
  • Delegate names are max 20 characters
  • A delegate address cannot already have its own account
  • A delegate cannot be registered to multiple accounts