Skip to main content

Blueprint SDK — API

Introduction

This article is the reference for the Python API provided by the blueprint SDK. The blueprint SDK Python API comprises all names from package hathor.nanocontracts that can be imported in a blueprint module.

This API reference is divided into the following sections:

  • Type aliases: simplify handling of the most common data types in contracts.
  • Classes: define the structure required by Hathor engine for a blueprint module.
  • Decorators: used to define the type of a method in the blueprint class.
  • Objects: describe the interface of internal objects from the available classes. That is, you can use them through instances of available classes, but you cannot import and use their classes directly.
tip

Not all names from the hathor.nanocontracts package can be imported into a blueprint module. Only strictly allowed names may be imported. For the list of these names, see Imports at Blueprint development guidelines.

warning

This article refers to the following version of the Blueprint SDK: branch experimental/nano-testnet-v1.8.0 of hathor-core repository at GitHub.

Note that the Blueprint SDK is an experimental phase and evolving rapidly. Newer versions may include features not yet covered here. Moreover, backward compatibility is not guaranteed, and they may change the behavior described in this article.

warning

This article is in final review stage. While most of its content is accurate, some errors may still be present.

Type aliases

Source code: type aliases in hathor.nanocontracts.types

Address

  • Description: wallet address
  • Alias for: bytes
  • Constraint: 20 bytes
  • Example: b'\x28\x1e\xd3\x2c\xcd\x0d\x28\xac\xea\x3a\xfc\xf4\x79\x8e\x2d\x4d\xb2\x14\x01\xed\xef\xa9\xa8\x98\x22'
  • Usage:
    from hathor.nanocontracts.types import Address
    ...
    address: Address
    ...
    # In base58check this wallet address is: H9L7do74fkLF7VHa662a4huGni1zKW4EGZ
    address = b'\x28\x1e\xd3\x2c\xcd\x0d\x28\xac\xea\x3a\xfc\xf4\x79\x8e\x2d\x4d\xb2\x14\x01\xed\xef\xa9\xa8\x98\x22'

Amount

  • Description: denotes an amount of tokens
  • Alias for: int
  • Constraint: integer where the last two digits are decimals
  • Example: 1025 represents 10.25 tokens
  • Usage:
    from hathor.nanocontracts.types import Amount
    ...
    amount: Amount
    ...
    amount = 1025

BlueprintId

  • Description: identifier of a blueprint. For built-in blueprints, ids are hardcode with the network's environment variables (testnet, mainnet, etc.). For on-chain blueprints, the id is the hash of the transaction that deployed it.
  • Alias for: VextexId
  • Constraint: 32 bytes
  • Example: bytes.fromhex("3cb032600bdf7db784800e4ea911b10676fa2f67591f82bb62628c234e771595")
  • Usage:
    from hathor.nanocontracts.types import BlueprintId
    ...
    blueprint: BlueprintId
    ...
    blueprint = bytes.fromhex("3cb032600bdf7db784800e4ea911b10676fa2f67591f82bb62628c234e771595")

ContractId

  • Description: identifier of a contract. It is recorded in the transaction where it was created.
  • Alias for: VextexId
  • Constraint: 32 bytes
  • Example: bytes.fromhex("000063f99b133c7630bc9d0117919f5b8726155412ad063dbbd618bdc7f85d7a")
  • Usage:
    from hathor.nanocontracts.types import ContractId
    ...
    contract: ContractId
    ...
    contract = bytes.fromhex("000063f99b133c7630bc9d0117919f5b8726155412ad063dbbd618bdc7f85d7a")

Timestamp

  • Description: timestamp following Unix epoch standard
  • Alias for: int
  • Constraint: integer representing the number of seconds elapsed since January 1st, 1970 00:00:00 UTC.
  • Example: timestamp for January 3, 2020, at noon UTC is 1578052800
  • Usage:
    from hathor.nanocontracts.types import Timestamp
    ...
    timestamp: Timestamp
    ...
    timestamp = 1578052800

