Skip to main content

Nano contracts flow

Introduction

This article is the reference material for the creation and execution flow of a nano contract, to consult while developing a blueprint. This flow can be divided into three phases:

  • Validation
  • Method execution
  • Resolution

Validation

Every creation and execution of a nano contract results from a user submitting an NC (nano contract) transaction to Hathor Network. In other words, everything starts when a user submits an NC transaction to a full node. An NC transaction is a subtype of transaction that has three specific fields not present in other transactions:

  • nc_id
  • nc_method
  • nc_args

Hathor protocol then begins the validation phase of the transaction. First, the common validations applicable to all transactions are performed. If the transaction passes these validations, the specific validations for NC transactions are then conducted:

  • Validation of nc_id
  • Validation of nc_method
  • Validation of withdrawals

Validation of nc_id

Hathor protocol verifies whether nc_id identifies an existing blueprint on Hathor platform or a nano contract registered on chain. If it does not, the transaction is considered invalid and discarded. If nc_id identifies a blueprint, Hathor protocol understands that the user wants to create a new contract. Conversely, if nc_id identifies a nano contract registered on chain, Hathor protocol understands that the user wants to execute an existing contract.

Validation of nc_method

Hathor protocol verifies if nc_method identifies a valid public method to be executed. In the case where nc_id identifies a blueprint — that is, contract creation — nc_method must be initialize. For example, let’s take the case of the swap blueprint from our tutorial. To create a swap contract, a user must submit an NC transaction such that:

  • nc_id: identifier of the blueprint on Hathor platform.
  • nc_method: 'initialize'

In the case where nc_id identifies a nano contract (registered on chain), nc_method must be the name of an existing public method in the contract, different from initialize. For example, to execute the swap method in a contract created from the swap blueprint, a user must submit an NC transaction such that:

  • nc_id: id of the transaction that registered the contract creation.
  • nc_method: 'swap'

If it does not fit into either of these cases, the transaction is considered invalid and discarded. This will occur in the following cases:

  • nc_id points to a blueprint and nc_method is not initialize.
  • nc_id points to a nano contract and nc_method is initialize.
  • nc_id points to a nano contract and nc_method is not an existing public method in the contract other than initialize.

Validation of withdrawals

To validate withdrawals, Hathor protocol first translates the set of inputs and outputs into a set of NCAction (actions). An NCAction object is a tuple that contains:

  • type of the action, which can be DEPOSIT or WITHDRAWAL.
  • token_uid that identifies the token to which the deposit or withdrawal action refers.
  • amount that describes the quantity (amount) of tokens to be transferred to or from the contract's balance.

Hathor protocol then verifies if the contract has sufficient funds to perform all requested withdrawal actions. If the contract does not have enough funds to perform all withdrawals, the transaction is considered invalid and discarded. For example, suppose a nano contract with the following multi-token balance:

  • Token A: 100
  • Token B: 10
  • Token C: 50
  • Token D: 20

In this case, the following sets of actions will be considered valid (individually):

  • Alice wants to: deposit 10 tokens A; withdraw 10 tokens B; withdraw 10 tokens C.
  • Bob wants to: withdraw 10 tokens A; withdraw 10 tokens B; deposit 20 tokens E.
  • Charlie wants to: withdraw 20 tokens D; deposit 10 tokens E; deposit 10 tokens F.

And the following sets of actions will be considered invalid (individually):

  • Alice wants to: withdraw 120 tokens A; deposit 30 tokens F.
  • Bob wants to: withdraw 10 tokens A; withdraw 15 tokens B.
  • Charlie wants to: withdraw 10 tokens G.

Another case in which Hathor protocol will consider the request invalid is when a contract creation transaction contains a withdrawal request. Obviously, if a contract is being created now, its balance for any token will always be zero, and thus no withdrawal makes sense. Hathor protocol considers the transaction invalid and discards it. The following diagram shows a case in which this occurs:

Example of invalid NC transaction

(Invalid NC transaction: withdrawal with initialize)(\text{Invalid NC transaction: withdrawal with initialize})

Alice calls the initialize method to create a contract from a blueprint but requests a withdrawal of 10 tokens B, which does not make sense since a newly created contract will always have an initial balance of zero for any token.

Note that Hathor protocol does not invalidate an NC transaction due to deposits. For Hathor protocol, if the user has sufficient funds in their wallet to make the deposit, then the deposit request is valid. It will be up to the contract, during its method execution, to decide whether or not to authorize this deposit request.

Awaiting in the mempool

Once the NC transaction passes the common checks, and the specific validations for nc_id, nc_method, and withdrawals, it is considered valid and sent to the mempool to await the arrival of the next block. When the next block arrives, all transactions waiting in the mempool will be added to the blockchain. At this point, the public method for creating or executing the nano contract will be called.

