Transaction Fields
Every transaction submitted to the Bullet exchange is wrapped in an UnsignedTransaction containing three components:
the call message, a uniqueness value, and transaction details. This guide covers the uniqueness and details fields.
Uniqueness
The UniquenessData field prevents transaction replay. Bullet supports two modes:
#![allow(unused)]
fn main() {
enum UniquenessData {
Nonce(u64) = 0,
Generation(u64) = 1,
}
}
Generation mode (recommended)
The uniqueness value can be whatever you want — it just needs to be unique per user within a block window (~5-6 seconds). We recommend using microsecond timestamps.
- No need to track or increment a counter
- Multiple transactions can be in-flight concurrently
Best practice: use SystemTime::now() in microseconds. Avoid reusing values — if you submit multiple
transactions in a tight loop, ensure each is distinct.
Nonce mode
Use Nonce(u64) for strict sequential ordering. The nonce must be exactly current_nonce + 1 for the credential.
This mode is simpler but only allows one in-flight transaction at a time.
TxDetails
#![allow(unused)]
fn main() {
struct TxDetails {
max_priority_fee_bips: u64,
max_fee: Amount,
gas_limit: Option<[u64; 2]>,
chain_id: u64,
}
}
These fields are required in every transaction. We recommend using the values below.
| Field | Type | Description |
|---|---|---|
chain_id | u64 | Chain identifier — fetch from GET /fapi/v1/exchangeInfo → chainInfo.chainId |
max_fee | Amount(u128) | Maximum fee the sender is willing to pay |
gas_limit | Option<[u64; 2]> | 2D gas limit: [compute, storage]. None defaults to block limit |
max_priority_fee_bips | u64 | Priority fee tip in basis points |
Gas model
Bullet uses a 2D gas model with separate compute and storage dimensions. The gas_limit field caps how much of
each resource a transaction may consume.
Paymaster
Gas fees are covered by a paymaster — users do not pay gas out of pocket. The fields are still required for transaction validity.
Recommended Values
| Field | Recommended value | Notes |
|---|---|---|
uniqueness | Generation(timestamp_us()) | Microsecond timestamp |
max_priority_fee_bips | 0 | |
max_fee | 1 << 48 | |
gas_limit | None | Defaults to block limit. Use [5_000_000, 5_000_000] for order placement or [500_000, 500_000] for simpler ops if you want explicit caps |
chain_id | from exchangeInfo | Must match the chain you are submitting to |
See the default_tx_details helper for a ready-to-use implementation.