TokenUid

  • Description: identifier of a contract. It is recorded in the transaction where it was created.
  • Alias for: bytes
  • Constraint: 32 bytes
  • Example: bytes.fromhex("00000943573723a28e3dd980c10e08419d0e00bc647a95f4ca9671ebea7d5669")
  • Usage:
    from hathor.nanocontracts.types import TokenUid
    ...
    token: TokenUid
    ...
    token = bytes.fromhex("00000943573723a28e3dd980c10e08419d0e00bc647a95f4ca9671ebea7d5669")

TxOutputScript

  • Description: lock script of a transaction output
  • Alias for: bytes
  • Constraint: 32 bytes
  • Usage:
    from hathor.nanocontracts.types import TxOutputScript
    ...
    oracle: TxOutputScript

VertexId

  • Description: identifier of a transaction in the ledger (blockchain). It is the hash of the transaction.
  • Alias for: bytes
  • Constraint: 32 bytes
  • Example: bytes.fromhex("00000943573723a28e3dd980c10e08419d0e00bc647a95f4ca9671ebea7d5669")
  • Usage:
    from hathor.nanocontracts.types import VertexId
    ...
    tx: VertexId
    ...
    tx = bytes.fromhex("00000943573723a28e3dd980c10e08419d0e00bc647a95f4ca9671ebea7d5669")

NCAction

  • Description: union type alias representing any of the four possible action types. Use for type annotations when a parameter, variable, or attribute can accept any action type.
  • Alias for: one of the possible action classes: NCDepositAction, NCWithdrawalAction, NCGrantAuthorityAction, or NCAcquireAuthorityAction.
  • Constraint: must be an instance of one of the classes above.
  • Usage:
    from hathor.nanocontracts.types import NCAction
    ...
    actions: list[NCAction] = []
    ...
    def fail_if_invalid_action(self, action: NCAction) -> None:
    if action.token_uid != VALID_TOKEN:
    ...
  • Source code: hathor.nanocontracts.types.NCAction

Classes

Blueprint

Serves as the base class for all blueprints. You must subclass Blueprint exactly once in your blueprint module.

Usage:

from hathor.nanocontracts.types import Blueprint
...
# Define your blueprint class as subclass of Blueprint:
class Bet(Blueprint):
...

Objects:

Blueprint provides contracts the following objects:

  • syscall: instance attribute used for all external interactions outside the contract itself — e.g., reading and writing to the ledger, calling other contracts, etc. See Blueprint.syscall at section Objects.
  • log: instance attribute used to record contract execution logs. Useful during development for debugging and testing, and in production for audits. See Blueprint.log at section Objects.

Source code:
hathor.nanocontracts.blueprint.Blueprint

Context

Provides the public method with the context in which it was called — namely, who called it, when it was called, and what the origin transaction is. The origin transaction is the transaction that originated the current call chain; in other words, it contains the entry point call.

When Hathor engine invokes a public method, it always passes a Context object as the first argument. Therefore, every public method must have a Context object as its second parameter.

The Context object is immutable, and what is passed is only a copy of the original maintained by Hathor engine. As such, you cannot, and should not attempt to, modify the call context in your blueprint's code.

Data attributes:

  • vertex: VertexData that contains the origin transaction.
  • address: Address or ContractId that denotes who called the method (also known as the caller).
  • timestamp: Timestamp that denotes the timestamp of the first block confirming the origin transaction.
  • actions: MappingProxyType where the keys are TokenUid and the values are tuples of NCAction objects. All actions requested in the current call. It may contain zero, one, or more elements.
tip

Note that a token is associated with a tuple of actions. However, not all combinations of actions are possible for the same token. For example, Hathor engine will never pass to a public method a Context.actions in which, for the same token UID (TokenUid), there are:

  • Two actions (NCAction) of the same type (NCActionType) — e.g., two deposits for the same token.
  • One DEPOSIT action and one WITHDRAWAL action.
  • One GRANT_AUTHORITY action and one ACQUIRE_AUTHORITY action.

Method:

  • get_single_action

The following subsection describes the (only) method of this class that available to use in your blueprint.

Context.get_single_action

Given a token UID, returns the single NCAction from actions that should be associated with it — i.e., the action whose key matches the token. Otherwise, raises an exception.

get_single_action(self, token_uid: TokenUid) -> NCAction:

