## Synopsis

The client needs to interact with the NOCUST smart-contract on the parent-chain and the operator in order to ensure security of his balance, make transactions, deposits, and withdraw funds from the commit-chain.

### Motivation

To ensure security of the balance and non-custody there are specific requirements that the client need to fulfill. In this document, we will describe the conditions needed to consider the commit-chain as safe. Further, we will describe the protocol to make off-chain transactions, deposits, withdrawals, and challenges.

### Definitions

• $A_i(e)$: The initial balance allotment reflected in the account interval tree of checkpoint $e$. We usually have $A_i^K(e) = \mathfrak{A}_i^K(e)\texttt{.accountProof.right} - \mathfrak{A}_i^K(e)\texttt{.accountProof.left}$
• $R^p_i(e)$: The amount received from transfers during the round
• $R^a_i(e)$: The amount received from swaps during the round
• $S_i(e)$: The amount spent by doing swaps or transfers during the round
• $\mathbb{D}_i(e)$: The amount deposited during the round
• $\mathbb{WR}_i(e)$: The amount requested for withdrawal during the round
• $\mathbb{WC}_i(e)$: The amount of withdrawal confirmed during the round
• $\mathbb{B}^K:$ Total parent-chain balance of the NOCUST smart-contract of asset token $K$

$R^p_i(e)$, $R^a_i(e)$, $S_i^K(e)$, $\mathbb{D}_i(e)$, $\mathbb{WR}_i(e)$, and $\mathbb{WC}_i(e)$ MUST be rested to 0 at the beginning of the round.

All variables can have an exponent indicating a specific asset token. For example, $A_i^K(e)$ is the initial balance allotment for asset $K$.

## Technical Specification

### Account Balance

We define the current balance or spendable balance of asset token $K$ on the commit-chain account $\mathbb{P}_i^K$ equal to: $balance(\mathbb{P}_i^K) = A_i^K(e) + R_i^K(e) - S_i^K(e) + \mathbb{D}_i^K(e) - \mathbb{W}_i^K(e)$ With $R_i(e) = R^p_i(e) + R^a_i(e)$

### New eon

As described in NSPEC003, the NOCUST system will periodically enter a new round. The NOCUST client MUST consider the new round for making transactions and swaps as soon as the block of the new round is published on the parent-chain. The client MUST set the value of the initial allotment for a new round to the balance of the previous round: $A_i^K(e+1) = balance(\mathbb{P}_i^K(e))$. The variables $R^p_i(e)$, $R^a_i(e)$, $S_i^K(e)$, $\mathbb{D}_i(e)$, $\mathbb{WR}_i(e)$, and $\mathbb{WC}_i(e)$ MUST be rested to 0 and the active and passive trees MUST be emptied.

### Ledger auditing

In NOCUST, users are required to audit their account on a regular basis:

• The owner of an account $\mathbb{P}_i^K$ MUST come online at least once every eon before the start of the 4th epoch to get his $\mathfrak{A}_i^K(e)$ proof of exclusive balance allotment from the operator and verify its validity.
• Given a valid $\mathfrak{A}_i^K(e)$, the user MUST complete the delivery verifications.
• If the operator does not cooperate to provide the proof $\mathfrak{A}_i^K(e)$, the user MUST open a state update challenge before the start of the 4th epoch. The user MUST come back online before the eon finishes to complete the delivery verifications using the $\mathfrak{A}_i^K(e)$ in the operator response of the state update challenge.
• $\mathfrak{A}_i^K(e)$ MUST be stored by the user until checkpoint $e+1$ is available on the parent-chain and $\mathfrak{A}_i^K(e+1)$ validity is confirmed and delivery verification is completed.

#### State update verification

In a NOCUST commit-chain you are required to verify the state transition between 2 consequent checkpoints. Given an account $\mathbb{P}_i^K(e)$ and its latest valid active state, the user have to verify the correct transition between $\mathbb{P}_i^K(e-1)$ and $\mathbb{P}_i^K(e)$ according to the transactions made during the round. A valid state update form $\mathbb{P}_i^K(e-1)$ to $\mathbb{P}_i^K(e)$ MUST meet the following requirements:

