Ethereal Docs
  • Introduction
    • What is Ethereal?
  • Public Testnet
  • Trading
    • Perpetual Futures
      • Margining
      • Order Types
      • Positions
      • Funding Rates
      • Market Specifications
      • Liquidations
      • Auto Deleveraging
      • Subaccounts
      • Price Oracles
  • Points
    • Staking sENA
    • Season Zero
  • developer-guides
    • Trading API
      • Quick Start
      • Message Signing
      • Accounts & Signers
      • Order Placement
      • System Limits
      • Products
      • Token Transfers
      • Supported Tokens
      • Websocket Gateway
    • Python SDK
  • Protocol Reference
    • API Hosts
    • Contracts
    • Audits
Powered by GitBook
On this page
  • Overview
  • How to Create a Subaccount
  • Querying
  • Linked Signers
  • Purpose of Linked Signers?
  • Revoking Signers
  • Signer Expiry
  • Querying for Linked Signers
  • System Accounts
  1. developer-guides
  2. Trading API

Accounts & Signers

Overview

All trading on Ethereal is done through subaccounts. Users can create multiple subaccounts to manage positions and balances separately.

How to Create a Subaccount

To start trading on Ethereal, you'll need to establish at least one subaccount. This process begins with selecting a unique bytes32 identifier for your subaccount, followed by making an initial deposit.

We recommend using the default subaccount name primary (encoded as bytes32).

Any valid bytes32 can be used as an identifier but we suggest you to avoid unicode characters.

To deposit, call deposit directly through the exchange smart contracts:

/// @notice Deposit `amount` of token from msg.sender to the `subaccount`.
/// @param subaccount bytes32 encoded string of the subaccount (unique per EOA)
/// @param depositToken Address of the supported deposit token to deposit
/// @param amount The amount of tokens in native units to deposit (non-D9)
/// @param referralCode accepted only on the first deposit for an account, reference to credit for referral
function deposit(
	bytes32 subaccount,
	address depositToken,
	uint256 amount,
	bytes32 referralCode
) external;

Set referralCode to bytes32(0) if you don't have a ref code. Subsequent deposits to the same subaccount will not create a new subaccount and follow the same path.

Users can create an unlimited number of subaccounts on our exchange without any restrictions on the total quantity. While we don't charge fees for deposits at present, each deposit must meet a specified minimum amount to ensure account viability. Though deposits are currently free, be aware that we may implement a nominal fee structure for deposits in the future as part of our evolving service model and preventing spam.

Querying

Upon deposit, funds enter a pending state while our system processes the transaction. The smart contracts emit events that are captured by our offchain indexer and verified by the matching engine. This verification is then relayed back onchain to complete the process.

Once confirmation is complete, the funds become available as margin for trading. This entire sequence typically completes within seconds. The two-step confirmation process is essential for maintaining synchronization between onchain smart contracts and our offchain systems, ensuring transaction integrity throughout the platform.

You can query the trading API to retrieve the state of your subaccount:

curl -X 'GET' \
  'https://api.etherealtest.net/v1/subaccount?sender=0x5d9351C05fA2a6F71d3D1c1A1218C77f2D60919e' \
  -H 'accept: application/json'
{
  "hasNext": false,
  "data": [
    {
      "id": "45783bec-4675-4116-8829-f277afe063d7",
      "name": "0x7072696d61727900000000000000000000000000000000000000000000000000",
      "account": "0x5d9351C05fA2a6F71d3D1c1A1218C77f2D60919e",
      "blockNumber": "11205366",
      "createdAt": 1743745535947
    }
  ]
}

In this example, we are querying for subaccounts belonging to 0x5d9351C05fA2a6F71d3D1c1A1218C77f2D60919e and the API has returned one subaccount with the id of 45783bec-4675-4116-8829-f277afe063d7 and a bytes32 subaccount name of 0x7072696d61727900000000000000000000000000000000000000000000000000(i.e. primary ).

Once you have a subaccount id you can also query the subaccount directly:

curl -X 'GET' \
  'https://api.etherealtest.net/v1/subaccount/45783bec-4675-4116-8829-f277afe063d7' \
  -H 'accept: application/json'

You can also query for the subaccount's balance by:

curl -X 'GET' \
  'https://api.etherealtest.net/v1/subaccount/balance?subaccountId=45783bec-4675-4116-8829-f277afe063d7' \
  -H 'accept: application/json'
{
  "hasNext": false,
  "data": [
    {
      "subaccountId": "45783bec-4675-4116-8829-f277afe063d7",
      "tokenId": "ff761c8b-6248-4673-b63d-d1f980551959",
      "tokenAddress": "0xa1623E0AA40B142Cf755938b325321fB2c61Cf05",
      "tokenName": "USD",
      "amount": "35.644112906",
      "available": "12014.500177678",
      "totalUsed": "317.97964604",
      "updatedAt": 1743851518800
    }
  ]
}

Linked Signers

