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.
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;
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.
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:
If you suspect your device has been compromised or you've lost access then revoking allows you to immediately invalidate that signer.
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
FeeCollector
✗
✗
✗
Liquidator
✓
✓
✗
Sequencer
✗
✗
✗
Last updated