• There MUST be a valid proof of exclusive balance allotment $\mathfrak{A}_i^K(e)$ matching checkpoint $e$ (provided by the operator)

• If the user signed at least one active state during round $e-1$ (made an outgoing transfer or started a swap) we consider case A. We consider case B otherwise. We have: $A_i^K(e) = \mathfrak{A}_i^K(e)\texttt{.accountProof.right} - \mathfrak{A}_i^K(e)\texttt{.accountProof.left}$

• CASE A: We denote $\mathfrak{S}_i^K(e-1)$ the latest valid active state during round $e-1$. The following inequality MUST hold:

$A_i^K(e) \ge A_i^K(e-1) + \mathfrak{S}_i^K(e-1)\texttt{.gained}\ -\ \mathfrak{S}_i^K(e-1)\texttt{.spent}\ + \mathbb{D}_i^K(e) - \mathbb{WR}_i^K(e) + \mathfrak{A}_i^K(e)\texttt{.accountAggregate.passiveAggregate.passiveAmountReceived}$

• CASE B: The following inequality MUST hold: $A_i^K(e) \ge A_i^K(e-1) +\mathbb{D}_i^K(e) - \mathbb{WR}_i^K(e) + \mathfrak{A}_i^K(e)\texttt{.accountAggregate.passiveAggregate.passiveAmountReceived}$
• The NOCUST smart contract MUST have sufficient funds, formally: $\mathfrak{A}_i^K(e)\texttt{.accountProof.totalAllotement} \le \mathbb{B}^K - \sum^{\forall j\in \mathbb{P^K}} \mathbb{D}_j(e) - \sum^{\forall j\in \mathbb{P^K}} \mathbb{WR}_j(e)+ \sum^{\forall j\in \mathbb{P^K}} \mathbb{WC}_j(e)$ Note that withdrawal requests, withdrawal confirmations and deposits for all users are available on the parent chain.

If any of the previous requirements doesn't hold, the user MUST initiate a state update challenge.

#### Delivery verifications

Additionally to the state update verification, the user MUST ensure delivery of his transactions. A delivery verification is required for each transaction. The delivery verifications MUST be done after the State Update Verification.

##### Transfer delivery verification

For all incoming transfers of a given eon the user MUST verify that the transfers where delivered. Meaning that the account was credited as expected and that the transfer is included in the passive tree. From the transfer sub-protocol the sender had to provide, for each transfer: $\mathfrak{S}_i^K$, $\mathfrak{T}_{A,B}^K(e)$, and $\lambda_P(\mathfrak{T}_{A,B}^K \in\mathbb{P}_A^K)$.

For each incoming transfer we MUST have a valid $\lambda_P(\mathfrak{T}_{A,B}^K \in\mathbb{P}_A^K)$

Additionally, we MUST verify the following for

• We MUST have $\lambda_P(\mathfrak{T}_{A,B}^K \in\mathbb{P}_A^K)\texttt{.deliveryProof.totalAllotement} \ge \mathfrak{A}_i^K(e)\texttt{accountAggregate.passiveAggregate.passiveAmountReceived}$
• We MUST have $\lambda_P(\mathfrak{T}_{A,B}^K \in\mathbb{P}_A^K)\texttt{.deliveryProof.root} == \mathfrak{A}_i^K(e)\texttt{.accountAggregate.passiveAgreggate.passiveTreeRoot}$

Therefore, $\mathbb{P}_j^K$ is expecting his account to have been credited by at least $\mathfrak{T}_{i,j}^K(e)\texttt{.amount}$. Formally, the following inequality MUST hold: $\mathfrak{A}_i^K(e)\texttt{.accountAggregate.passiveAggregate.passiveAmountReceived} \ge \sum^{\forall i} \mathfrak{T}_{i,j}^K(e)\texttt{.amount}$

