Message encoding

When a user submits an order, the application prepares a message whose payload is the transaction request. Either the application or the wallet needs to sign the transaction request, in one of the following ways:

  • The wallet signs the transaction
    The application and wallet communicate with each other through messages containing the transaction using broadcast signing or raw signing:

    Broadcast signing

    The wallet receives the transaction payload from the application. This method is fully transparent to the user, as the wallet can present the transaction’s parameters to the user. When the user approves, the wallet constructs the hash and computes the signature. Multi-Party Computation (MPC) wallets can use StarkEx transaction-specific parameters in the policy engine in order to limit some operations, such as adding another signer when the amount exceeds a given threshold.

    Raw signing

    The application hashes the transaction. The wallet receives the hash of the transaction and signs it.

  • The application signs the transaction
    The application hashes and signs the transaction request.

Broadcast signing flow

The following sequence of events takes place, concluding with the StarkEx gateway receiving a signed, encoded message with the transaction request:

  1. A user submits a transaction request using the application.

  2. The application sends the transaction request to a wallet.

  3. The wallet runs a Pedersen hash function on the parameters in the transaction request.

  4. The wallet prompts the user to sign the request.

  5. The wallet signs the transaction and sends the resulting signature back to the application.

  6. The application sends an encoded message to the StarkEx gateway that includes the transaction request and the signature hash.

Raw signing flow

  1. A user submits a transaction request using the application.

  2. The application runs a Pedersen hash function on the parameters in the transaction request.

  3. The application sends the hash to a wallet.

  4. The wallet prompts the user to sign the request.

  5. The wallet signs the hash and sends the resulting signature back to the application.

  6. The application sends an encoded message to the StarkEx gateway that includes the transaction request and the signature hash.

Application signing flow

  1. A user submits a transaction request using the application.

  2. The application runs a Pedersen hash function on the parameters in the transaction request.

  3. The application signs the hash.

  4. The application sends an encoded message to the StarkEx gateway that includes the transaction request and the signature hash.

Supported order types

The following order types are currently supported:

WithdrawalToAddress

(StarkEx Perpetual v2.0)

Withdrawal to a specific L1 address. Requests collateral to move from the L2 state to L1.

Withdrawal

(StarkEx Perpetual v1.0)

Requests collateral to move from the L2 state to L1.

Limit order with fees

Declares intent to sell a certain amount of a certain asset in exchange for a different asset at a certain ratio. One of the assets must be the collateral.

Trade is a pairing of two matching limit orders with fees.

Liquidate is a trade between a user whose position can be liquidated---that is, it is below the maintenance margin---and another user with an existing limit order that can be used to liquidate the first user’s position.

Transfer

Transfer, requests collateral to be transferred from one vault to another.

ConditionalTransfer

Conditional transfer, requests collateral to be transferred from one vault to another if some on-chain event is recorded.

For information on using the corresponding APIs for these transaction types, see Transactions in the StarkEx Perpetual REST API reference.

