Deploy your first smart contract using pint
"counter" is one of the simplest smart contracts that can be written in Pint. It showcases how a contract can have multiple predicates and how it can declare and use storage
Simple Counter contract
Create a new file named counter.pnt.
The contract starts by declaring a storage
block which contains a single storage variable called counter
of type int
(i.e. integer). The contract later declares two separate predicates, each having a single parameter and declaring two statements. Let's walk through the first predicate named Initialize
:
Predicate
Initialize
has a single parameter calledvalue
of typeint
. The parameters of a predicate are essentially decision variables that a solver is required to find values for such that everyconstraint
in the predicate evaluates totrue
. The expression "decision variable" is commonly used in constraint programming languages to refer to unknowns that a solver must find given some constraints. InInitialize
, the parametervalue
is the value that we want our counter to get initialized to.The second statement declares a local variable and initializes it to
mut storage::counter
. The statementlet counter: int = mut storage::counter
creates a local variable calledcounter
and initializes it to the current value ofcounter
declared in thestorage
block. Themut
keyword simply indicates that the solver is allowed to propose a new value forcounter
. Ifmut
is not present, then the storage variablecounter
cannot be modified by anyone attempting to solve predicateInitialize
.The third statement contains the core logic of this predicate. It declares that the "next value" of
counter
must be equal tovalue
. Note the'
notation here which can be only applied to a local variable, and means "the next value of the state variable after a valid state transition".
The second predicate, called Increment
, has a similar structure to Initialize
. However, instead of initializing counter
, It increments it by amount
. Note that both counter
(the current value) and counter'
(the next value) are both used in the constraint to enforce that the next value is dependent on the current value, which was not the case in Initialize
.
Deploy a token smart contract
In this example you will get a clear understanding on how to create a simple token smart contract using pint, compile and deploy it on a local network. The components are as follows 1) Storage Struct
Storage Definitions:
balances
: A mapping of account addresses (b256
) to their token balances (int
).nonce
: Tracks the number of transactions made by each account to safeguard against replay attacks.token_name
: A hashed representation of the token's name.token_symbol
: A hashed representation of the token's symbol.decimals
: An integer indicating the token's decimal precision.
BurnAccount
Interface:
Contains a predicate
Owner
which verifies authorization to burn tokens. It requires:key
: The account address.amount
: The number of tokens to burn.token_address
: The address of the predicate used for verification purposes.
Macros:
Macros
@check_if_predicate_is_owner
are defined to streamline the process of checking if a given predicate is the owner. These macros allow for different numbers of arguments:They evaluate whether a specified contract and predicate address match, utilizing the current contract and its address.
The macros can accept varying numbers of arguments (from one to three), enhancing flexibility. These arguments assist in conducting ownership checks in different contexts of authorization.
These elements work together to ensure secure execution of token-burning functions, while also enabling efficient ownership verification processes.
BurnAuth & MintAuth: These are union types that determine the authorization method for burning and minting tokens. They can either be signed using a Secp256k1Signature or validated using a PredicateAddress.
TransferSignedMode: An enumeration defining the different modes of signed transfer authorization including options such as All, Key, KeyTo, and KeyAmount.
TransferSignedAuth: A type that combines a Secp256k1Signature and a TransferSignedMode, representing signed authorization for transfers.
TransferAuthMode: A union that encapsulates the method of transfer authorization, accepting either a signed authorization or a predicate-based one.
Extra: A type holding a PredicateAddress, providing additional information for authorization.
ExtraConstraints: A union type that can either be an Extra or None, indicating if there are additional constraints on authorization.
TransferAuth: A type representing the complete transfer authorization details, combining TransferAuthMode and ExtraConstraints for comprehensive transfer verification.
The interface MintAccount
defines a predicate called Owner
to verify ownership when minting new tokens. It requires certain parameters: a key (b256
), an amount (int
), decimals (int
), and a token address (PredicateAddress
). This predicate ensures that the entity attempting to mint tokens has legitimate ownership and the right parameters.
The predicate Mint
function checks if tokens can be minted under specific conditions. It ensures:
The
key
matches a predefinedMINT_KEY
.Various token attributes like
balance
,token_name
, andtoken_symbol
are initialized correctly.The
auth
parameter is validated either through a signature or by checking if a predicate is the owner, using the@check_if_predicate_is_owner
macro.
This setup secures the minting process, ensuring only authorized entities can mint tokens by verifying ownership through signatures or predicates.
The Transfer
predicate validates a token transfer between two addresses in a smart contract. It checks several conditions:
Balance checks: The sender must have enough balance, and the receiver's balance is updated accordingly.
Amount validation: The transfer amount must be positive.
Nonce management: The sender’s nonce is safely incremented to prevent replay attacks.
Authentication: The transaction is authorized either by a digital signature (with various verification modes) or by checking a predicate to verify ownership.
Additional constraints: If there are any extra constraints (provided in
auth.extra
), they are validated.
Last updated