Integrating with an exchange

This document is intended to guide developers and system integrators through the integration of the DHP token into an Exchange platform. It contains recommendations on how to set up accounts, listen for deposits, and create withdrawals as well as code examples ready to be adopted.

The code examples shared use the dHealth SDK for TypeScript, but can be ported to other available SDKs since all of them share the same design principles. If there is no SDK supported for a required programming language, you may still be able to integrate with our network by connecting directly via dHealth's REST Gateway.


Integration overview

There are many ways to design an exchange. This guide is based on how to support DHP deposits and withdrawals in an exchange that follows a central wallet approach.

Please note that this design is not particularly recommended over others. However, its simplified architecture is a good showcase for dHealth's set of features involved in integrating with an Exchange. A different approach, for example, would be to use a different wallet for each user.

4147

Fig. 1: General design diagram of the central wallet approach.

Next, we will describe the main components of this architecture.

Components

Central wallet

The exchange owns a dHealth account where all the user's deposits and withdrawals occur. The keys to this account need to be on an online machine, so this is also commonly called the Hot wallet. This account only has the necessary amount of DHP for daily use (withdrawals and deposits), since it is the account most exposed to attacks.

Cold wallet

Cold wallet(s) hold a certain threshold for the pool of DHP. These accounts should be created and remain in a setup with no internet connection. Transactions issued from cold wallets must be signed offline and announced to the network using another device. It is advisable as well that cold wallets are set up with multi-signature accounts.

Unique User ID

In the proposed architecture, each user is identified by a Unique User Identifier (UUID) in the exchange's database. A user will deposit to the central wallet with their UUID attached as the message of the transaction (called sometimes the memo). The UUID is only shown in the user's dashboard during the deposit confirmation.

🚧

Drawbacks of this approach

One of the drawbacks of this design is that many users are not used to having a message attached to their transactions. If they forget to attach the UUID or attach a wrong UUID, it will lead to receiving lots of support tickets concerning "lost funds".

Therefore, we recommend that exchanges create QR-Codes that are pre-filled for users with the correct message and amount, sending funds to the exchange's central wallet. This solution is compatible with both our dHealth Wallet on desktop and our dHealth Mobile Wallet.

🚧

Caution: Message types

dHealth's Transfer transactions can hold an arbitrary message up to 1023 bytes long but the first byte is treated specially by the dHealth SDK to identify persistent harvesting delegation requests.

This can be a source of confusion because the receiver of a transaction does not know if the message was generated by the dHealth SDK or otherwise (for example accessing the REST Gateway), so it does not know if the first byte must be treated specially or not.

To avoid any such issues, the following measures must always be enforced:

  • Always start messages with the first byte in the 32 to 128 range (this is the standard ASCII printable range).
  • Always ignore any received initial byte outside the 32 to 128 range.

Follow these rules, regardless of whether you use the dHealth SDK or not to generate and parse transfer transactions.

Exchange Server

The exchange owns a machine that is constantly listening for user's withdrawal requests, and monitors the blockchain to detect user deposits into the Exchange Central Wallet. As explained in the rest of this document, this machine maintains the database updated and announces any required transaction.

Exchange Database

The exchange should keep a trace of individual user's balances in its own database, because all the user's funds are merged together in the Exchange's wallets. This database permits to keep track of the amount of tokens each individual user holds. It also records all processed transactions, for record-keeping and to avoid processing the same transaction(s) more than once.

Running a node

Although not absolutely necessary, it is recommended that Exchanges deploy their own dHealth node to communicate with the rest of the network. Since each node automatically connects to several other nodes on the network, this approach is more robust than accessing the network always through the same public node, which might become unavailable.

If you are unable to run your own node, you can choose one from the list provided by the Statistics Service.

See the different guides about deploying dHealth nodes and make sure you create an API node.

Accounts setup

Exchanges can create the central and cold wallets by downloading the official dHealth Desktop Wallet for Windows, Linux or Mac, or Using the command line interface.

Note that every wallet is assigned to an account (a deposit box that holds tokens that can only be transferred with the appropriate private key).

❗️

Caution: Private keys

The private key(s) must be kept secret at all times and must not be shared. Losing access to the private key means losing access to an account's funds.

