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.

Data types

Address

  • Description: a wallet address
  • Format: 20 bytes
  • Alias for: 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
  • Format: integer where the last two digits are decimals
  • Alias for: int
  • 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.
  • Format: 32 bytes
  • Alias for: VextexId
  • Example: bytes.fromhex("3cb032600bdf7db784800e4ea911b10676fa2f67591f82bb62628c234e771595")
  • Usage:
    from hathor.nanocontracts.types import BlueprintId
    ...
    blueprint: BlueprintId
    ...
    blueprint = bytes.fromhex("3cb032600bdf7db784800e4ea911b10676fa2f67591f82bb62628c234e771595")

ContractId

  • Description: identifier of a nano contract. It is the hash of the transaction that created it.
  • Format: 32 bytes
  • Alias for: VextexId
  • Example: bytes.fromhex("000063f99b133c7630bc9d0117919f5b8726155412ad063dbbd618bdc7f85d7a")
  • Usage:
    from hathor.nanocontracts.types import ContractId
    ...
    contract: ContractId
    ...
    contract = bytes.fromhex("000063f99b133c7630bc9d0117919f5b8726155412ad063dbbd618bdc7f85d7a")

Timestamp

  • Description: timestamp following Unix epoch standard
  • Format: integer representing the number of seconds elapsed since January 1st, 1970 00:00:00 UTC.
  • Alias for: int
  • 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 token. It is the hash of the transaction that created it.
  • Format: 32 bytes
  • Alias for: 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
  • Format: 32 bytes
  • Alias for: 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.
  • Format: 32 bytes
  • Alias for: bytes
  • Example: bytes.fromhex("00000943573723a28e3dd980c10e08419d0e00bc647a95f4ca9671ebea7d5669")
  • Usage:
    from hathor.nanocontracts.types import VertexId
    ...
    tx: VertexId
    ...
    tx = bytes.fromhex("00000943573723a28e3dd980c10e08419d0e00bc647a95f4ca9671ebea7d5669")

Classes

Blueprint

Your blueprint class must inherit directly from Blueprint.

Usage:

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

Context

Provides to the invoked method all the information regarding the current transaction and the state of the ledger (blockchain). Every public method must have a Context object as its second parameter. Context

Data attributes:

  • vertex: VertexData object that contains the basic data of the transaction that called the method (current transaction).
  • address: Address that denotes who called the method.
  • timestamp: int that denotes the timestamp (Unix epoch standard) of the first block confirming the current transaction.
  • actions: dict where the keys are TokenUid and the values are NCAction objects. All actions (deposits and withdrawals) requested in the current transaction.

Methods:

See hathor-core/hathor/nanocontracts/context.py.

Usage:

from hathor.nanocontracts.context import Context
...
ctx: Context
...
# Second parameter of a public method is always a Context object:
@public
def bet(self, ctx: Context, address: Address, score: str) -> None:
"""Make a bet."""
...

NCActionType

An enumeration (Enum) that defines the possible types of interactions a transaction can have with a contract. Can be one of the following:

  • DEPOSIT for deposit.
  • WITHDRAWAL for withdrawal.

Usage:

from hathor.nanocontracts.types import NCActionType
...
# Check if the action is a deposit:
if action.type != NCActionType.DEPOSIT:
raise WithdrawalNotAllowed('must be deposit')

NCAction

A NamedTuple that defines an action — either deposit or withdrawal — that a user wants to perform on the contract. This action is derived from the consolidated inputs and outputs of the current transaction.

Data attributes:

  • type: NCActionType that denotes the type of action (deposit or withdrawal).
  • token_uid: TokenUid that denotes the token being deposited/withdrawn.
  • amount: int that denotes the amount to be deposited/withdrawn.

Examples:

The three data attributes of an NCAction together define an action in the format: "perform an NCActionType of amount tokens token_uid". For example, "perform a deposit of 10.25 tokens A" corresponds to NCAction:

action_a:
type: DEPOSIT
token_uid: <token_A_UID>
amount: 1025

Here is a sample code for this action:

action_a = NCAction(NCActionType.DEPOSIT, b'<token_A_UID>', 1025)

And "perform a withdrawal of 10.25 tokens B" corresponds to NCAction:

action_b:
type: WITHDRAWAL
token_uid: <token_B_UID>
amount: 1025

Here is a sample code for this action:

action_b = NCAction(NCActionType.WITHDRAWAL, b'<token_B_UID>', 1025)

Usage:

from hathor.nanocontracts.types import NCAction
...
def fail_if_invalid_token(self, action: NCAction) -> None:
...
def _get_action(self, ctx: Context) -> NCAction:
...

NCFail

An NCFail exception signals to Hathor protocol 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.

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')
...

SignedData

Used for implementing oracles in blueprints. To achieve this, the blueprint should have a public method exclusively for oracle use, with a SignedData object as its primary received parameter.

Data attributes:

  • data: off-chain data that the oracle wants to input 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 must 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>

Method checksig:

Called in the oracle's public method to authenticate the oracle. That is, confirm that script_input resolves the oracle script defined during contract creation.

Usage:

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

Functions

public

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

Usage:

from hathor.nanocontracts.types import public
...
# Mark all your public methods.
@public
def bet(self, ctx: Context, address: Address, score: str) -> None:
"""Make a bet."""
...

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."""
...

What's next?