Hathor protocol calls the method defined in the NC transaction, passing as arguments a Context object followed by all the arguments contained in nc_args, in the same order they appear. A Context object provides:

  • tx: the transaction ID that called the method.
  • address: the wallet address that called the method.
  • timestamp: the timestamp of the first block confirming the transaction.
  • actions: a dictionary where the keys are token_uid and the values are NCAction objects.

Note that the set of deposits and withdrawals the user wants to perform with the transaction is found in actions.

Method execution

The method call initialize denotes contract creation, while the call of any other public method denotes contract execution.

Contract creation

Every blueprint must have the initialize method. The initialize method typically performs the following activities:

  1. Verify that the set of received arguments is valid.
  2. Authorize or deny the creation of a new contract.
  3. Define the initial state of the attributes for this new contract.

For example, suppose Alice wants to create a new nano contract from a certain blueprint called "ABC":

  • She submits an NC transaction to Hathor Network that correctly describes the creation of this contract. This transaction has three deposits: 10 tokens A, 20 tokens B, and 30 tokens C, and no withdrawals.
  • Hathor protocol considered the transaction valid, and upon the arrival of the next block, called the initialize method of the blueprint for execution.
  • The initialize method confirmed that the received arguments are valid for the creation of a new contract.
  • initialize will use the arguments passed by Alice in nc_args and the Context to initialize the attributes of the new contract.
  • initialize executes to the end and returns nothing (None). This indicates to Hathor protocol that the contract creation was successful.

On the other hand, suppose Bob wants to create another nano contract using this same blueprint "ABC":

  • However, he submits an NC transaction to Hathor Network that does not correctly describe the creation of this contract. This transaction has no deposits (which is not what initialize expects) and no withdrawals.
  • Hathor protocol considered the transaction valid, and upon the arrival of the next block, called the initialize method of the blueprint for execution.
  • The initialize method was expecting exactly three deposits for tokens A, B, and C respectively (as Alice did). Since it did not receive exactly these three deposits, initialize raises an exception. This indicates to Hathor protocol that the contract creation failed.

Contract execution

Executing a contract denotes that the public method (other than initialize) typically performs the following activities:

  1. Verify that the set of received arguments is valid.
  2. Authorize or deny the execution of all deposits and withdrawals that the user wants to make.
  3. Update the contract's attributes.

For example, suppose Alice wants to execute a certain nano contract that was instantiated from the swap blueprint:

  • She submits an NC transaction to Hathor Network that correctly describes the call to the public method swap of this contract. This transaction has a deposit of 10 tokens A and a withdrawal of 20 tokens B.
  • Hathor protocol considers the transaction valid, and upon the arrival of the next block, calls the swap method for execution.
  • The swap method confirms that the received arguments are valid.
  • swap make the checks to verify if the request should be authorized.
  • swap updates the contract's attributes.
  • swap executes to the end and returns nothing (None). This indicates to Hathor protocol that the contract execution was successful, which means the set of all deposits and withdrawals of the NC transaction was authorized.

On the other hand, suppose Bob wants to execute the same contract, calling the same swap method:

  • He submits an NC transaction to Hathor Network that does not correctly describe the call to the public method swap. This transaction has a deposit of 100 tokens C and no withdrawal.
  • Hathor protocol considers the transaction valid, and upon the arrival of the next block, calls the swap method for execution.
  • The swap method was expecting exactly two actions, one for deposit and one for withdrawal. Since this did not occur, swap raises an exception. This indicates to the Hathor protocol that the contract execution failed, and thus, the requested deposit was not authorized.

Resolution

Hathor protocol receives the method's return and completes the processing of the NC transaction. There are two possible outcomes for the creation/execution of a contract:

  • Success
  • Fail

Success

If the public method runs to completion without raising an exception, Hathor protocol understands that the creation/execution was successful and will carry out the following activities:

  • In the case of contract creation, add it to the database (i.e., the ledger).
  • In the case of contract execution, update the attributes as modified by the method.
  • Perform all deposits and withdrawals contained in the NC transaction and update the contract's balance.
  • Add the NC transaction to the blockchain marked as "success".

Fail

If the execution of the public method raises an exception, Hathor protocol understands that the creation/execution has failed and will carry out the following activities:

  • In the case of contract creation, discard the created instance.
  • In the case of contract execution, discard any modifications made to attributes.
  • Do not perform any of the deposits and withdrawals contained in the NC transaction.
  • Add the NC transaction to the blockchain marked as "fail" and with its "inputs/outputs" voided.

What's next?