Parameter:

  • token_uid: TokenUid that identifies the single action.

Return: NCAction if there is one and only one action associated with the token UID. If no action is found, raises an NCFail exception. If more than one action is found, also raises an NCFail exception.

Usage:

from hathor.nanocontracts.context import Context
...
# Second parameter of a public method is always a Context object:
@public(allow_deposit=True, allow_withdrawal=True)
def swap(self, ctx: Context) -> None:
"""Execute a token swap."""

# Check if there is exactly one action related to each token:
# You should use the method get_single_action for it:
action_a = ctx.get_single_action(self.token_a)
action_b = ctx.get_single_action(self.token_b)
...

Source code:
hathor.nanocontracts.context.Context

NCActionType

An enumeration (Enum) that defines the possible types of actions a contract user (wallet or another contract) can perform on a contract's multi-token balance. Can be one of the following:

  • DEPOSIT: deposit tokens into contract.
  • WITHDRAWAL: withdrawal tokens from contract.
  • GRANT_AUTHORITY: grant mint/melt authority to contract.
  • ACQUIRE_AUTHORITY: acquire mint/melt authority from contract.

For more about it, see Actions section at Nano contracts: how it works.

Usage:

from hathor.nanocontracts.types import NCActionType
...
# Checking the type of a given action
# You can use:
if not isinstance(action, NCDepositAction)
raise InvalidActions

# OR with NCActionType the equivalent:
if action.type != NCActionType.DEPOSIT:
raise InvalidActions

# Defining what actions a public method shall receive:
# You can use in the decorator:
@public(allow_deposit=True, allow_withdrawal=True)

# OR with NCActionType the equivalent:
@public(allow_actions=[NCActionType.DEPOSIT, NCActionType.WITHDRAWAL])

Source code:
hathor.nanocontracts.types.NCActionType

NCDepositAction

Used to create or validate actions of type DEPOSIT.

Data attributes:

  • name: always "DEPOSIT"
  • type: always NCActionType.DEPOSIT
  • token_uid: TokenUid that denotes the token the caller wants to deposit.
  • amount: Amount that denotes the amount of tokens to be deposited.

Usage:

from hathor.nanocontracts.types import NCDepositAction
...

# Use it whenever you want to represent the specific deposit action:
# For example, to check if a given action is a deposit:
if not isinstance(action, NCDepositAction)
...

Source code:
hathor.nanocontracts.types.NCDepositAction

NCWithdrawalAction

Used to create or validate actions of type WITHDRAWAL.

Data attributes:

  • name: always "WITHDRAWAL"
  • type: always NCActionType.WITHDRAWAL
  • token_uid: TokenUid that denotes the token the caller wants to withdraw.
  • amount: Amount that denotes the amount of tokens to be withdrawn.

Usage:

from hathor.nanocontracts.types import NCWithdrawalAction
...
# Use it whenever you want to represent the specific withdrawal action:
# For example, to check if a given action is a withdrawal:
if not isinstance(action, NCWithdrawalAction)
...

Source code:
hathor.nanocontracts.types.NCWithdrawalAction

NCGrantAuthorityAction

Used to create or validate actions of type GRANT_AUTHORITY.

Data attributes:

  • name: always "GRANT_AUTHORITY".
  • type: always NCActionType.GRANT_AUTHORITY.
  • token_uid: TokenUid that denotes the token the caller wants to grant authority to contract.
  • mint: bool; if True, contract will be allowed to issue new amounts of the token, increasing its total supply.
  • melt: bool; if True, contract will be allowed to destroy amounts of the token, decreasing its total supply.

Usage:

from hathor.nanocontracts.types import NCGrantAuthorityAction
...
# Use it whenever you want to represent the specific grant authority action:
# For example, to check if a given action is a grant authority:
if not isinstance(action, NCGrantAuthorityAction)
...

Source code:
hathor.nanocontracts.types.NCGrantAuthorityAction

NCAcquireAuthorityAction

Used to create or validate actions of type ACQUIRE_AUTHORITY.

