Write the predicate

Start by adding a new predicate called Increment to the contract/src/contract.pnt file:

predicate Increment {

}

Storage

The first thing we want to do within this predicate is to read the counter storage value:

predicate Increment {
    state counter: int = storage::counter;
}

When a storage value is read like this there are actually two values read:

  • The pre-state value of the storage, denoted by counter.
  • The post-state value of the storage, denoted by counter'. (Notice the apostrophe ').

Constraint

Let's add our first constraint:

predicate Increment {
    state counter: int = storage::counter;

    constraint counter' == counter + 1;
}

A constraint is a boolean expression which must be true for the predicate to be satisfied.
This constraint says that the post-state of the counter must be equal to the pre-state plus one.

But there is a problem with this constraint.
What if the pre-state of the counter is not yet set to anything?

We can use a nil check to handle this case:

predicate Increment {
    state counter: int = storage::counter;

    constraint counter == nil && counter' == 1;
}

This says that if the pre-state of the counter is nil then the post-state must be 1.

Now let's put it all together:

predicate Increment {
    state counter: int = storage::counter;

    constraint (counter == nil && counter' == 1) || counter' == counter + 1;
}

This constraint is satisfied if either the counter pre-state is nil and the post-state is 1, or the counter pre-state is n and the post-state is n + 1.

Your complete contract/src/contract.pnt file should look like this:

storage {
    counter: int,
}

predicate Increment {
    state counter: int = storage::counter;

    constraint (counter == nil && counter' == 1) || counter' == counter + 1;
}

Congratulations on writing your first pint predicate!