Withdrawal to address` (StarkEx Perpetual v2.0)

Message payload

{
   "type": 7 (10 bits),
   "asset_id_collateral": uint251,
   "eth_address": uint251,
   "position_id": uint64,
   "amount": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch / 3600
}

Message hash chain format

Pedersen_hash(
   asset_id_collateral,
   eth_address,
   packed_message
)
Table 1. Construction of 251-bit packed_message
type position_id nonce amount expiration_timestamp 0 padding

10 bits

64 bits

32 bits

64 bits

32 bits

49 bits

Corresponding flow

Corresponding transaction in StarkEx API

Limit order with fees

Message payload

{
   "type": 3 // (10 bits),
   "is_buying_synthetic": uint64, // The number of bits is not a signed parameter.
   "asset_id_synthetic": uint251,
   "asset_id_collateral": uint251,
   "asset_id_fee": uint251,
   "amount_synthetic": uint64,
   "amount_collateral": uint64,
   "max_amount_fee": uint64,
   "position_id": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32 // hours_since_Unix_epoch / 3600
}

The number of bits for is_buying_synthetic is not a signed parameter of this payload. Although the default implementation is 64 bits, this is not a requirement.

Set parameters as follows:

  • If is_buying_synthetic == 1:

    asset_id_sell = asset_id_collateral
    asset_id_buy = asset_id_synthetic
    amount_sell = amount_collateral
    amount_buy = amount_synthetic

  • If is_buying_synthetic == 0:

    asset_id_sell = asset_id_synthetic
    asset_id_buy = asset_id_collateral
    amount_sell = amount_synthetic
    amount_buy = amount_collateral

Message hash chain format

Pedersen_hash(
   asset_id_sell,
   asset_id_buy,
   asset_id_fee,
   packed_message0,
   packed_message1
)
Table 2. Construction of 224-bit packed_message_0
amount_sell amount_buy max_amount_fee nonce

64 bits

64 bits

64 bits

32 bits

Table 3. Construction of 251-bit packed_message_1
type position_id position_id position_id expiration_timestamp 0 padding

10 bits

64 bits

64 bits

64 bits

32 bits

17 bits

postion_id should appear three times in this packed message, to keep the message length consistent with the generic message structure.

Corresponding flows

Transfer

Message payload

{
   "type": 4 (10 bits),
   "asset_id": uint251,
   "asset_id_fee": uint251,
   "receiver_public_key": uint251,
   "sender_position_id": uint64,
   "receiver_position_id": uint64,
   "src_fee_position_id": uint64,
   "amount": uint64,
   "max_amount_fee": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch / 3600
}

Message hash chain format

Pedersen_hash(
   asset_id,
   asset_id_fee,
   receiver_public_key,
   packed_message0,
   packed_message1
)
Table 4. Construction of 224-bit packed_message_0
sender_position_id receiver_position_id src_fee_position_id nonce

64 bits

64 bits

64 bits

32 bits

Table 5. Construction of 251-bit packed_message_1
type amount max_amount_fee expiration_timestamp 0 padding

10 bits

64 bits

64 bits

32 bits

81 bits

Corresponding flows

ConditionalTransfer

Message payload

{
   "type": 5 (10 bits),
   "asset_id": uint251,
   "asset_id_fee": uint251,
   "receiver_public_key": uint251,
   "condition": uint251,
   "sender_position_id": uint64,
   "receiver_position_id": uint64,
   "src_fee_position_id": uint64,
   "amount": uint64,
   "max_amount_fee": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch / 3600
}

Message hash chain format

Pedersen_hash(
   asset_id,
   asset_id_fee,
   receiver_public_key,
   condition,
   packed_message0,
   packed_message1
)
Table 6. Construction of 224-bit packed_message_0
sender_position_id receiver_position_id src_fee_position_id nonce

64 bits

64 bits

64 bits

32 bits

Table 7. Construction of 251-bit packed_message_1
type amount max_amount_fee expiration_timestamp 0 padding

10 bits

64 bits

64 bits

32 bits

81 bits

Corresponding flows

Withdrawal (StarkEx Perpetual v1.0 only)

Signature construction

\[ECDSA(H(w_1, w_5), k_{private})\]

Where:

ECDSA is the regular elliptic curve digital signature algorithm, \(H\) is the Pedersen hash function, and \(w_{1-n}\) are 252-bit words.

Parameters

\(k_{private}\)

The user’s private Stark key

\(w_1\)

The withdrawn assetId.

\(w_5\)

Defined as follows:

       +----+----------------+---------+---------+---------+------------+
#bits  | 10 |      64        |   32    |    32   |   32   |     49      |
       +----+----------------+---------+---------+---------+------------+
label    A         B             C          D        E          F

Where:

A

Order type: 6.

B

positionId from which the user wants to take funds.

C

nonce for the transaction.

D

quantizedAmount to be withdrawn.

E

expirationTimestamp, in hours since the Unix epoch. For example, for the order to expire 24 hours from the beginning of the current hour, set the timestamp to \(⌊\frac{t_{unix}}{3600}⌋+24\).

F

Padding of zeros.