Please, always make sure to securely back up private keys of exchange wallets.

❗️

Caution: Two-factor authentication

It is advisable to update exchanges' central and cold wallets into multi-signature accounts to enable protocol-ruled two-factor authentication.
The cosignatories of the multi-signature account then become the account managers, so no transaction can be announced from the multi-signature account without the cosignatories' approval.

dHealth's current implementation of multi-signature is “M-of-N” meaning that M out of the total N cosignatories of an account need to approve a transaction for it to be announced.

❗️

Caution: Complexity

Multi-signature accounts are a powerful, yet dangerous tool. If access to some cosignatory account is lost and the minimum approval is not reached (the M above), access to the multi-signature account can be permanently lost. Always configure multisig accounts with caution.

To strengthen security, extra account restrictions can be added to the Exchange's accounts, like blocking announcing or receiving transactions given a series of rules.

The DHP token

The native currency of the dHealth network is named DHP. The token is used to pay for transactions and service fees, which are used as well to provide an incentive for those participants who secure the network and run the infrastructure.

Tokens can be divided up to 6 decimal places. Amounts given without decimals are called absolute, whereas when decimals are used amounts are called relative. For example, when divisibility is 6, 1 relative unit corresponds to 1'000'000 absolute units, and the smallest token is 0.000001 relative units. The smallest absolute unit is always 1, regardless of the divisibility.

These are the properties of DHP:

PropertyValueDescription
ID39E0C49FA322A459 The unique token identifier.
Aliasdhealth.dhpA friendly name for the token.
Initial supply1'000'000'000 (relative)The initial amount of tokens in circulation.
Max. supply2'000'000'000 (relative)The maximum amount of token units in circulation after inflation is applied.
Divisibility6The number of decimal places allowed for this token.
This means that the smallest fraction of the token is 0.000001 (relative).
Duration0This token does not expire.
Supply mutableFalseThis token's initial supply cannot be altered.
TransferableTrueThis token can be transferred between arbitrary accounts.
RestrictableFalseThe token creator cannot restrict which accounts can transaction with this token.

.. caution::

🚧

Caution: Token identifiers

The DHP token can be referred to through its native token ID or its friendlier alias dhealth.dhp, which has an identifier on itself.

On MAINNET, these IDs are 39E0C49FA322A459 (token ID) and 9D8930CDBB417337 (alias ID).

Always treat these two IDs as equivalent.

Aggregates

dHealth has a novel feature called aggregate transactions which allows bundling multiple inner transactions into a single one.

Therefore, when monitoring incoming Transfer transactions you must remember to also look inside all Aggregate transactions (Both Aggregate Complete and Aggregate Bonded transactions). The example code given below shows a way of achieving this.

🚧

Caution: Monitoring aggregates

When Aggregate transactions are not monitored, inner transfer transactions cannot detected, leading to lots of reports of lost funds.

This is most critical for multi-signature accounts, for which transactions are always wrapped in an Aggregate transaction.

Avoiding rollbacks

This is a classic conflict in blockchain technology: On one hand, if transactions are accepted too quickly, they might need to be reverted later on, in the event of a network fork. On the other hand, waiting for too long is inconvenient for users.

There is a simple way of dealing with this in dHealth:

The procedure, which is common in blockchains, is to wait for a few blocks to be validated (added to the blockchain) before considering a transaction to be complete, or confirmed.

The amount of blocks to wait for, depends on the risk you are willing to accept. The recommendation for dHealth is 20 blocks (approximately 10 minutes, regardless of network conditions).

Note that waiting for a fixed amount of blocks leads to consistent confirmation times.

Deadlines

An added problem caused by blockchain rollbacks is that transactions might expire in the process of resolving a network fork. A bit of context is required here.

Transactions are not allowed to remain unconfirmed in the network forever, as this would pose a significant strain on the network's resources. Instead, all transactions have a deadline, and are automatically disposed of when the deadline arrives.

Users are free to use any deadline they want for their transactions, between now and 6h into the future (48h for aggregate-bonded transactions).

Transactions which are about to expire are delicate because, even if they get confirmed and are added to the blockchain, a rollback could send them back to the unconfirmed state and their deadline could expire before they are confirmed again.