Data attributes:

  • name: always "ACQUIRE_AUTHORITY".
  • type: always NCActionType.ACQUIRE_AUTHORITY.
  • token_uid: TokenUid that denotes the token the caller wants to grant authority to contract.
  • mint: bool; if True, caller will be allowed to issue new amounts of the token, increasing its total supply.
  • melt: bool; if True, caller will be allowed to destroy amounts of the token, decreasing its total supply.

Usage:

from hathor.nanocontracts.types import NCAcquireAuthorityAction
...
# Use it whenever you want to represent the specific acquire authority action:
# For example, to check if a given action is an acquire authority:
if not isinstance(action, NCAcquireAuthorityAction)
...

Source code:
hathor.nanocontracts.types.NCAcquireAuthorityAction

NCFail

An NCFail exception signals to Hathor engine that a contract's creation or execution has failed. Use it in your blueprint's methods to indicate execution failures. Also, define subclasses of NCFail to provide more specific and clearer failure reasons for contract users (wallets and other contracts).

Usage:

from hathor.nanocontracts.types import NCFail
...
# Raise a generic NCFail exception.
if len(ctx.actions) != 0:
raise NCFail('must be a single call')
...
# Define specific exception classes.
class WithdrawalNotAllowed(NCFail):
pass
...
# Raise a specific exception.
if action.type != NCActionType.DEPOSIT:
raise WithdrawalNotAllowed('must be deposit')
...

Source code:
hathor.nanocontracts.exception.NCFail

SignedData

Out-of-the-box support for oracles in blueprints. To achieve this, the blueprint should have a public method exclusively for oracle use, which receives a SignedData as a parameter.

Data attributes:

  • data: off-chain data that the oracle wants to feed into the contract. The type of data is defined in the SignedData parameter received by the oracle's public method referred to.
  • script_input: bytes denoting the script used to authenticate the oracle.

Examples:

Suppose a sports betting contract in which an oracle should submit the result of a game after it has ended. In this scenario, SignedData[str] specifies that the result in data must be passed as a string. For example:

  data: "Barcelona2x1Real-Madrid"
script_input: <unlock_script_to_auth_oracle_as_bytes>

Now, suppose an oracle needs to submit the exchange rate of 1 BTC in US dollars (USD) every minute. In this scenario, SignedData[int] specifies that the result in data must be passed as an integer, with the last two digits representing cents. For example:

  data: 9654292
script_input: <unlock_script_to_auth_oracle_as_bytes>

Methods:

  • checksig
  • get_data_bytes

The following subsections describe each of these methods.

SignedData.checksig

Called in the oracle's public method to authenticate the oracle. That is, checks if this object's script_input attribute resolves the oracle script registered in the contract state.

checksig(script: bytes) -> bool:

Parameter:

  • script: bytes that denotes the oracle script. That is, a script from the contract state used to authenticate the oracle.

Return: True if this object's script_input attribute unlocks script received as parameter. That is, oracle is authenticated.

SignedData.get_data_bytes

Given a contract ID, returns a serialized version of data as bytes. Use it to perform unit tests on your blueprint.

get_data_bytes(self, contract_id: ContractId) -> bytes:

Parameter:

  • contract_id: ContractId that denotes a contract ID that is being used in the unit test.

Return: bytes that denotes the serialized version of the attribute data. Use it to generate the script_input during unit tests.

Usage:

The following snippet presents how to write a public method that allows an oracle to feed off-chain data to a contract:

from hathor.nanocontracts.types import TxOutputScript
from hathor.nanocontracts.types import SignedData

# Script that must be resolved to authenticate oracle.
oracle_script: TxOutputScript

# SignedData[str] specifies that off-chain data being passed is of type string.
@public
def provide_offchain_data(self, ctx: Context, signed_data: SignedData[str]) -> None:
"""Called by oracle to input off-chain data into contract."""

# Check if script_input resolves oracle_script, to authenticate oracle.
if not signed_data.checksig(self.oracle_script):
raise NCFail('Oracle not authenticated')

# Once oracle authenticated, off-chain data can be input into contract.
self.offchain_data = signed_data.data

Source code:
hathor.nanocontracts.types.SignedData

Decorators

public