If the inequality doesn't hold, the user MUST initiate a delivery challenge for the incoming transfer missing in the passive set $\mathfrak{A}_i^K(e)\texttt{.accountAggregate.passiveAggregate.passiveTreeRoot}$

TODO

### Sub-protocols

#### Registration protocol

A new user $A$ wishes to join the commit-chain for asset $K$. He is required to create an initial active state with the field nocustContractAddressChecksum set to the checksum of the commit-chain smart contract address, tokenContractAddressChecksum set to the checksum of the address of the asset token $K$, userAddressChecksum the address of user $A$, accountIndex must be set to 0, eonNumber to the current eon, and spent and gained to zero.

Then the user MUST produce signatures according to NSPEC004 over the checksum of the active state and post it to the operator registration endpoint according to the model:

interface operatorRegistrationEndpoint {
token: string            // Asset token address
authorization: string   // Registration signature
}


The signature is in the RSV form (See NSPEC004). The addresses are the 40 bytes addresses as hexadecimal string without 0x prefix.

#### Transfer protocol

Given an account $\mathbb{P}_A^K$ sending amount $M$ of an asset token $K$ and to recipient account $\mathbb{P}_B^K$.

In order to make a transfer the sender MUST make all of the following checks:

• $\mathbb{P}_A^K$ and $\mathbb{P}_B^K$ MUST belong to the same commit-chain.
• The commit-chain MUST not be in recovery.
• The sender MUST have sufficient balance, $balance(\mathbb{P}_A) \gt M$
• Account $A$ MUST be different from account $B$
• $\mathbb{P}_i$ must not have a pending/non-finalized swap
• The recipient $\mathbb{P}_A^K$ MUST be registered with the commit chain. To ensure that the recipient is registered the sender MUST verify at least one state update (Previous eon or current eon)

We describe the protocol for an account to authorize an outgoing transaction.

Transfer object

We need to construct $\mathfrak{T}_{A,B}^K(e)$. First, the sender needs to create a Transfer object as described in NSPEC005. The fields counterpartyAddressChecksum and amount are set according to the address of $\mathbb{P}_A$ and $M$ respectively. index is set to the number of the transfers/swaps made in the round. Meaning, 0 if it is the first transfer or swap, 1 for the second transfer or swap, etc.. This will later represent the leaf index in the active tree. transferTag is set as in NSPEC005. $\mathfrak{T}_{A,B}^K(e).\texttt{transferTag.offset}$ MUST be set to the max Uint256 value or $2^{256} - 1$.

nonce SHOULD be set to a random number chosen by the transaction sender. The transaction sender MAY set the nonce to a previously agreed value with the recipient for transaction authentication purposes. The nonce MUST be unique for the account in the eon.

If the current last element of the active tree set is not finalized, the user MUST first finalize this transfer. To finalize the transfer, the user needs to replace $2^{256} - 1$ in the passive Marker by its actual value provided by the operator. See transaction model for payment. for more information.

Once the last element in the active tree was finalized the new transfer created previously MUST be appended to the active tree of the sender account.

Active state

The sender MUST construct a new active state object $\mathfrak{S}_i^K$ with the account details and the new transfer created above. tokenContractAddressChecksum MUST be set to the address of the asset token $K$. activeTreeRoot MUST be set to the root of the active tree with all transfers since the beginning of the around and the newly created transfer above. The spent value must be incremented by $M$. The gain value MUST keep its previous value (If this is the first outgoing transfer in the eon and no swap was made, spent will be equal to $M$ and gain to zero).

Balance Marker

The sender MUST construct a balance marker $\mathfrak{M}_i^K(e)$ as specified in NSPEC005.

nocustContractAddressChecksum, tokenContractAddressChecksum, and userAddressChecksum are the same as in the active state of the account. eonNumber is set to the current eon number. balance is set to the balance after the transfer, calculated according to the balance formula .

Signatures

The sender MUST produce signatures according to NSPEC004.

The 2 following signatures MUST be produced with the private key of the account $\mathbb{P}_i$:

• $SIG_{i}(\mathfrak{S}_i^K)$ A signature over the checksum of $\mathfrak{S}_i^K$ the active state object created above.
• $SIG_{i}(\mathfrak{M}_i^K)$ A signature over the checksum of the BalanceMarker created above.

Sending the authorization to the operator

The sender of the transfer needs to send to the operator the signatures and the transfer details

Operator response

The operator must ratify the new active state including the new transfer by sending to the client his signature $SIG_{op}(\mathfrak{S}_i^K)$. The user MUST verify this signature to consider that the operator committed to the transfer.

Communicating the transfer to the recipient

To ensure that the operator delivers the transfer (recipient account is credited) in the upcoming checkpoint. The transaction sender MUST inform the recipient of the transaction and send him directly $SIG_{i}(\mathfrak{S}_i^K)$ , $SIG_{op}(\mathfrak{S}_i^K)$, $\mathfrak{S}_i^K$, $\mathfrak{T}_{A,B}^K(e)$, and $\lambda_P(\mathfrak{T}_{A,B}^K \in\mathbb{P}_A^K)$. These values will allow the recipient to challenge delivery of the transfer if needed in the future.

#### Swap protocol

For a new swap $\mathfrak{X}_i^{X,Y}(e)$. $\mathbb{P}_i(e)$ wishes to exchange amount $M$ of asset token $X$ for $N$ amount of asset token $Y$. We call $\mathbb{P}_i^X$ the debited account and $\mathbb{P}_i^Y$ the credited account.

In order to make such a swap the user MUST make all of the following checks:

• The commit-chain MUST not be in recovery.
• The debited wallet MUST have an exact balance of $M$
• Asset token $X$ and $Y$ MUST be different
• $\mathbb{P}_i^X$ and $\mathbb{P}_i^Y$ MUST not have a pending/non-finalized swap.
• $\mathbb{P}_i^X$ and $\mathbb{P}_i^Y$ MUST be registered with the commit chain.
• $\mathbb{P}_i^X$ and $\mathbb{P}_i^Y$ MUST belong to the same commit-chain.
• $\mathbb{P}_i^X$ and $\mathbb{P}_i^Y$ MUST have the same owner (same address).

We describe the protocol for an account to authorize a swap.

Swap object

We first need to construct $\mathfrak{X}_i^{X,Y}(e)$. sellTokenChecksum and buyTokenChecksum are set according to $X$ and $Y$ respectively. index is set to the leaf index of the credited account. sellAmount and buyAmount are set according to $M$ and $N$ respectively. startingBalance is set to $A_i^X(e)$. nonce is set to a random number.

Active states

We need to prepare 2 active states, $\mathfrak{S}_i^X$ and $\mathfrak{S}_i^Y$. The swap object MUST be appended to the active trees of both active states, the activeTreeRoot MUST be set accordingly for each. $\mathfrak{S}_i^X\texttt{.spent}$ is incremented by $M$ ($\mathfrak{S}_i^Y\texttt{.gained}$ is kept unchanged).

Balance markers

The user MUST construct 2 balance markers $\mathfrak{M}_i^X(e)$ and $\mathfrak{M}_i^Y(e)$. one for each active state $\mathfrak{S}_i^X$ and $\mathfrak{S}_i^Y$.

nocustContractAddressChecksum, tokenContractAddressChecksum, and userAddressChecksum are the same as in their respective active states. eonNumber is set to the current eon number. The balance field of $\mathfrak{M}_i^X(e)$ is set to the current balance after the swap calculated according to the balance formula. For $\mathfrak{M}_i^Y(e)$ the balance field MUST be set to 0.

Signatures

The sender MUST produce signatures according to NSPEC004.

The 4 following signature MUST be produced with the private key of the account $\mathbb{P}_i$:

• $SIG_{i}(\mathfrak{S}_i^X)$
• $SIG_{i}(\mathfrak{S}_i^Y)$
• $SIG_{i}(\mathfrak{M}_i^X)$
• $SIG_{i}(\mathfrak{M}_i^Y)$

