For the complete documentation index, see llms.txt. This page is also available as Markdown.

Closing a position

Closing is one EIP-712 op. The trick is signerAccount.addr: for closes it's the virtual account, not the sub-account.

Why? Because as far as the Symmio core is concerned, it's that virtual address that holds the quote. The core looks up quotes[quoteId].partyA and checks that the caller (after the AccountLayer's signer-context forwarding) matches. That partyA is the VA. Sign as the sub-account and the core rejects the call with an authorization error that doesn't exactly say "wrong account"; it just fails.

Compute close price

Slippage runs in the opposite direction to opens: when you close a long, you're selling, so you accept a lower price; when you close a short, you're buying back, so you accept a higher price.

Side closing
Worst-acceptable close price

CLOSE LONG

price = mark × (1 − slippage / 100)

CLOSE SHORT

price = mark × (1 + slippage / 100)

Quantize to price_precision and convert to wei.

Sign one SignedOperation

The envelope is the same SignedOperation struct as for opens, the domain is the same SymmioInstantLayer, and the signer is the same session key. The fields that differ:

  • target: Symmio Core (same as sendQuote)

  • signerAccount.addr: virtual account

  • callData: selector 0x501e891f followed by ABI-encoded (quoteId: uint256, closePrice: uint256, quantityToClose: uint256, orderType: uint8, deadline: uint256). orderType = 1 for MARKET.

POST as a JSON array

POST <instant-close endpoint>
Content-Type: application/json

[
  {
    "signedOperation": { ... },
    "signature": "0x..."
  }
]

Note the array. Open is a JSON object, close is a JSON array. Mixing them up may cause failures on the server side.

The solver responds with 200 null when the close is queued. The notifications WS will show FillCloseRequest once it fills on-chain.

Last updated