4 Accepting Deposits

Each NXT address and public key combination are maintained forever in the blockchain (even in Ardor), however maintaining a completely empty account is less costly than maintaining an account with non zero balance.

Due to this we do not recommend using a throw away NXT address per deposit as creating these addresses is likely to become more expensive in the future due to higher fees.

Instead, we recommend creating at most one deposit address per user or even direct all deposits to the same address and maintain user identity using a message attached to the deposit transaction.

Deposits can be accepted using one of the following approaches:

1. Message Based Deposits - NXT deposits are sent to a single address, the user is identified by an attached message.

2. Address per User - NXT is deposited to a new deposit address for each user.

When using both methods, always use a strong passphrase for the deposit account and protect the deposit account with a public key before accepting deposits.

4.1 Message-Based Deposits

Each payment transaction in Nxt can have an attached message, either in plain text or encrypted. This allows you to identify the customer through a customer number or order number mentioned in the message.

Which identifier you will use in the message to connect the payment to a specific user account is up to you and won’t be discussed in this document.

To monitor your account for new incoming payments, the GetBlockchainTransactions API call is used with the parameter executedOnly=true (the executedOnly parameter filters out phased transactions which did not execute).

The API call takes the following parameters:

account - deposit account id

timestamp - if specified, transactions should be newer than this block timestamp

type - the type of transaction. For payments this should be 0

subtype - the transaction subtype. For payments this should be 0 as well

firstIndex - for pagination purposes

lastIndex - for pagination purposes

executedOnly - set to true to filter out phased transactions which did not execute

To monitor a specific account for payment transactions use the following URL:

Loop over this array of transactions and process the transactions one by one. Note that this response includes both incoming and outgoing payment transactions. You should filter out your own (outgoing) payments by looking at the senderRS account address.

timestamp - the time the transaction was made, in seconds since the genesis block

blockTimestamp - the time of the block since the genesis block

confirmations - number of confirmations received for the block in which the transaction is included

For most transactions, waiting for 10 confirmations should be enough. However, for transactions with large amount, special attention should be given to the transaction timestamp and deadline parameters, since blocks can become orphaned and transactions cancelled as a result in case their deadline has passed.

When genesis time + timestamp + deadline * 60 is bigger than transaction.blockTime + 23 hours, a transaction can be accepted when the confirmations count reaches 10.

For phased transactions, check the block in which the transaction has executed not the block in which it was initially submitted.

If genesis time + transaction.timestamp + transaction.deadline * 60 is smaller than transaction.blockTimestamp + 23 hours, you should wait until the transaction has 720 confirmations before crediting the user’s account. 720 blocks is the maximum depth a blockchain reorganization can go. By waiting that long, you ensure the transaction is always included. Transactions that only required 10 confirmations will be put back in the blockchain automatically due to their longer deadline time.

The default deadline in the client is 24 hours, which means that in 99% of the cases only 10 confirmations will be necessary before crediting the user’s account.

Genesis time for the NXT blockchain is 24th of Nov, 2013 12:00:00 UTC.

To identify the user, you must look at the transaction attachment. If a plain text message is included, attachment.message is set and attachment.messageIsText is set to “true” (as string).

If an encrypted message was attached instead, attachment.encryptedMessage should exist instead. This is not just a string, but an object and contains two keys; data and nonce.

On your site’s deposit page, you will need to show the account address extracted from the accountRS field i.e. NXT-5WUN-YL5V-K29F-F43EJ.

If the account hasn’t yet had any incoming transactions, you will also need to display the publicKey to the user.

The public key doesn’t have to be displayed any more after it has had it’s first incoming transaction.

When a user sends funds to a new account, it needs to add the public key, so that an announcement of this key can be made. Once done, this is no longer needed.

Accounts without a public are only protected by the 64 bit account address not by the 256 public key.

Tracking New Account-Based Deposits

To track new deposits, it’s easiest to simply inspect all transactions in a block to see if any of them are to account addresses you generated. An alternative method would be to use the getBlockchainTransactions API detailed in message-based deposits.

(This is to be done in a loop)

Use the getBlockchainStatus API to check if there is a new block. This API call has no parameters.

The response includes lastBlock (block id) and numberOfBlocks (the height).

If numberOfBlocks is different from the previous execution of this API request, one or more new blocks have been generated. The transactions from the block which now has 10 confirmations have to be fetched. You should save in your database the height of the last block you processed.

Use the getBlock API to get the block at the height of 10 blocks ago (10 confirmations).

Pass it the numberOfBlocks parameter from the getBlockchainStatus API response after subtracting 11 from this value, since blocks start at height 0

height - height of the block, zero-based.

includeTransactions - set to true to return the array of transactions included in the block

includeExecutedPhased - set to true to return the array of phased transactions which were executed in this block

Note the "executedPhasedTransactions" array which includes the now executed "transaction":"5821164293445600529" as well as the "transactions" array which includes the non-phased "transaction":"1510166370135252701"

Loop over the "transactions" array (filter out "phased":true transactions) and the "executedPhasedTransactions" array (do not filter "phased":true transactions)

For each transaction, see if the recipientRS field corresponds to one of the deposit accounts you generated for your users. If so, this is an incoming payment. Credit the user’s internal balance and send the money to your hot wallet.

Similarly to message based deposits, special attention should be given to the transaction timestamp and deadline parameters

After all transactions of this block have been checked, see if you’ve processed the previous block before or not (previousBlock).

If not, traverse through the previous blocks chain until you reach the last processed block.

5 Withdrawing / Sending Money