Subaccounts can be linked to specialized signers (known as "linked signers") to enhance the trading experience for users. These linked signers are client-generated private keys associated with your EOA (i.e. the msg.sender of the original depositor) that enable specific limited functions without requiring message signatures from your main wallet.

Purpose of Linked Signers?

Linked signers allow users to submit and cancel orders without needing to sign a message through your EOA. This allows the exchange application to enable one-click trading, an improved UX feature that does not require wallet providers to prompt on every exchange interaction.

If you are integrating directly with the API, linked signers do not provide any additional UX as presemubly your trading bot would already have access to private keys. It is largely in place to provide retail traders with an improved trading experienced through a UI.

However, it does provide an added layer of security if you choose to deposit funds with your primary account and delegate order submissions and cancelations to a linked signer.

To link a signer to your subaccount, first generate a secure private key using any popular cryptography library of your choice. Once you have your private key, create an EIP712 signature by signing a SigningKey message with your EOA wallet, including the necessary action details, derived signer address, subaccount ID, and expiration time.

Submit this information to our API endpoint with the required parameters, and upon successful verification, the system will establish the connection between your subaccount and the new signing key, enabling streamlined order management without repetitive wallet signatures.

curl -X 'POST' \
  'https://api.etherealtest.net/v1/linked-signer/link' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "signature": "string",
  "signerSignature": "string",
  "data": {
    "subaccountId": "<id_of_subaccount_linked_to>",
    "sender": "<address_of_subaccount_linked_to>",
    "subaccount": "<bytes32_subaccount_name_linked_to>",
    "signer": "<linked_signer_address>",
    "nonce": "<nonce_in_nanoseconds_as_string>",
    "signedAt": <timestamp_in_seconds>
  }
}'

Signers are restricted to a configurable number per specified time period (in days). This value is applied across all subaccounts. As of writing the cap enforces a maximum of 5 signers within a 7-day period.

You can view a subaccount's remaining linked signer quota by:

curl -X 'GET' \
  'https://api.etherealtest.net/v1/linked-signer/quota?subaccountId=45783bec-4675-4116-8829-f277afe063d7' \
  -H 'accept: application/json'
{
  "maxLinkedSignersPeriodDays": 7,
  "maxLinkedSignersInPeriod": 5,
  "linkedSignersUsedInPeriod": 1
}

Revoking Signers

You can unlink a previously linked signer through the revoke flow. Revoking is essential as a security feature for several reasons:

  1. If you suspect your device has been compromised or you've lost access then revoking allows you to immediately invalidate that signer.

  2. It's also useful for general opsec, rotating signers as part of regular security practices

Once revoked, a signer cannot be relinked, ensuring complete invalidation of the compromised credentials.

You can revoke a signer by calling:

curl -X 'DELETE' \
  'https://api.etherealtest.net/v1/linked-signer/revoke' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "signature": "string",
  "data": {
    "subaccountId": "<subaccount_of_linked>",
    "sender": "<subccount_address_of_linked>",
    "subaccount": "<bytes32_name_of_subaccount_linked>",
    "signer": "<address_of_signer_to_revoke>",
    "nonce": "<nonce_in_nanoseconds_as_string>",
    "signedAt": <timestamp_in_seconds>
  }
}'

All resting orders signed by this signer must be canceled before the signer can be revoked. Linked signers are settled and validated onchain so if an order is matched offchain but linked signer is revoked onchain, they cannot be matched.

Signer Expiry

Signers have a built-in expiration mechanism that automatically invalidates them after a period of inactivity. Currently, linked signers have a 2-week expiration period, after which they can no longer be used for order submissions or cancellations.

This expiration timer isn't static. After each subsequent order submission/cancelation, the exchange refreshes your signer's expiration window, essentially resetting the countdown. It's worth noting that this expiration enforcement happens at the offchain level through the trading API, which will reject requests from expired signers, rather than through on-chain verification. To completely clear out expired signers, it is recommended to revoke them.

Ethereal supports multiple linked signers. A subaccount can have many signers linked. This is often useful when users have many devices used to place orders.

Querying for Linked Signers

To query for a subaccount's linked signers:

curl -X 'GET' \
  'https://api.etherealtest.net/v1/linked-signer?subaccountId=45783bec-4675-4116-8829-f277afe063d7&active=true' \
  -H 'accept: application/json'
{
  "hasNext": false,
  "data": [
    {
      "id": "b406a408-0494-4e57-99e0-c4af28ff790c",
      "signer": "0x033Ec075B617D384688f51f0780a25C0d389A03F",
      "isActive": true,
      "blockNumber": "11206111",
      "linkedAt": 1743746279000,
      "expiresAt": 1744456485480,
      "createdAt": 1743746274425
    }
  ]
}

System Accounts

Account
Deposit
Trade
Withdraw

FeeCollector

✗

✗

✗

Liquidator

✓

✓

✗

Sequencer

✗

✗

✗

PreviousMessage SigningNextOrder Placement

Last updated 2 days ago

Page cover image