LogoLogo
  • Overview
    • Introduction
    • Table of Contents
  • Token Information
    • Symmio Foundation
  • Protocol Architecture
    • Protocol Introduction
    • Technical Documentation
      • Building an Application with SYMM
        • Introduction and Diamond Explainer
        • Querying Info from the SYMM Diamond
        • MultiAccount
        • Creating an Account and Depositing Funds
        • Sending a Quote
        • Closing a Quote
        • Instant Trading
          • Instant Login (EOA)
          • Instant Login (Account Abstraction)
          • Sending a Quote (Instant Open)
          • Sending a Quote (Instant Close)
        • Frequently Used Queries
      • Solver Docs
        • Solver Docs (github)
        • Solver Implementation Guide (High Level Overview)
        • Building a Solver on SYMMIO
          • 1. Intent Creation
          • 2. Seeing the Intent
          • 3. Hedging Off-Chain
          • 4. Opening/Closing a Position On-Chain
          • Creating the APIs
            • GET Contract Symbols
            • GET Open Interest
            • GET Notional Cap
            • GET Price Range
            • GET Error Codes
            • GET Get Locked Params
            • GET Get Funding Info
            • POST Position State
          • Solver Flow Summary Example
          • Recommended Architecture for Solvers
          • Glossary
        • Conditional Orders Handler
        • Rasa Solver TP/SL Implementation
        • Instant Trading
          • Instant Trading (Solvers)
          • Rasa Instant Trading Implementation
          • Instant Trading Condition Checks
        • Fetching Gas Prices Script
        • How to Add a Market as a Solver
        • Verifying Account Abstracted Instant Actions (ERC-4337)
      • Frontend Docs
        • Setting up a Frontend with SYMMIO
        • Frontend SDK Setup Guide
        • MultiAccount Deployment Guide
        • Instant Trading (Frontends)
          • Account Abstracted Instant Actions (Frontends)
        • Implement a Trading Bot on Symmio (OLD)
          • Setup
          • Creating a Sub-Account
          • Minting Collateral Tokens (Optional)
          • Depositing and Allocating Tokens
          • Obtaining Muon Signatures
          • Sending a Quote
          • Monitoring Price for Execution
      • Contract Docs
        • SYMMIO CORE v0.82
        • Contracts Documentation 0.8.2
          • Main Flow
          • The SYMM Diamond
          • Facets
            • Account Facet
            • Control Facet
            • Funding Rate Facet
            • PartyA Facet
            • PartyB Facet
            • Liquidation Facet
            • View Facet
          • MultiAccount
            • PartyA
            • PartyB
          • SYMM App (Muon)
            • LibMuon
            • MuonStorage
        • Contracts Documentation 0.8.3
          • Facets
            • Control Facet
            • Account Facet
            • PartyA Facet
            • PartyB Facet
            • View Facet
            • Bridge Facet
            • Liquidation Facet (Implementation)
          • Modified Events
          • New Events
          • MuonStorage
        • Contracts Documentation 0.8.4
          • Main Flow (0.8.4)
          • The SYMM Diamond (0.8.4)
          • Facets
            • Account Facet (0.8.4)
            • Bridge Facet (0.8.4)
            • Control Facet (0.8.4)
            • Force Actions Facet (0.8.4)
            • Funding Rate Facet (0.8.4)
            • Liquidations Facet (0.8.4)
            • PartyA Facet (0.8.4)
            • PartyB Group Actions Facet (0.8.4)
            • PartyB Quote Actions Facet (0.8.4)
            • PartyB Position Actions Facet (0.8.4)
            • Settlement Facet (0.8.4)
            • View Facet (0.8.4)
          • MultiAccount (0.8.4)
            • SymmioPartyA
            • SymmioPartyB
          • SYMM App (Muon)
            • LibMuon (0.8.4)
            • MuonStorage (0.8.4)
      • Contract Addresses / Solver Endpoints
        • Mantle
        • Mode
        • IOTA
        • Base
        • BSC
        • Arbitrum
        • Polygon
        • Berachain
        • Solver Endpoints and Addresses
          • Perps Hub
          • Rasa Capital
          • Zenith
      • How to Query our Contracts
      • Muon API Queries
      • Solver Error Codes
      • Interacting with SYMMIO Contracts
    • Protocol higher level architecture
      • 12-Hour Fraud Proof Window
      • PartyB
      • Solver Settings
      • Max Leverage
      • Maintenance Margin (CVA) Calculations
    • Symmio Whitepaper
  • Building on Symmio
    • Builders introduction
    • Solving for Symmio
      • Solver documentation
      • Solver - Example Flow
    • Trading Fees
      • Perps - Settlement Costs
      • Pair Trading - Settlement costs
    • Exchanges (Frontends)
      • Frontend Introduction
      • SDK - SYMM client
      • Trade on Symmio
  • Legal & Brand & Security
    • Security (Audits / Bugbounty)
      • Bug bounty / Coverage
        • How to contact ?
      • Audits
        • SYMM - V0.8 - 0.81
          • Sherlock Audit - Jun 15, 2023
          • Smart State - Jul 2, 2023
        • SYMM - 0.82
          • Sherlock Audit -Aug 30, 2023
        • SYMM - 0.83
          • Sherlock Audit - Jun 17, 2024
        • SYMM - 0.84
          • Sherlock Audit - Oct 3, 2024
        • Vaults
          • Sherlock Audit - Jan 2, 2024
    • Terms of Service & Licensing
      • TRADEMARK & COPYRIGHT NOTICE
      • CONTACT US
      • TERMS OF SERVICE
      • FRONTEND LICENSE
        • Frontend Modifications
        • Frontend Use Grants
      • CONTRACT LICENSE
        • Contract Use Grants
        • Contract Modifications
    • Brand - Assets Logos