Decorator that marks a method in your blueprint class as 'public'. All public methods must be marked with the public decorator. In addition, you must explicitly specify which types of actions the public method can receive. This should be done using the following keyword arguments:

  • Option 1: use allow_actions to provide the list of allowed NCActionType values. Example: allow_actions=[NCActionType.DEPOSIT, NCActionType.WITHDRAWAL]).
  • Option 2: pass True for each action type you want to allow:
"""
- allow_deposit=True for DEPOSIT
- allow_withdrawal=True for WITHDRAWAL
- allow_grant_authority=True for GRANT_AUTHORITY
- allow_acquire_authority=True for ACQUIRE_AUTHORITY
"""

You cannot use allow_actions (option 1) together with the other keyword arguments (option 2). Doing so will always raise a BlueprintSyntaxError exception.

tip

If an action type is not explicitly allowed using the keyword arguments in the @public decorator, the public method will not be able to receive or handle that type of action. If you use the @public decorator with no keyword arguments, the method will not be allowed to receive any actions. Finnaly, calling a public method with actions it is not allowed to handle will cause the method call to fail.

Usage:

from hathor.nanocontracts.types import public, NCActionType, SignedData
from hathor.nanocontracts.context import Context
...

# Mark all your public methods:
@public
def set_result(self, ctx: Context, result: SignedData[Result]) -> None:
"""Public method that CANNOT receive any type of action.

This is because you didn't explicitly allowed any type
alongside the public decorator.
"""
...

# If you want your method to receive any type of action
# You must do it explicitly:
@public(allow_actions=[NCActionType.DEPOSIT, NCActionType.WITHDRAWAL])
def swap(self, ctx: Context) -> None:
"""Public method that works with deposits and withdrawals.

It can receive ANY number of deposits and withdrawals
of any token. It is up to your code to validate these
actions.
We used the allow_actions arg to pass a list of enabled
actions, and we needed to use the NCActionTypes.
"""
...

# There are two alternative syntaxes to state the types of actions
# You either pass the allow_actions arg or:
@public(allow_deposit=True, allow_withdrawal=True)
def swap(self, ctx: Context) -> None:
"""Decorator using the other keyword args of public.

Both work the same way.
Here we do the same we did above but using one keyword arg
for each specific type of action.
"""
...

# It is not required to pass: one of them as False:
@public(allow_grant_authority=False, allow_acquire_authority=False)
def foo(self, ctx: Context) -> None:
"""False with <allow_some_action_type> arg changes nothing.

You may decide to use it just for human-reading purposes if you prefer.
"""
...

Source code:
hathor.nanocontracts.types.public

view

Decorator that marks a method in your blueprint class as 'view'. All view methods must be marked with the view decorator.

Usage:

from hathor.nanocontracts.types import view
...
# Mark all your view methods.
@view
def get_max_withdrawal(self, address: Address) -> int:
"""Return the maximum amount available for withdrawal."""
...

Source code:
hathor.nanocontracts.types.view

fallback

Decorator that marks the method named 'fallback' in your blueprint class. That is, you can only use the @fallback decorator once in the entire blueprint class, and only to mark a method named fallback.

Just like with public methods, you must explicitly specify the allowed action types; use the same keyword arguments and follow the same rules, as described in subsection public at Decorators.

Usage:

from hathor.nanocontracts.types import public, NCActionType
from hathor.nanocontracts.context import Context
...

# Mark your fallback method:
@fallback(allow_actions=[NCActionType.DEPOSIT, NCActionType.WITHDRAWAL, NCActionType.GRANT_AUTHORITY, NCActionType.ACQUIRE_AUTHORITY])
def fallback(self, ctx: Context) -> None:
"""THE only fallback method of your blueprint class.

You can only use this decorator with the method named 'fallback'.
Whenever a caller calls a non-existent PUBLIC method, Hathor engine
will invoke the fallback method.
Thus: just like any public method, you must explicitly state
what action types the method works with.
"""
...

Source code:
hathor.nanocontracts.types.fallback

Objects

Blueprint.syscall

For all interactions outside the scope of the blueprint itself (external interactions). That is, whenever you need to perform reads and writes to the ledger, call methods from other contracts, or access special features provided by Hathor engine.