Therefore, it is recommended that:

  • Incoming transactions with a deadline less than 1h into the future are rejected with a warning message, for example:

    Transaction is too close to expiration to be safely accepted.

  • Exchanges avoid using transactions with short lifespans.

  • Exchanges actively encourage their customers to avoid using transactions with short lifespans.

The example code

After the little of theory from above, let's look at an actual implementation source code. All snippets are based on the same program that can be found here.

A few notes on this example program:

  • It uses a fake DBService object that simulates the Exchange database. Calls to this object should obviously be replaced by the actual Exchange infrastructure in production code. For simplicity these calls are synchronous but they could be executed asynchronously too.

  • No error handling is performed at all. Use mechanisms like try {} catch where appropriate in production code.

  • Finally, besides the snippets shown in the guide, the complete program also contains auxiliary code (like polling loops) in order to make it runnable and self-sufficient. This auxiliary code is not meant to be used as an inspiration at all, it is just there for convenience.

❗️

Caution: Do not use in production!

Do not use this example source code in a production environment. Please, use this example software only to illustrate the integration of dHealth Network features.

Deposits

2941

Fig. 2: Deposit process.

Users perform deposits by announcing a regular transfer transaction using their wallet, moving the funds from their account directly to the Exchange Central Wallet. Since the transfer is handled entirely by the blockchain, the funds will be added to the Exchange Central Wallet without the Exchange's mediation, and this poses some problems:

  • The intended recipient of the transaction must be determined. This is done by attaching the user's UUID as the transaction's message.
  • The fact that a transaction has happened must be timely detected to update the user's account on the Exchange.

The code proposed next addresses all these issues by monitoring the blockchain.

Monitoring

The blockchain is polled periodically and all incoming transactions since last poll are processed in a batch:

  1. All Transfer transactions added to the blockchain since the last check and up to the latest confirmed block are examined, looking for the ones destined to the Central Exchange Wallet. This can be done efficiently with a single dHealth API.

    • Transfer transactions embedded in Aggregate Complete and Aggregate Bonded transactions must also be examined. This is handled in the example code by the embedded: true parameter in the
      Search confirmed transactions call.
  2. Filter out transactions that:

    a. Have no message or the message does not correspond to an existing UUID.

    b. Do not contain tokens, or the token is not dhealth.dhp.

    c. Have already been processed (as a security measure).

  3. The remaining transactions are then processed:

    a. The tokens are added to the user's account in the database.

    b. The transaction is marked as processed by adding its hash to the database.

  4. Store the last height that has been processed and wait for the next polling period.

The code snippet, using dHealth's TypeScript SDK is available here.

All configuration data is held in the ExchangeDHPConfig object including the parameters of the dHealth Network.

The above code snippet should be called in a loop every minute, for example, and it will process all new valid transactions that have waited enough blocks to be considered confirmed (e.g. 20 blocks).

However, transactions will not be reported immediately, and this might be annoying for users. Using Websocket channels, transactions can be monitored in real-time and a notification can be shown to the user as soon as a transaction is confirmed on the network (or even as soon as it is announced on the network).

These transactions, though, should be clearly marked as pending and not acted upon until verified by the above code, to avoid rollbacks](#avoiding-rollbacks).

Withdrawals

3196

Fig. 3: Withdrawal process.

Users send withdrawal requests to the Exchange Server, via a web page or mobile app, for example. If the database indicates that the user has enough funds to perform the withdrawal, a transfer transaction can be announced from the Exchange Central Wallet to the dHealth address indicated in the request.

Announcing the transaction has a fee, which is paid by the Exchange Central Wallet but can be deduced from the user's account. Regardless of the token being transferred, fees are always paid in DHP tokens.

Announcing

The code snippet, using dHealth's TypeScript SDK is available here.

The withdrawal transaction is just a regular dHealth transfer transaction. The code looks long because it contains a lot of repeated boilerplate, to make it self-contained:

  • Configuration is stored in the ExchangeDHPConfig object.
  • A number of repositories are instantiated via the RepositoryFactoryHttp class.
  • The withdrawal details are retrieved from environment variables in this example.

Then:

  1. The actual transaction is created using TransferTransaction.create.
  2. The transaction is signed.
  3. The signed transaction is announced using the TransactionService to simplify waiting for its confirmation.