Powered by GitBook
LogoLogo

All rights to the people (c) 2023 Symmetry Labs A.G.

On this page
  • /position-state
  • Overview
  • Endpoint Specification
  • Request & Response Schemas
  • Data Sources & Field Mapping
  • Implementation Details (Annotated)
  • Controller Layer (controllers.py)
  • Example (Full Open Position -> Close Position Flow)
  • Full Lifecycle Flow
  1. Protocol Architecture
  2. Technical Documentation
  3. Solver Docs
  4. Building a Solver on SYMMIO
  5. Creating the APIs

POST Position State

/position-state

position-state/{start}/{size}

Example Query:

https://base-hedger82.rasa.capital/position-state/{start}/{size}

Overview

This endpoint gives insights into historical lifecycle updates for positions based on a quote ID or counterparty address. Results are sourced from the Notifications, Positions, and Symbol tables, then mapped into the response schema.


Endpoint Specification

URL: https://base-hedger82.rasa.capital/position-state/{start}/{size} Method: POST

Headers

  • Content-Type: application/json

  • Optional: App-Name:(client identifier)

cURL Example (Limit Open — Reserved but not yet Opened)

curl -X POST "https://base-hedger82.rasa.capital/position-state/0/10" \
     -H "Content-Type: application/json" \
     -H "App-Name: Cloverfield" \
     -d '{"quote_id": "131388"}'

Response (HTTP 200):

{
    "count": 1,
    "position_state": [
        {
            "id": "7d0c10a4-1d7e-44b9-8712-77c863bfab55",
            "create_time": 1745970777,
            "modify_time": 1745970777,
            "quote_id": 131388,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "0",
            "filled_amount_close": "0",
            "avg_price_open": "0",
            "avg_price_close": "0",
            "last_seen_action": "SendQuote",
            "action_status": "seen",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "alert"
        }
    ]
}

Path Parameters

Name
Type
Description

start

integer

0-based pagination offset

size

integer

Number of records to return (max 100)

Body Parameters (JSON)

Provide at least quote_id or address of the following to filter results; other fields are optional:

Field

Type

Description

quote_id

string

Exact quote ID (string). One of quote_id or address is required.

address

string

Counterparty address (Ethereum hex string). One of quote_id or address is required.

symbols

string[]

Optional filter by trading symbols (e.g., ["ETHUSD"]).

states

string[]

Optional filter by position state enums (e.g., ["alert"]).

create_time_gte

integer

Optional: include records with Notifications.create_time >= epoch seconds UTC.

modify_time_gte

integer

Optional: include records with Notifications.modify_time >= epoch seconds UTC.


Request & Response Schemas

Define Schemas

Create PositionsStateRequestSchema and PositionStateResponseSchema + PositionsStateOutputSchema in the schema file.

class PositionStateResponseSchema(BaseModel):
    id: UUID
    create_time: int
    modify_time: int
    quote_id: int
    temp_quote_id: Optional[int] = None
    counterparty_address: str
    filled_amount_open: Decimal = 0
    filled_amount_close: Decimal = 0
    avg_price_open: Decimal = 0
    avg_price_close: Decimal = 0
    last_seen_action: str
    action_status: str
    failure_type: Optional[str] = None
    error_code: Optional[int] = None
    order_type: int
    state_type: PositionStateType