Methods:

  • get_contract_id
  • get_blueprint_id
  • get_balance_before_current_call
  • get_current_balance
  • can_mint_before_current_call
  • can_mint
  • can_melt_before_current_call
  • revoke_authorities
  • mint_tokens
  • melt_tokens
  • create_token
  • call_view_method
  • call_public_method
  • emit_event
  • create_contract

The following subsections describe each of these methods.

syscall.get_contract_id

Returns the contract's own ID.

get_contract_id(self) -> ContractId:

syscall.get_blueprint_id

Returns the blueprint ID of the given contract.

get_blueprint_id(self, contract_id: Optional[ContractId] = None) -> BlueprintId:

Parameter:

  • contract_id: ContractId to query; defaults to the contract itself.

syscall.get_balance_before_current_call

Returns the balance of a token held by a contract; it does not take into account the effects of the current call.

get_balance_before_current_call(
self,
token_uid: Optional[TokenUid] = None,
*,
contract_id: Optional[ContractId] = None,
) -> Amount:

Parameters:

  • token_uid: TokenUid to check balance; defaults to 'HTR'.
  • contract_id: ContractId to query; defaults to the contract itself.

Return: Amount, such that:

  • It takes into account:
    • Everything that happened in the call chain before this call, including any actions.
  • It does not take into account:
    • Actions or changes that occurred during the current call.
    • Actions or changes that will occur later in this call or in subsequent calls (since they haven’t happened yet, by definition).

Example: if a contract holds 50 HTR and the current call is requesting to withdraw 3 HTR, this method still returns 50 HTR.

syscall.get_current_balance

Returns the balance of a token held by a contract; it does take into account the actions and changes already performed in the current call.

get_current_balance(
self,
token_uid: Optional[TokenUid] = None,
*,
contract_id: Optional[ContractId] = None,
) -> Amount:

Parameters:

  • token_uid: TokenUid to check balance; defaults to 'HTR'.
  • contract_id: ContractId to query; defaults to the contract itself.

Return: Amount, such that:

  • It takes into account:
    • Everything that happened in the call chain before this call, including any actions.
    • All actions and changes that occurred during the current call.
  • It does not take into account:
    • Actions or changes that will occur later in this call or in subsequent calls (since they haven’t happened yet, by definition).

Example: if a contract holds 50 HTR and the current call is requesting to withdraw 3 HTR, this method returns 47 HTR.

syscall.can_mint_before_current_call

Returns whether a contract has mint authority over a token; it does not take into account the actions and changes already performed in the current call.

can_mint_before_current_call(
self,
token_uid: TokenUid,
*,
contract_id: Optional[ContractId] = None,
) -> bool:

Parameters:

  • token_uid: TokenUid to check authority.
  • contract_id: ContractId to query; defaults to the contract itself.

Return: bool, such that:

  • True means the contract has mint authority over the token.
  • It takes into account:
    • Everything that happened in the call chain before this call, including any actions.
  • It does not take into account:
    • All actions and changes that occurred during the current call.
    • Actions or changes that will occur later in this call or in subsequent calls (since they haven’t happened yet, by definition).

Example: if a contract has mint authority over a token and the current call revokes it before invoking this method, it still returns True.

syscall.can_mint

Returns whether a contract has mint authority over a token; it does take into account the actions and changes already performed in the current call.

can_mint(
self,
token_uid: TokenUid,
*,
contract_id: Optional[ContractId] = None,
) -> bool:

Parameters:

  • token_uid: TokenUid to check authority.
  • contract_id: ContractId to query; defaults to the contract itself.

Return: bool, such that:

  • True means the contract has mint authority over the token.
  • It takes into account:
    • Everything that happened in the call chain before this call, including any actions.
    • All actions and changes that occurred during the current call.
  • It does not take into account:
    • Actions or changes that will occur later in this call or in subsequent calls (since they haven’t happened yet, by definition).

Example: if a contract has mint authority over a token and the current call revokes it before invoking this method, it returns False.

syscall.can_melt_before_current_call

Returns whether a contract has melt authority over a token; it does not take into account the actions and changes already performed in the current call.

can_melt_before_current_call(
self,
token_uid: TokenUid,
*,
contract_id: Optional[ContractId] = None,
) -> bool:

