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:

Limit order with fees

Declares intent to buy or 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.

Transfer with fees

Requests collateral to be transferred from one vault to another.

Conditional transfer with fees

Requests collateral to be transferred from one vault to another if some on-chain event is recorded.

Multi-asset order

Consists of multiple orders and their fulfillment information. Each order can come from a different party. All orders must be completely fulfilled. Partial fulfillment is not supported.

Neither the Deposit nor the Withdrawal transactions require a signature, so they are not mentioned here.

Limit order with fees

Message payload

{
   "type": 3 // (10 bits),
   "vault_sell": uint64,
   "vault_buy": uint64,
   "amount_sell": uint64,
   "amount_buy": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch/3600
   "fee_limit": uint64,
   "fee_vault_id": uint64,
   "fee_token": uint251,
   "token_sell": uint251,
   "token_buy": uint251,
}

Message hash chain format

Pedersen_hash(
   token_sell,
   token_buy,
   fee_token,
   packed_message_0,
   packed_message_1
)
Table 1. Construction of 224-bit packed_message_0
amount_sell amount_buy fee_limit nonce

64 bits

64 bits

64 bits

32 bits

Table 2. Construction of 251-bit packed_message_1
type fee_ vault_id vault_sell vault_buy expiration_timestamp 0 padding

10 bits

64 bits

64 bits

64 bits

32 bits

17 bits

Corresponding flow

Corresponding transaction and object in StarkEx API

Transfer with fees

Message payload

{
   "type": 4,
   "sender_vault_id": uint64,
   "receiver_vault_id": uint64,
   "amount": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch/3600
   "fee_limit": uint64,
   "fee_vault_id": uint64,
   "fee_token": uint251,
   "token": uint251,
   "receiver_public_key": uint251,
}

Message hash chain format

Pedersen_hash(
   token,
   fee_token,
   receiver_public_key,
   packed_message_0,
   packed_message_1
)
Table 3. Construction of 224-bit packed_message_0
sender_vault_id receiver_vault_id fee_vault_id nonce

64 bits

64 bits

64 bits

32 bits

Table 4. Construction of 251-bit packed_message_1
type amount fee_limit expiration_timestamp 0 padding

10 bits

64 bits

64 bits

32 bits

81 bits

Corresponding flow

Corresponding transaction in StarkEx API

Conditional transfer with fees

Message payload

{
   "type": 5,
   "sender_vault_id": uint64,
   "receiver_vault_id": uint64,
   "amount": uint64,
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch/3600
   "fee_limit": uint64,
   "fee_vault_id": uint64,
   "fee_token": uint251,
   "token": uint251,
   "receiver_public_key": uint251,
   "condition": uint251,
}

Message hash chain format

Pedersen_hash(
   token,
   fee_token,
   receiver_public_key,
   condition,
   packed_message_0,
   packed_message_1
)
Table 5. Construction of 224-bit packed_message_0
sender_vault_id receiver_vault_id fee_vault_id nonce

64 bits

64 bits

64 bits

32 bits

Table 6. Construction of 251-bit packed_message_1
type amount fee_limit expiration_timestamp 0 padding

10 bits

64 bits

64 bits

32 bits

81 bits

Corresponding flows

Corresponding transaction in StarkEx API

Multi-asset order

Message payload

{
   "type": 6, // 10 bits
   "public_key": uint251,
   "system_id": uint126, // Must be 0. This is a reserved field.
   "give": [
      (
         "asset_id": uint251,
         "vault_id": uint64,
         "amount": uint64,
      ), …
   ], // list of tuples, max length = 10
   "receive": [
      (
         "public_key": uint251,
         "asset_id": uint251,
         "vault_id": uint64,
         "amount": uint64,
      ), …
   ], // list of tuples, max length = 10.
   "conditions": List[integer (251 bits)], // list of integers, max length = 10
   "nonce": uint32,
   "expiration_timestamp": uint32, // hours_since_Unix_epoch/3600
}

Message hash chain format

Pedersen_hash(
      conditions,
      sorted(receive).public_keys and assets,
      sorted(give).assets,
      sorted(receive).vaults and amounts,
      sorted(give).vaults and amounts,
      packed_message
)
Table 7. Construction of 251-bit packed_message
type nonce expiration_timestamp len(give) len(receive) len(conditions) 0 padding

10 bits

32 bits

32 bits

8 bits

8 bits

8 bits

27 bits

Corresponding flow

Corresponding transaction in StarkEx API