class PositionsStateOutputSchema(BaseModel):
    count: int
    position_state: List[PositionStateResponseSchema]

Data Sources & Field Mapping

Response Field
Source Table.Column(s)
Notes

id

Notifications.id

Primary key (UUID) -> in some solver implementations this is also the quote ID.

create_time

Notifications.create_time

Epoch seconds UTC

modify_time

Notifications.modify_time

Epoch seconds UTC

quote_id

Notifications.quote_id

quote_id.

temp_quote_id

Notifications.temp_quote_id

Used for instant trades or null.

counterparty_address

Notifications.counterparty_address

partyA address

filled_amount_open

Notifications.filled_amount_open

Recorded open fill amount

avg_price_open

Notifications.avg_price_open

Recorded open fill price

filled_amount_close

Notifications.filled_amount_close

Recorded close fill amount

avg_price_close

Notifications.avg_price_close

Recorded close fill price

last_seen_action

Notifications.last_seen_action

e.g., SendQuote, FillLimitOrderOpen

action_status

Notifications.action_status

success, seen, etc.

failure_type

Notifications.failure_type

If action failed

error_code

Notifications.error_code

Numeric code

order_type

Notifications.order_type

Limit = 0, Market = 1

state_type

Notifications.state_type

"alert" or "report"


Implementation Details (Annotated)

This section explains how each piece fits together.

Router Layer (routers.py)

@common_router.post(
    '/position-state/{start}/{size}',
    responses={status.HTTP_200_OK: {"model": PositionsStateOutputSchema}},
    response_model=PositionsStateOutputSchema
)
@with_context_db_session
async def search_position_state(
    request: PositionsStateRequestSchema,
    start: NonNegativeInt = 0,
    size: PositiveInt = 100
):
    # Map incoming HTTP payload to internal search DTO
    new_request = NotificationsRequestSchema()
    new_request.counterparty_address = request.address
    new_request.quote_id = request.quote_id
    new_request.symbols = request.symbols
    new_request.states = request.states
    new_request.timestamp_gte = request.modify_time_gte

    # Call service layer to fetch and map results
    count, data = search_notification_by_counterparty(
        new_request, start, size, map_to_positions_state=True
    )

    # Return raw dict form; FastAPI serializes to schema
    return dict(count=count, position_state=data)

Controller Layer (controllers.py)

# Located in controllers.py
# Handles fetching and mapping notifications to position state

def search_notification_by_counterparty(
    request: NotificationsRequestSchema,
    start: int,
    size: int,
    map_to_positions_state: bool = False
):
    # a. Sanitize page size
    size = min(size, 100)

    # b. Handle relative timestamps (e.g., -3600 for last hour)
    if request.timestamp_gte and request.timestamp_gte < 0:
        request.timestamp_gte = get_now_epoch() + request.timestamp_gte

    # c. Build base SQLAlchemy query with necessary joins
    stmt = (
        Notifications.select()
        .outerjoin(
            Positions,
            or_(
                Positions.quote_id == Notifications.quote_id,
                Positions.temp_quote_id == Notifications.temp_quote_id
            )
        )
        .outerjoin(
            Symbol, Positions.symbol_id == Symbol.symbol_id
        )
        .where(Notifications.should_send == true())
    )

    # d. Apply filters based on request fields
    if request.quote_id:
        if is_quote_id_temp(request.quote_id):
            stmt = stmt.where(Notifications.temp_quote_id == request.quote_id)
        else:
            stmt = stmt.where(Notifications.quote_id == request.quote_id)
    if request.counterparty_address:
        stmt = stmt.where(
            Notifications.counterparty_address == request.counterparty_address
        )
    if request.states:
        stmt = stmt.where(Positions.state.in_(request.states))
    if request.symbols:
        stmt = stmt.where(Symbol.title.in_(request.symbols))
    if request.timestamp_gte:
        stmt = stmt.where(Notifications.create_time >= request.timestamp_gte)

    # e. Count and paginate
    count = session.count_star(stmt)
    records = (
        session.scalars_all(
            stmt.order_by(desc(Notifications.create_time))
                .offset(start)
                .limit(size)
        )
    )

    # f. Map to DTOs
    result = []
    for row in records:
        data = row.to_dict()
        if map_to_positions_state:
            result.append(map_notification_to_positions_state(data))
        else:
            result.append(prepare_notification_to_send(data))
    return count, result

Example (Full Open Position -> Close Position Flow)

cURL Query