Parameters:

  • token_uid: TokenUid to check authority.
  • contract_id: ContractId to query; defaults to the contract itself.

Return: bool, such that:

  • True means the contract has melt authority over the token.
  • It takes into account:
    • Everything that happened in the call chain before this call, including any actions.
  • It does not take into account:
    • All actions and changes that occurred during the current call.
    • Actions or changes that will occur later in this call or in subsequent calls (since they haven’t happened yet, by definition).

Example: if a contract has melt authority over a token and the current call revokes it before invoking this method, it still returns True.

syscall.can_melt

Returns whether a contract has melt authority over a token; it does take into account the actions and changes already performed in the current call.

can_melt(
self,
token_uid: TokenUid,
*,
contract_id: Optional[ContractId] = None,
) -> bool:

Parameters:

  • token_uid: TokenUid to check authority.
  • contract_id: ContractId to query; defaults to the contract itself.

Return: bool, such that:

  • True means the contract has melt authority over the token.
  • It takes into account:
    • Everything that happened in the call chain before this call, including any actions.
    • All actions and changes that occurred during the current call.
  • It does not take into account:
    • Actions or changes that will occur later in this call or in subsequent calls (since they haven’t happened yet, by definition).

Example: if a contract has melt authority over a token and the current call revokes it before invoking this method, it returns False.

syscall.revoke_authorities

Revokes the contract’s own mint/melt authorities over a token.

revoke_authorities(
self,
token_uid: TokenUid,
*,
revoke_mint: bool,
revoke_melt: bool
) -> None:

Parameters:

  • token_uid: TokenUid to revoke authorities over.
  • revoke_mint: bool; if True, will revoke mint authority.
  • revoke_melt: bool; if True, will revoke melt authority.

syscall.mint_tokens

Mints a new amount of a given token and adds it to the contract balance.

def mint_tokens(self, token_uid: TokenUid, amount: int) -> None:

Parameters:

  • token_uid: TokenUid to mint; contract must have mint authority over it.
  • amount: Amount to mint; contract must hold enough HTR in its balance to be consumed in the process.

syscall.melt_tokens

Melts an amount of a given token by removing it to the contract balance.

def melt_tokens(self, token_uid: TokenUid, amount: int) -> None:

Parameters:

  • token_uid: TokenUid to melt; contract must have melt authority over it.
  • amount: Amount to melt; contract receives in its balance the redemption of HTR.

syscall.create_token

Creates a new fungible token and adds its initial supply to the contract balance.

create_token(
self,
token_name: str,
token_symbol: str,
amount: int,
mint_authority: bool = True,
melt_authority: bool = True,
) -> TokenUid:

Parameters:

  • token_name: str; 1-30 UTF-8 characters.
  • token_symbol: str; 1-5 UTF-8 characters.
  • amount: Amount that denotes initial supply of the token; contract must hold enough HTR in its balance to be consumed in minting initial supply.
  • mint_authority: bool; if True, creates a mint authority for the contract over the new token.
  • melt_authority: bool; if True, creates a melt authority for the contract over the new token.

Return: TokenUid that uniquely identifies the token on the ledger (blockchain).

syscall.call_view_method

Calls a view method of another contract.

call_view_method(self, nc_id: ContractId, method_name: str, *args: Any, **kwargs: Any) -> Any:

Parameters:

  • nc_id: ContractId; contract to be called.
  • method_name: str; view method to be called.
  • Use *args or **kwargs to pass the method arguments according to the blueprint API of the target contract.

Return: you should know the blueprint API of target contract in order to properly handle return value.

syscall.call_public_method

Calls a public method of another contract.

call_public_method(
self,
nc_id: ContractId,
method_name: str,
actions: list[NCAction],
*args: Any,
**kwargs: Any,
) -> Any:

Parameters:

  • nc_id: ContractId; contract to be called.
  • method_name: str; public method to be called.
  • actions: list of NCAction to be performed over target contract; caller contract (itself) must have sufficient funds to perform deposits and target contract must have sufficient funds for withdrawals.
  • Use *args or **kwargs to pass the method arguments according to the blueprint API of the target contract.

