# Transaction Signing

All write operations (placing orders, cancelling, deposits) are submitted as signed transactions to the Bullet
exchange. This page describes how to build, sign, and submit a transaction.

This will be codified into official SDKs in the near future, but for now you can use the following Rust code as a
reference implementation. The same principles apply in any language: build the call message, wrap in an unsigned
transaction, sign, wrap in a signed transaction, and submit.

## Overview

```text
1. Build call message           (e.g. PlaceOrdersCall, CancelAllOrders)
2. Wrap in UnsignedTransaction  (call + uniqueness + tx details)
3. Sign                         borsh(unsigned_tx) ++ chain_hash → ed25519 sign
4. Wrap in SignedTransaction     (signature + pubkey + unsigned_tx)
5. Submit                       borsh(signed_tx) → base64 → POST or WS
```

## Prerequisites

Fetch exchange info once to obtain chain parameters (`chain_id` and `chain_hash`) and available markets:

```
GET /fapi/v1/exchangeInfo
```

From the response, extract:

- `chainInfo.chainId` — u64 chain identifier
- `chainHash` — 32-byte hex string, decode to `[u8; 32]` (strip `0x` prefix if present)
- `symbols` — array of available markets; each entry contains `marketId` (u16) and `symbol` (e.g. `"BTC-USD"`)

Use the `symbols` array to map between human-readable symbol names and the `market_id` values required by all order
calls.

You also need an **ed25519 keypair** for signing.

## Dependencies

<!-- @formatter:off -->
```toml
{{#include example/Cargo.toml:deps}}
```
<!-- @formatter:on -->

## Rust Types

All types are borsh ([borsh.io](https://borsh.io)) serialized. Enum discriminants and struct field ordering must match
the schema exactly (`GET /rollup/schema`).

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:borsh_types}}
```
<!-- @formatter:on -->

For field reference (order types, TP/SL, sub-account index), see [Order Types and Fields](./order-fields.md).

## Helpers

<!-- @formatter:off -->
```rust
use std::time::{SystemTime, UNIX_EPOCH};
use rust_decimal::Decimal;

{{#include example/src/lib.rs:helpers}}
```
<!-- @formatter:on -->

## Signing

<!-- @formatter:off -->
```rust
use borsh::BorshSerialize;
use ed25519_dalek::{Signer, SigningKey};

{{#include example/src/lib.rs:sign_transaction}}
```
<!-- @formatter:on -->

## Place Orders

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:create_place_order_bytes}}
```
<!-- @formatter:on -->

## Cancel Orders

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:create_cancel_order_bytes}}
```
<!-- @formatter:on -->

## Cancel Market Orders

Cancels every open order on a given market. No order list needed — just the `market_id`.

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:create_cancel_market_orders_bytes}}
```
<!-- @formatter:on -->

## Cancel All Orders

Cancels every open order across all markets.

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:create_cancel_all_order_bytes}}
```
<!-- @formatter:on -->

## Replace Orders

Replace uses `PlaceOrders` with `replace: true`. This atomically cancels **all** existing orders on the market and
places the new set in one transaction. Useful for market makers who want to refresh their entire quote set.

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:create_replace_order_bytes}}
```
<!-- @formatter:on -->

## Amend Orders

Amend atomically cancels specific orders by ID and places new ones. Unlike replace, it targets individual orders rather
than wiping the entire market. Each `AmendOrderArg` pairs a cancel (by `order_id` or `client_order_id`) with a new
order placement.

<!-- @formatter:off -->
```rust
{{#include example/src/lib.rs:create_amend_order_bytes}}
```
<!-- @formatter:on -->

## Order Management Comparison

|                    | Scope          | Atomic | Use case                  | Keeps queue priority |
|--------------------|----------------|--------|---------------------------|----------------------|
| **Cancel + Place** | Per order      | No     | Simple workflows          | No                   |
| **Amend**          | Per order      | Yes    | Adjusting price/size      | No                   |
| **Replace**        | Entire market  | Yes    | Refreshing full quote set | No                   |

## Demo

<!-- @formatter:off -->
```rust
{{#include example/src/main.rs:demo}}
```
<!-- @formatter:on -->

## Submitting

Base64-encode the borsh-serialized bytes, then submit via REST or WebSocket:

**REST:**

```
POST /tx/submit
Content-Type: application/json

{ "body": "<base64>" }
```

**WebSocket:**

```json
{
  "method": "order.place",
  "params": {
    "tx": "<base64>"
  },
  "id": 1
}
```

`tx` is the base64-encoded borsh-serialized `SignedTransaction` bytes from the signing step above.

| Transaction type     | WebSocket method   |
|----------------------|--------------------|
| PlaceOrders          | `order.place`      |
| PlaceOrders (replace)| `order.place`      |
| CancelOrders         | `order.cancel`     |
| CancelMarketOrders   | `order.cancelAll`  |
| CancelAllOrders      | `order.cancelAll`  |
| AmendOrders          | `order.amend`      |
