Toolkit

REST API

The exchange uses the REST API of two services for interaction:

  1. Auth Service – required for user registration/authorization on the exchange

  2. Exchange Service – required for interacting with the exchange

Async API

Asynchronous exchange events are delivered using the Centrifugo service, which provides the following features on top of the standard WS protocol:

  • Message channels

  • JWT-based channel access rights

  • Epochs and state recovery in case of connection loss to the server

Snapshot updates

To maintain data consistency on the client, the "Initial snapshot with real-time updates" approach is used. First, the client subscribes to asynchronous state updates of an entity via the WS protocol, then it requests the initial state of the entity using the REST API, and finally, the entity state is merged into a final state using the latest updatedAt.

Crypto

To confirm the user’s intent when submitting orders to the exchange, a cryptographic signature is used based on the EIP-712: Ethereum typed structured data hashing and signing standard.

Each order must be accompanied by a signature field containing a signature of the order made with the user's crypto wallet. The exchange will reject any user order if:

  1. The signature is missing

  2. The signature format does not comply with EIP-712

  3. The signature was made with a wallet not belonging to the sender

  4. The data in the order differs from that used during signature creation

It is recommended to use the Ethers library and its Signer.signTypedData method, or any similar library that implements typed data signing according to the EIP-712 standard.

Schema description for generating a signature:

Important: Order data must not contain floating-point numbers when generating the signature. You must transform the data passed to the signTypedData method so that all floating-point values are converted to integers using the following formula: normalizeNumber = Round(floatValue * 10 ^ 8, HalfUp) This formula applies everywhere except for withdrawal requests from the trading balance, where rounding must always be done as Down.

Examples of order preparation and signing can be found here

Example of signature generation using GoLang libraries
import (
    "github.com/ethereum/go-ethereum/signer/core/apitypes"
    "github.com/ethereum/go-ethereum/crypto"
    "math/big"
)

domain := apitypes.TypedDataDomain{
    Name:              "MyDapp",
    Version:           "1",
    ChainId:           big.NewInt(1),
    VerifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
}

typedData := apitypes.TypedData{
    Types: apitypes.Types{
        "Mail": {
            {Name: "from", Type: "Person"},
            {Name: "to", Type: "Person"},
            {Name: "contents", Type: "string"},
        },
        "Person": {
            {Name: "name", Type: "string"},
            {Name: "wallet", Type: "address"},
        },
    },
    PrimaryType: "Mail",
    Domain:      domain,
    Message: map[string]interface{}{
        "from": map[string]interface{}{
            "name":   "Alice",
            "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
        },
        "to": map[string]interface{}{
            "name":   "Bob",
            "wallet": "0xaBbACaBaa0000000000000000000000000000000",
        },
        "contents": "Hello, Bob!",
    },
}

hash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
domainSeparator, _ := typedData.HashDomain()

finalHash := crypto.Keccak256(
    []byte("\x19\x01"),
    domainSeparator,
    hash,
)

privateKey, _ := crypto.HexToECDSA("your_private_key")
signature, _ := crypto.Sign(finalHash, privateKey)

Last updated