Return: you should know the blueprint API of target contract in order to properly handle return value.

syscall.emit_event

Registers an event related to the current contract execution. The event is recorded by all full nodes configured to produce events — i.e., with the ledger events producer feature enabled — and can be consumed by client applications connected to them. For more on ledger events, see Ledger events at Highlighted configurations.

emit_event(self, data: bytes) -> None:

Parameter:

  • data: bytes that denotes the event to be registered; limited to 100 KiB. The event is marked as type NC_EVENT in the event database of each full node. Its content data consists of raw bytes, intended for client applications that know how to interpret it.

syscall.create_contract

Create a new contract.

create_contract(
self,
blueprint_id: BlueprintId,
salt: bytes,
actions: list[NCAction],
*args: Any,
**kwargs: Any,
) -> tuple[ContractId, Any]:

Parameters:

  • blueprint_id: BlueprintId to instantiate new contract from.
  • salt: bytes used to generate the ContractId for contracts created by the current contract itself. This value must be unique for each contract it creates. You can use UUIDs generated via a pseudo-random number generator, or even a simple counter.
  • actions: list of NCAction as required by method initialize of chosen blueprint.
  • Use *args or **kwargs to pass the arguments required by method initialize of chosen blueprint.

Return: tuple where the first item is ContractId that uniquely identifies the newly created contract; and second is the return value of method initialize of the chosen blueprint. You should know the chosen blueprint API in order to properly handle return value.

Object:

Source code:
hathor.nanocontracts.blueprint_env.BlueprintEnvironment

Blueprint.log

Use it to record method execution logs. Useful during development for debugging and testing, and in production for audits.

Methods:

  • debug
  • info
  • warn
  • error

The following subsections describe each of these methods.

log.debug

Create a new DEBUG log entry.

debug(self, message: str, **kwargs: Any) -> None:

log.info

Create a new INFO log entry.

info(self, message: str, **kwargs: Any) -> None:

log.warn

Create a new WARN log entry.

warn(self, message: str, **kwargs: Any) -> None:

log.error

Create a new ERROR log entry.

error(self, message: str, **kwargs: Any) -> None:
info

In addition to the log message (argument message), all methods accept arbitrary arguments via **kwargs: Any. These arguments will be recorded as key/value pairs. bytes will be represented as hexadecimals, and all values will be recorded as strings.

syscall.rng

Random number generator (RNG) for use cases that require randomness. From Hathor engine's perspective, random number generation is deterministic — all nodes on the network will generate the same number. However, from the contract users' perspective, the number generation is truly random. It is built on the ChaCha20 algorithm.

Data attribute:

  • seed: bytes; seed used to create the RNG object. The seed is the double hash of the first block validating the transaction.

Methods:

  • randbits
  • randbelow
  • randrange
  • randint
  • choice
  • random

The following subsections describe each of these methods.

rng.randbits

Returns a random integer in the range [0,2bits)[0,2^{bits}), where bitsbits is integer and 1\geq 1. In other words, a random non-negative integer with size bitsbits.

randbits(self, bits: int) -> int:

rng.randbelow

Returns a random integer in the range [0,n)[0, n), where nn is integer and 1\geq 1.

randbelow(self, n: int) -> int:

rng.randrange

Returns a random integer in the range [start,stop)[start, stop) with step size stepstep, where startstart, stopstop, and stepstep are integers such that start<stopstart < stop and step1step \geq 1. The result will always be within the given interval, and of the form start+kstepstart + k \cdot step for a random integer kk. For example: randrange(start=10, stop=20, step=2) may return any of the following values: 10, 12, 14, 16, or 18.

randrange(self, start: int, stop: int, step: int = 1) -> int:

rng.randint

Returns a random integer in the range [a,b][a, b], where aa and bb are integers such that a1a \geq 1 and ba b \geq a.

randint(self, a: int, b: int) -> int:

rng.choice

Chooses a random element from the non-empty Sequence.

choice(self, seq: Sequence[T]) -> T:

Parameter:

rng.random

Returns a random float in the range [0,1)[0,1).

random(self) -> float:

Source code:
hathor.nanocontracts.rng.NanoRNG

What's next?