curl -X POST "https://base-hedger82.rasa.capital/position-state/0/10" \
     -H "Content-Type: application/json" \
     -H "App-Name: Cloverfield" \
     -d '{"quote_id": "131391"}'

fResponse (HTTP 200):

{
    "count": 6,
    "position_state": [
        {
            "id": "000be762-2592-43b0-937f-32a75fa4587a", //last notification
            "create_time": 1745976098,
            "modify_time": 1745976098,
            "quote_id": 131391,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "0",
            "filled_amount_close": "0",
            "avg_price_open": "0",
            "avg_price_close": "0",
            "last_seen_action": "FillLimitOrderClose",
            "action_status": "success",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "alert"
        },
        {
            "id": "4763fe3d-e3ed-40f9-9821-2b501342579b",
            "create_time": 1745976092,
            "modify_time": 1745976092,
            "quote_id": 131391,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "0",
            "filled_amount_close": "6.70000000",
            "avg_price_open": "0",
            "avg_price_close": "2.2345",
            "last_seen_action": "RequestToClosePosition",
            "action_status": "success",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "report"
        },
        {
            "id": "c99b51b8-a18e-4271-af05-3ed37f3805b9",
            "create_time": 1745976091,
            "modify_time": 1745976091,
            "quote_id": 131391,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "0",
            "filled_amount_close": "0",
            "avg_price_open": "0",
            "avg_price_close": "0",
            "last_seen_action": "RequestToClosePosition",
            "action_status": "seen",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "alert"
        },
        {
            "id": "8ff29bbd-6ca6-42cd-973f-20b6f88bfdea",
            "create_time": 1745976010,
            "modify_time": 1745976010,
            "quote_id": 131391,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "0",
            "filled_amount_close": "0",
            "avg_price_open": "0",
            "avg_price_close": "0",
            "last_seen_action": "FillLimitOrderOpen",
            "action_status": "success",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "alert"
        },
        {
            "id": "98620b7c-c752-42ed-8611-34bde40a4b28",
            "create_time": 1745976004,
            "modify_time": 1745976004,
            "quote_id": 131391,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "6.70000000",
            "filled_amount_close": "0",
            "avg_price_open": "2.2367",
            "avg_price_close": "0",
            "last_seen_action": "SendQuote",
            "action_status": "success",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "report"
        },
        {
            "id": "2f383602-054e-46a2-96e6-b39a7c483c49", //first notification
            "create_time": 1745975999,
            "modify_time": 1745975999,
            "quote_id": 131391,
            "temp_quote_id": null,
            "counterparty_address": "0xEb42F3b1aC3b1552138C7D30E9f4e0eF43229542",
            "filled_amount_open": "0",
            "filled_amount_close": "0",
            "avg_price_open": "0",
            "avg_price_close": "0",
            "last_seen_action": "SendQuote",
            "action_status": "seen",
            "failure_type": null,
            "error_code": 0,
            "order_type": 0,
            "state_type": "alert"
        }
    ]
}

By Address

curl -X POST "https://base-hedger82.rasa.capital/position-state/0/50" \
     -H "Content-Type: application/json" \
     -H "App-Name: Cloverfield" \
     -d '{
       "address": "0x20F764F49bf8A2c653942dA29FeD1D7A7BAefD20"
     }'

Response (200 OK):

{
  "count": 383,
  "position_state": [ /* items */ ]
}

Full Lifecycle Flow

Below is the end-to-end sequence of events and how they map to the records you see in the /position-state response:

  1. RFQ Observed

    • On-Chain Event Poller listens for SendQuote events.

    • Creates a “alert” notification (state_type = "alert") with action_status = "seen" and zeros in all fill fields.

    • At this point the hedger can lock the quote. The quote is seen but not yet filled.

  2. Hedger Confirmation & Opening of the position

    • The hedger’s risk engine executes the quote on-chain.

    • Updates the Notificationstable with actual filled_amount_open and avg_price_open values.

    • Emits a “report” notification (state_type = "report") with action_status = "success" and real fill data.

  3. On-Chain Fill Event

    • Almost immediately thereafter, the contract itself emits an OpenPositionevent when the transaction finally lands on-chain.

    • Poller picks it up and creates another “alert” (state_type = "alert") with zeros in fill fields until the DB update completes.

    • The same poller picks up that on-chain event and writes a fresh Notification with

      • last_seen_action = "FillLimitOrderOpen"

      • action_status = "success"

PreviousGET Get Funding InfoNextSolver Flow Summary Example

Last updated 9 days ago