Exchange Transactions
This section covers how to build, sign, and submit transactions to the Synchronicity rollup, and the full perpetual exchange API for order management.
Overview
The rollup uses the Sovereign SDK transaction framework. Transactions are Borsh-serialized, signed with secp256k1 or EIP-712, and submitted to the sequencer over HTTP. The sequencer executes transactions immediately and responds with a soft confirmation.
SDKs and Libraries
Each SDK provides a Signer (key management and signing) and a Serializer (Borsh serialization driven by the rollup schema). You don’t need to implement Borsh serialization yourself — the SDKs fetch the schema from the rollup and handle it for you.
TypeScript
@sovereign-sdk/web3— Transaction building, serialization, and submission@sovereign-sdk/signers— Secp256k1 and EIP-712 signers
Python
py_sovereign_web3— Transaction building, serialization, signing, and submission
Rust
sov-web3—TransactionBuilder, schema-based serializer, and signing utilities
Synchronicity SDK
@synchronicity/sdk— A higher-level TypeScript SDK purpose-built for the Synchronicity rollup with convenience methods for exchange operations. Requires access — contact the team for availability.
Schema
The rollup exposes its full type schema (all modules, call messages, and data types) at:
GET https://api.t.synchronicity.xyz/rollup/schemaThe response includes:
- schema — JSON type definitions for all
RuntimeCallvariants, their fields, and nested types - chain_hash — 32-byte hash derived from the schema, required for signing transactions
The SDKs fetch this schema automatically on initialization and use it to serialize JSON call data into Borsh bytes. You can also inspect the schema directly to see every available call and its expected fields.
Keys and Addresses
The rollup uses secp256k1 keys with Ethereum-compatible address derivation.
| Component | Format |
|---|---|
| Private key | 32 bytes |
| Public key | 33 bytes (compressed secp256k1) |
| Address | 20 bytes (keccak256(uncompressed_pubkey)[12:]) |
Standard Ethereum private keys and addresses work directly.
import { Secp256k1Signer } from "@sovereign-sdk/signers";
import { computeAddress } from "ethers";
const privKey =
"0d87c12ea7c12024b3f70a26d735874608f17c8bce2b48e6fe87389310191264";
const signer = new Secp256k1Signer(privKey);
const address = computeAddress(`0x${privKey}`).toLowerCase();Transaction Structure
A transaction wraps a module call with replay protection, fee parameters, and a signature.
Transaction (V0)
The signed transaction envelope:
| Field | Type | Description |
|---|---|---|
signature | 64 bytes | Compact secp256k1 signature (r || s) |
pub_key | 33 bytes | Compressed secp256k1 public key |
runtime_call | RuntimeCall | The module call to execute |
uniqueness | UniquenessData | Replay protection |
details | TxDetails | Fee and chain parameters |
UnsignedTransaction
The payload that gets signed (same fields minus signature and pub_key):
| Field | Type | Description |
|---|---|---|
runtime_call | RuntimeCall | The module call to execute |
uniqueness | UniquenessData | Replay protection |
details | TxDetails | Fee and chain parameters |
TxDetails
| Field | Type | Description |
|---|---|---|
max_priority_fee_bips | u64 | Priority fee in basis points (0 = no tip) |
max_fee | string | Maximum fee willing to pay (default: "100000000") |
gas_limit | Gas | null | Gas limit (null = unlimited). See Gas & Fees |
chain_id | u64 | Must be 4321 |
UniquenessData
Replay protection. Two modes:
| Variant | Description |
|---|---|
nonce(u64) | Sequential nonce. Must be consecutive per account. |
generation(u64) | Timestamp-based (milliseconds). Must be unique within a time window. Preferred for clients. |
Using generation with Date.now() is recommended since it doesn’t require tracking nonce state.
RuntimeCall
The runtime_call field identifies which module and call to execute. It’s a tagged enum where the key is the module name and the value is the module’s CallMessage:
{
"perp_exchange": {
"create_orders": {
"orders_to_create_perp_orderbook": [
[1, [{ "is_bid": true, "size": 100000 }]]
]
}
}
}Available modules:
| Module key | Description |
|---|---|
perp_exchange | Perpetual exchange operations (see Perpetual Exchange API below) |
advanced_orders | TWAP orders (see CreateTwapOrder). Requires gas_limit — see Gas & Fees |
conditional_execution | Register conditional callbacks. Embedded dependency_call requires gas_limit — see Gas & Fees |
bank | Token transfers — use transfer to send SYNC or other tokens (see Bank Transfer) |
accounts | Account management |
sync_accounts | Synchronicity account operations including delegated signing (call_with_signature). Gas on delegated calls is charged to the inner signer |
tokens | Token management |
oracles | Oracle price updates |
The full schema of all modules and their calls is returned by GET /rollup/schema.
Serialization
All transaction data is serialized using Borsh (Binary Object Representation Serializer for Hashing).
The TypeScript SDK handles serialization automatically using the schema fetched from the rollup:
import { createStandardRollup } from "@sovereign-sdk/web3";
const rollup = await createStandardRollup(
"https://api.t.synchronicity.xyz",
);
// The rollup fetches the schema on init and uses it
// to serialize all calls to Borsh automaticallyThe schema is fetched once from GET /rollup/schema and provides the type definitions needed for the serializer to convert JSON call data to Borsh bytes.
Signing
Standard (Secp256k1)
- Borsh-serialize the
UnsignedTransaction - Append the 32-byte
chain_hash(a compile-time constant derived from the rollup schema) keccak256the combined bytes- Sign the hash with secp256k1 producing a 64-byte compact signature
msg = borsh(UnsignedTransaction) || chain_hash
signature = secp256k1_sign(keccak256(msg), private_key)The chain_hash is returned alongside the schema from GET /rollup/schema.
EIP-712
For wallet integrations (MetaMask, etc.), the rollup supports EIP-712 typed data signing. The EIP-712 domain and struct types are derived from the rollup schema. The wallet signs the EIP-712 digest instead of the raw concatenated bytes, but the transaction content is identical.
Submission Endpoints
Base URL: https://api.t.synchronicity.xyz
POST /sequencer/txs
Submit a transaction signed with a Secp256k1 signature.
Request body:
{
"body": "<base64-encoded Borsh transaction bytes>"
}Response:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}POST /sequencer/eip712_tx
Submit a transaction signed with an EIP-712 typed data signature. Used by browser wallets (MetaMask, etc.) that support Ethereum-style structured data signing.
Request body: Same format as /sequencer/txs but the transaction is expected to contain an EIP-712 signature.
POST /rollup/simulate
Simulate a transaction without committing it to state. Useful for validating calls, checking margin requirements, or estimating gas before real submission. No signature required.
Request body:
{
"sender": "<address_hex>",
"call": { "perp_exchange": { "create_orders": { "...": "..." } } },
"tx_details": {
"max_fee": "100000000",
"chain_id": 4321
}
}Other Endpoints
| Method | Path | Description |
|---|---|---|
GET | /rollup/schema | Returns the runtime schema (all type definitions) and chain_hash |
GET | /sequencer/txs/:tx_hash/status | Poll transaction status by hash |
GET | /rollup/base-fee-per-gas/latest | Current gas price |
Transaction Lifecycle Summary
1. GENERATE KEYS
private_key (32 bytes)
→ secp256k1 → public_key (33 bytes compressed)
→ keccak256[12:] → address (20 bytes)
2. CONSTRUCT RUNTIME CALL
{ "perp_exchange": { "create_orders": { ... } } }
3. BUILD UNSIGNED TRANSACTION
{
runtime_call: <call from step 2>,
uniqueness: { generation: Date.now() },
details: {
max_priority_fee_bips: 0,
max_fee: "100000000",
gas_limit: null,
chain_id: 4321
}
}
4. SERIALIZE & SIGN
utx_bytes = borsh(unsigned_transaction)
msg = utx_bytes || chain_hash
signature = secp256k1_sign(keccak256(msg), private_key)
5. ASSEMBLE SIGNED TRANSACTION
Transaction::V0 {
signature,
pub_key,
runtime_call,
uniqueness,
details
}
6. SUBMIT
tx_bytes = borsh(signed_transaction)
POST /sequencer/txs { "body": base64(tx_bytes) }Perpetual Exchange API
The sync-perp-exchange module is the core of the Synchronicity rollup. It implements a perpetual futures exchange with on-chain orderbooks, batch auction clearing, margin management, funding rates, and liquidations.
All transactions are submitted as serialized CallMessage variants via the Sovereign SDK transaction pipeline described above.
Key Concepts
Batch Auction Model
Orders do not match continuously. Instead, orders rest in the orderbook at their limit price and are cleared every 100ms at the intersection of cumulative bids and asks. This is a frequent batch auction (FBA), not a continuous limit order book.
Decimals
- Lot decimals: Size precision (e.g., 5 for BTC means 1 lot = 0.00001 BTC)
- Tick decimals: Price precision (e.g., 1 means $0.1 increments)
- Margin decimals: 6 decimals used internally for all margin/collateral calculations
- Constraint:
lot_decimals + tick_decimals == 6
Margin Modes
- Crossed: Margin is shared across all positions. Unrealized gains in one position can offset losses in another.
- Isolated: Margin is dedicated per-orderbook. Only the allocated margin is at risk for that position.
MMR Brackets
Each orderbook defines tiered maintenance margin requirements based on position notional size. Larger positions require higher margin rates and are limited to lower leverage.
Transaction Calls
CreateOrders
Place one or more orders across one or more orderbooks in a single transaction.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"create_orders": {
"orders_to_create_perp_orderbook": [
[
1,
[
{
"is_bid": true,
"order_type": "limit",
"price": 500000,
"slippage": null,
"size": 150000,
"reduce_only": false,
"cancel_time": null,
"stop_loss": null,
"take_profit": null,
"client_order_id": null,
"trigger_calls": null
}
]
]
]
}
}
}| Field | Type | Description |
|---|---|---|
orders_to_create_perp_orderbook | Vec<(OrderbookId, Vec<CreateOrder>)> | Batched orders grouped by orderbook |
CreateOrder fields:
| Field | Type | Required | Description |
|---|---|---|---|
is_bid | bool | yes | true = buy/long, false = sell/short |
order_type | OrderType | yes | market or limit |
price | u128 | null | for limit | Limit price in tick decimals |
slippage | u32 | null | for market | Slippage tolerance in centibips (1/100th of a basis point). Defaults to system default if omitted. |
size | u128 | yes | Order size in lot decimals |
reduce_only | bool | yes | If true, order can only reduce an existing position |
cancel_time | u64 | null | no | Unix timestamp (ms) when order auto-cancels. 0 = IOC (immediate-or-cancel) |
stop_loss | SlTp | null | no | Attach a stop loss at order creation |
take_profit | SlTp | null | no | Attach a take profit at order creation |
client_order_id | string | null | no | Hex-encoded caller-chosen ID. Must be unique among the user’s active orders. |
trigger_calls | Vec<OrderTriggerCall> | null | no | Cross-module calls to fire on fill |
Notes:
- Market orders execute at the oracle price +/- slippage during the next clearing cycle.
- Limit orders rest in the orderbook until cleared at a price at or better than their limit.
- An IOC order (
cancel_time: 0) that isn’t filled in the next clearing is automatically cancelled. - If
stop_lossortake_profitis set, the embeddedSlTpobject now requires agas_limitfield (a[compute, storage]array). See Gas & Fees. - If
trigger_callsis set, everytrigger_calls[].dependency_callnow requires agas_limitfield.gas_payeris auto-set to the caller — do not include it.
Response
200 OK - Orders created successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include OrdersCreated(Vec<OrderId>) with the system-assigned IDs for each created order.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Invalid order parameters: price must be positive"
}500 Internal Server Error - Server error:
{
"error": "Failed to create orders"
}ReduceOrders
Reduce the size of one or more existing orders. Can partially or fully cancel orders.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"reduce_orders": {
"order_ids_and_orders_to_reduce": [[1, [[12345, 50000]]]]
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
order_ids_and_orders_to_reduce | Vec<(OrderbookId, Vec<(OrderId, u128)>)> | yes | (order_id, size_to_reduce) grouped by orderbook |
Reducing by the full remaining size is equivalent to cancelling the order.
Response
200 OK - Orders reduced successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include OrdersReduced.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Order not found or invalid parameters"
}500 Internal Server Error - Server error:
{
"error": "Failed to reduce orders"
}ReduceOrdersByClientId
Same as ReduceOrders but references orders by the caller-assigned ClientOrderId instead of the system OrderId.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"reduce_orders_by_client_id": {
"orders_to_reduce": [[1, [["0xabcdef1234567890abcdef1234567890", 50000]]]]
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
orders_to_reduce | Vec<(OrderbookId, Vec<(ClientOrderId, u128)>)> | yes | (client_order_id, size_to_reduce) grouped by orderbook |
Response
200 OK - Orders reduced successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include OrdersReducedByClientId.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Client order ID not found or invalid parameters"
}500 Internal Server Error - Server error:
{
"error": "Failed to reduce orders"
}CancelAllOrders
Cancel all of the caller’s open orders across all orderbooks.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"cancel_all_orders": {
"reduce_only_too": true
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
reduce_only_too | bool | yes | If false, keeps reduce-only orders alive (e.g., SL/TP-generated orders) |
Response
200 OK - Cancel all request processed successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include OrdersCancelled.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}500 Internal Server Error - Server error:
{
"error": "Failed to cancel orders"
}ChangeInitialLeverage
Change the leverage and/or margin mode for the caller’s position in a specific orderbook.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"change_initial_leverage": {
"orderbook_id": 1,
"leverage": 20,
"margin_type": "crossed"
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
orderbook_id | OrderbookId | yes | Target orderbook |
leverage | u8 | yes | New leverage (1 to max allowed by MMR bracket for current notional) |
margin_type | MarginTypeInput | yes | crossed or isolated |
Notes:
- Validates that the new leverage doesn’t violate margin requirements.
- Switching from crossed to isolated (or vice versa) reallocates margin accordingly.
Response
200 OK - Leverage modified successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include ChangeInitialLeverage.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Invalid leverage value or margin requirements violated"
}500 Internal Server Error - Server error:
{
"error": "Failed to modify leverage"
}UpdateIsolatedMargin
Add or remove margin from an isolated-margin position.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"update_isolated_margin": {
"orderbook_id": 1,
"margin": 5000000
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
orderbook_id | OrderbookId | yes | Target orderbook |
margin | i128 | yes | Signed amount: positive = add margin, negative = remove margin |
Notes:
- Only works for positions in isolated margin mode.
- Removing margin is blocked if it would put the position below maintenance margin.
Response
200 OK - Margin updated successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include UpdateIsolatedMargin.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Position is not in isolated margin mode"
}400 Bad Request - Margin removal would violate maintenance margin:
{
"error": "Removing margin would put position below maintenance margin"
}500 Internal Server Error - Server error:
{
"error": "Failed to update isolated margin"
}ManageSlTp
Create, modify, or remove Stop Loss / Take Profit on a position or a specific order.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"manage_sl_tp": {
"orderbook_id": 1,
"order_id": null,
"stop_loss": {
"create": {
"price": { "fixed": 490000 },
"slippage": 100,
"size": 150000,
"gas_limit": [500000, 100000],
"max_priority_fee_bips": 0
}
},
"take_profit": {
"create": {
"price": { "percentage": 20000 },
"slippage": 100,
"size": 150000,
"gas_limit": [500000, 100000],
"max_priority_fee_bips": 0
}
}
}
}
}The gas_limit field is required on every create (and on the new SlTp inside a modify variant). It bounds the gas the SL/TP callback can consume when it triggers. See Gas & Fees.
| Field | Type | Required | Description |
|---|---|---|---|
orderbook_id | OrderbookId | yes | Target orderbook |
order_id | OrderId | null | no | Specific order to attach SL/TP to. null = position-level SL/TP. |
stop_loss | SlTpRequest | yes | Action for stop loss side |
take_profit | SlTpRequest | yes | Action for take profit side |
SlTpRequest variants:
| Variant | Description |
|---|---|
no_change | Leave this side untouched |
create(SlTp) | Create a new SL or TP |
modify(SlTpModify) | Update an existing SL/TP. Includes conditional_execution_id and new SlTp. |
remove(SlTpRemove) | Delete an existing SL/TP. Includes conditional_execution_id. |
SlTp
{
"price": { "fixed": 490000 },
"slippage": 500,
"size": 1000000,
"gas_limit": [500000, 100000],
"max_priority_fee_bips": 0
}| Field | Type | Required | Description |
|---|---|---|---|
price | object | yes | Trigger price — either { "fixed": u128 } for an absolute price in tick decimals, or { "percentage": u32 } for a price offset from fill price in centibips (20_000 = 2%) |
slippage | u32 | yes | Slippage tolerance in centibips (10,000 = 1%) |
size | u128 | yes | Size in lot decimals |
gas_limit | [u64, u64] | yes | Per-execution gas budget [compute, storage]. See Gas & Fees |
max_priority_fee_bips | u64 | no | Sequencer tip in basis points; defaults to 0. Higher tips drain first within a flush cycle |
Price examples:
// Fixed price SL at 49000
"price": { "fixed": 490000 }
// Percentage-based TP 2% above fill price (20000 centibips = 2%)
"price": { "percentage": 20000 }Percentage direction logic:
| Buy / Long | Sell / Short | |
|---|---|---|
| Take Profit | fill price + offset | fill price − offset |
| Stop Loss | fill price − offset | fill price + offset |
Response
200 OK - SL/TP managed successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include SlTpManaged.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "No position or order found for SL/TP"
}500 Internal Server Error - Server error:
{
"error": "Failed to manage SL/TP"
}SetTriggerCall
Attach cross-module trigger calls to an existing open order. Triggers fire on fill events.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
Note: This message must be wrapped in a signed transaction envelope. See Submission Endpoints for details.
The call message structure:
{
"perp_exchange": {
"set_trigger_call": {
"order_id": 12345,
"trigger_calls": [
{
"mode": "on_last_fill",
"dependency_call": {
"call_message": { "...": "..." },
"copy_instructions": null,
"caller": { "...": "..." },
"gas_limit": [500000, 100000],
"max_priority_fee_bips": 0
}
}
]
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
order_id | OrderId | yes | Target order |
trigger_calls | Vec<OrderTriggerCall> | yes | Triggers to attach |
OrderTriggerCall fields:
| Field | Type | Description |
|---|---|---|
mode | TriggerMode | When to fire: on_first_fill, on_every_fill, or on_last_fill |
dependency_call | DependencyCall | Cross-module call payload to execute. Must include gas_limit — see below |
DependencyCall gas fields:
| Field | Type | Required | Description |
|---|---|---|---|
gas_limit | [u64, u64] | yes | Gas budget [compute, storage] for the deferred dispatch. See Gas & Fees |
max_priority_fee_bips | u64 | no | Sequencer tip in basis points; defaults to 0. Doubles as flush priority in the reactive queue |
gas_payer | — | — | Do not set. The rollup auto-defaults this to the caller and rejects any non-caller value (prevents billing-bypass) |
The same dependency_call shape applies to trigger_calls embedded in CreateOrders and to the dependency_call field on conditional_execution.add_conditional_execution.
Response
200 OK - Trigger calls set successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include TriggerCallSet.
Error Responses
401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}400 Bad Request - Invalid nonce or transaction replay:
{
"error": "Invalid nonce or transaction replay detected"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Order not found or invalid trigger configuration"
}500 Internal Server Error - Server error:
{
"error": "Failed to set trigger calls"
}CreateTwapOrder
Create a TWAP (Time-Weighted Average Price) order that splits a parent size into evenly-spaced child fills over a fixed running time. Each child fill is dispatched from the reactive queue and consumes its own gas budget.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
The call message structure:
{
"advanced_orders": {
"create_twap_order": {
"orderbook_id": 1,
"total_size": 1000000,
"num_slices": 10,
"frequency_ms": 60000,
"running_time_ms": 600000,
"is_bid": true,
"reduce_only": false,
"gas_limit": [500000, 100000],
"max_priority_fee_bips": 0
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
orderbook_id | OrderbookId | yes | Target orderbook |
total_size | u128 | yes | Total parent size in lot decimals |
num_slices | u64 | yes | Number of child fills the parent is divided into |
frequency_ms | u64 | yes | Time between child fills, in milliseconds |
running_time_ms | u64 | yes | Total wall-clock duration of the TWAP, in milliseconds |
is_bid | bool | yes | true = buy/long, false = sell/short |
reduce_only | bool | yes | If true, child fills can only reduce an existing position |
gas_limit | [u64, u64] | yes | Per-child-fill gas budget [compute, storage]. Bounds each child execution, not the total TWAP |
max_priority_fee_bips | u64 | no | Sequencer tip in basis points paid on each child fill; defaults to 0 |
Notes:
gas_limitis per child fill, not for the whole TWAP. The total gas a TWAP consumes scales withnum_slices.- If
gas_limitexceeds the reactive queue’s per-item cap, the transaction is rejected at submission. See Gas & Fees. - A TWAP whose child dispatch fails (insufficient gas, runtime revert) is auto-removed via
RemoveOrphanedTwapand reported withcancellation_reason: "DispatchFailed". Clients reading TWAP order status should handle this new variant alongsideUserRequestandOrderCreationFailed.
Response
200 OK - TWAP created successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction event will include TwapOrderCreated.
Error Responses
400 Bad Request - Gas limit exceeds the reactive queue’s per-item cap:
{
"error": "gas_limit [a, b] exceeds max per-item reactive gas [x, y]"
}400 Bad Request - Invalid request format or parameters:
{
"error": "Invalid TWAP parameters"
}401 Unauthorized - Invalid signature or authentication failure:
{
"error": "Invalid transaction signature"
}500 Internal Server Error - Server error:
{
"error": "Failed to create TWAP order"
}To cancel a TWAP, submit advanced_orders.cancel_twap_order with the TWAP id returned in the create event.
Bank Transfer
Send any bank token (including the SYNC gas token) from your account to another account.
Authentication: All transactions require signed envelopes. See Transaction Structure and Signing.
Endpoint
POST https://api.t.synchronicity.xyz/sequencer/txs
Transaction Message
The call message structure:
{
"bank": {
"transfer": {
"to": "0xRecipientAddress0000000000000000000000000",
"coins": {
"token_id": "token_1nyl0e0yweragfsatygt24zmd8jrr2vqtvdfptzjhxkguz2xxx3vs0y07u7",
"amount": "1000000"
}
}
}
}| Field | Type | Required | Description |
|---|---|---|---|
to | string | yes | Recipient Ethereum address |
coins.token_id | string | yes | Token ID to transfer. Use the SYNC token id to send gas |
coins.amount | string | yes | Amount in the token’s native decimals |
Response
200 OK - Transfer submitted successfully:
{
"id": "<tx_hash_hex>",
"status": "submitted"
}The transaction emits a TokenTransferred event from the sender to the recipient.
Types Reference
Core IDs
| Type | Underlying | Description |
|---|---|---|
OrderbookId | u64 | Unique orderbook identifier, chosen at creation |
OrderId | u64 | System-assigned order ID (nonce-based) |
ClientOrderId | bytes (hex) | Caller-chosen order identifier, must be unique among active orders |
OrderType
| Variant | Description |
|---|---|
market | Executes at oracle price +/- slippage at next clearing |
limit | Rests in orderbook at specified price until cleared |
MarginTypeInput
| Variant | Description |
|---|---|
crossed | Shared margin across all positions |
isolated | Dedicated margin per orderbook |
SlTp
{
"price": { "percentage": 20000 },
"slippage": 500,
"size": 1000000,
"gas_limit": [500000, 100000],
"max_priority_fee_bips": 0
}| Field | Type | Required | Description |
|---|---|---|---|
price | object | yes | { "fixed": u128 } — absolute price in tick decimals, or { "percentage": u32 } — offset from fill price in centibips (20_000 = 2%) |
slippage | u32 | yes | Slippage tolerance in centibips (10,000 = 1%) |
size | u128 | yes | Size in lot decimals |
gas_limit | [u64, u64] | yes | Per-execution gas budget [compute, storage]. See Gas & Fees |
max_priority_fee_bips | u64 | no | Sequencer tip in basis points; defaults to 0 |
Percentage direction logic:
| Buy / Long | Sell / Short | |
|---|---|---|
| Take Profit | fill price + offset | fill price − offset |
| Stop Loss | fill price − offset | fill price + offset |
TriggerMode
| Variant | Description |
|---|---|
on_first_fill | Fires once on first partial fill, then self-removes |
on_every_fill | Fires on every fill (partial or complete) |
on_last_fill | Fires only when order is fully filled |