Send the authorizations to the operator

The sender of the swap needs to send to the operator the signatures and the swap details

Operator response

The operator must ratify the new active states including the new swap by sending to the client his signatures $SIG_{op}(\mathfrak{S}_i^X)$ and $SIG_{op}(\mathfrak{S}_i^Y)$. The user MUST verify the signatures to consider that the operator committed to the swap. The user account is now blocked, the user MUST not make any outgoing transfer or additional swaps before the pending swap get finalized.

Swap finalization

To unblock the account and spend freely the amount gained in the credited wallet the user need to finalize the swap. To complete the finalization the user and the operator need to produce and sign new active states for the credited and debited wallet. In this new active state we need updated spent and gained values that reflect the result of the matching of the swap.

The user and the operator must come to an agreement on what should be spent and gained in the final active states. The user must make sure that he is getting a fair price. For the final active states $\mathfrak{S}_i^X$ (debited) and $\mathfrak{S}_i^Y$ (credited) the user MUST ensure that: $M(\mathfrak{S}_i^Y\texttt{.gained} - \mathfrak{S}_i^Y\texttt{.spent})\ge N(\mathfrak{S}_i^X\texttt{.spent} - \mathfrak{S}_i^X\texttt{.gained})$

In the final active state the startingBalance field of the swap MUST be set to $2^{256} - 1$. The 2 active states MUST be signed by both party and the signatures MUST be shared with each-other.

Note that the user MAY or MAY NOT finalize a swap. If the swap is not finalized during an eon the operator can still match the swap without the user approval. In this case, the swap delivery challenge will ensure that the user get a fair price for the swap.

#### Deposit protocol

For depositing funds to the NOCUST commit-chain the user is required to call the deposit function on the NOCUST smart-contract. The contract requires 3 parameters. The token parameter is the contract address of the asset token to deposit. If the user wishes to deposit the parent-chain native asset token, the token must be set to the NOCUST smart-contract address. The beneficiary is the address of the account to credit, and amount is the amount of the asset token to deposit. The amount field MUST be equal to the amount of funds send together with the deposit call. Note that some asset token standard might require transfers from third party contracts to be authorized (For Ethereum see the approve function).

The NOCUST operator will credit the commit-chain account after some period of time according to the BLOCK_CONFIRMATION variable.

#### Withdrawal protocol

The process of sending funds from the commit-chain back to the parent-chain is a 2 step process separated by a period of a complete eon. The withdrawal is first requested and after a full eon has passed it can be confirmed.

##### Withdrawal request

To initiate the withdrawal the user needs to call the function requestWithdrawal. The function require to pass the token to withdraw, the withdrawalAmount and the proof of exclusive balance allotment of the account for round $e-1$. The sender of the request MUST be the withdrawing account.

We have the following condition on the balance:

• The amount to withdraw MUST be inferior to the initial allotment in the previous checkpoint:

$\texttt{withdrawalAmount} \le A_i(e-2)$

• The amount to withdraw MUST be inferior the current balance or the withdrawal will be subject slashing.

Note that the full balance is not always available to withdraw. Only the balance that was included in a checkpoint that went through a full round. Therefore, it is required to wait to withdraw freshly received funds.

After the withdrawal request transaction is confirmed on the parent-chain, we increment $\mathbb{WR}_i^K(e)$

##### Withdrawal confirmation

After some period time, the withdrawal can be confirmed and the funds will be transferred from the NOCUST smart-contract to the the address on the parent-chain. A withdrawal initiated during eon $e$ can only be confirmed in eon $e+2$. It is required to call the function confirmWithdrawal with the token and recipient parameter.

The confirmWithdrawal will confirm all the pending withdrawals.

After the withdrawal confirmation transaction is confirmed on the parent-chain, we increment $\mathbb{WC}_i^K(e)$

## Example Implementation

NOCUST client library: https://github.com/liquidity-network/nocust-client-library

## History

14.10.2019 - Added deposit and withdrawal 30.10.2019 - Added new eons