When a user wants to withdraw to a specific account, you ask him for the account id he wants to withdraw to. When you receive this account id, you must first check if that account has a public key attached to it or not (i.e. if it’s new or not).

When you get this error, you should also ask the user for his public key or at least display a warning explaining the risk of using an account without a public key.

When you have both the account id and public key, you can verify that they are correct by comparing the given account id with the account id generated by the public key using the getAccountID API call.

secretPhrase - account passphrase

publicKey - account public key

We want to calculate only by publicKey so our request looks like this:

deadline - deadline for the transaction in minutes. Should be set to the maximum value of 1440

recipientPublicKey - recipient public key as provided by the user, only needed if the user account has no public key yet (on first transaction)

At the moment (v1.9.2) the recipientPublicKey is optional, however not specifying it, puts the user's funds at risk. The recipientPublicKey is mandatory in case you like to attach an encrypted message to the withdrawal transaction of a new account.

If there’s an error, you may get a response such as this (other errors may apply):

{ "errorCode": 5, "errorDescription": "Unknown account" }

A correctly executed response should always contain the "transaction" field which represents the newly created transaction id.

5.1 Adding a Message To a (Payment) Transaction

You can add messages to any kind of transaction.

To do so, specify the below parameters in your request:

message - plain text message.

messageIsText - should be set to the string “true” if text.

messageToEncrypt - plain text message that should be encrypted.

messageToEncryptIsText - should be set to the string "true" if text.

In case you want to attach a plain text message, specify message and set messageIsText to “true”.

If you want to attach an encrypted message that can only be read by the recipient, specify messageToEncrypt and set messgaeToEncryptIsText to “true”.

Note that these are not mutually exclusive, you can add both a plain text and encrypted message in the same transaction.

Allowing the user to add a message on your withdrawal page is recommended, so that you can coordinate with other services who use a message-based deposit system.

5.2 Hot and Cold Wallets

You should not keep all of your user’s deposits in a single hot wallet. A hot wallet is a wallet for which the passphrase is stored somewhere on your server, so that you can send money from it.

Instead, you should have both a hot and cold wallet. The cold wallet should hold most of the coins and not be accessible from any of your servers. Ideally, you’d manually send from your cold wallet to your hot wallet when more coins are needed for day-to-day operations.

So the best thing to do is to have money sent to your cold wallet address, and then send out to your hot wallet manually when needed.

5.3 Additional information

5.3.1 Nxt Account Format

The Nxt account ID is stored internally as a 64 bit signed long variable. When used in APIs it is usually returned as both unsigned number represented as string and using alphanumeric Reed-Solomon representation starting with "NXT-" prefix.

For example: NXT-ER8M-SYV3-R7EK-EUF3L

In API request parameters and response JSon, you will find both representations, the numeric representation is typically displayed as account, sender, recipient. The alphanumeric representation is typically displayed as accountRS, senderRS, recipientRS (simply always add “RS”).
RS stands for Reed-Solomon. This form of address improves reliability by introducing redundancy that can detect and correct errors when entering and using Nxt account ID’s.

5.3.2 NXT and NQT Amounts

All NXT amounts should be converted to NQT format to be used in API calls.
NQT is the name given to 0.00000001 NXT (or 10^(-8) in mathematical shorthand). The NQT to NXT ratio is equivalent to the Satoshi to Bitcoin ratio.
Simply put, 1 NXT is 100000000 NQT, therefore to convert NXT to NQT, simply multiply by 100000000.

5.3.3 Asset and currency QNT amounts

Each NXT Asset and Currency (generally referred to as "Holding") has specific number of decimal positions to which this holding is divisible.
API requests and responses always expect the holding quantity to be specified as a whole number without decimal positions. We refer to this value as QNT.
For example, when transferring 12.34 units of holding XYZ which has 4 decimal positions, specify the QNT value as 123400.

5.3.4 Minimum Fee

All outgoing transactions require a fee of at least 1 NXT at the moment. In API calls, this must be represented as 100000000 NQT.

5.3.5 Dealing with Assets and Currencies

In addition to sending the main transactional token NXT between accounts, which is done using the sendMoney API (type:0, subType: 0) the NXT blockchain supports two additional types of holding types: assets and currencies.

An asset typically represent a share in an entity, for example the ARDR asset (id: 12422608354438203866) represents the future distribution of the ARDR token at the time of the Ardor mainnet launch.
Each asset is identified by the unique 64 bit transaction id of the asset issuance transaction, has a name, which is not necessarily unique, has specific number of shares, which can be deleted and perhaps also increased in the future. Asset quantities are divisible to between 0 to 8 decimal positions as specified by the asset issuance transaction. Use the getAsset API to retrieve the asset properties. Depositing and withdrawing assets is done using the transferAsset transaction, asset transfer transactions are identified by type=2 and subType=1.

A currency is a more general purpose token, identified uniquely using a currency code and also using the unique 64 bit transaction id of the asset issuance transaction.
For example currency NAUT has currency id 18154834130337484019.
Use the getCurrency API to retrieve the currency properties. Depositing and withdrawing currencies is done using the transferCurrency transaction, currency transfer transactions are identified by type=5 and subType=3.
When dealing with currencies, make sure the currency is issued, i.e. the blcokchain passed the issuance height of the currency and that it is not deleted.
See more information in the monetary system documentation https://bitbucket.org/JeanLucPicard/nxt/issues/205/monetary-system-documentation

Other considerations regarding deposit and withdrawal of asset shares and currency units, for example the treating of phased transactions and message attachments, should work the same way as NXT deposits and withdrawals.
Quantity and fee calculations for assets and currencies are explained above.