Skip to main content

On-Chain Values

In a zkApp, you can access the current on-chain state and many other on-chain values of the account.

The zkApp account's on-chain state can be updated by account updates included in a transaction (see Tutorial 10: Account Updates). On the Mina blockchain, each zkApp account provides eight fields of ~32 bytes each of arbitrary storage for the on-chain state.

Two possible use cases:

  • You want to let users vote on a proposal, but only within a specific timespan. To restrict the dates, your zkApp can require that the current timestamp lies in a certain range.
  • In DeFi, you want to compute amounts relative to a balance. For example, paying a yield of 0.001 times the account balance requires the current on-chain balance.

There are two categories of on-chain values:

  • Network: includes the current timestamp, block height, total Mina in circulation, and other network state
  • Account: includes fields and properties of the zkApp account, such as balance, nonce, and delegate

In a smart contract, the subfields are accessible on and this.account. For example, the timestamp on has four methods:;;, upper);
  • The familiar on-chain state has the same get() and requireEquals() methods.
  • The requireBetween() method has even more power: it allows you to make assertions that the timestamp is between lower and upper (inclusive).

Example: Restricting timestamps

To use the requireBetween() method in a voting example, you can allow voting throughout September 2024. Timestamps are represented as a UInt64 in milliseconds since the UNIX epoch. You can use the JS Date object to easily convert to this representation. In the simplest case, a zkApp could just hard-code the dates:

const startDate = UInt64.from(Date.UTC(2022, 9, 1));
const endDate = UInt64.from(Date.UTC(2022, 10, 1));

class VotingApp extends SmartContract {
// ...

@method async vote(...) {, endDate);
// ...

A more refined example could store the current start date in an on-chain state variable, which can then be reset by some process that is also encoded by the zkApp.

Network reference

For completeness, here is the list of network states you can use and make assertions about in your zkApp.

All of these fields have a get() and an requireEquals() method. The subset that represents "ordered values" (those that are UInt32 or UInt64) also have requireBetween().

// current UNIX time in milliseconds, as measured by the block producer UInt64;
// length of the blockchain, also known as block height UInt32;
// total minted currency measured in units of 1e-9 MINA UInt64;
// slots since genesis / hardfork -- a "slot" is the Mina-native time unit of 3 minutes UInt32; UInt32;
// hash of the snarked ledger -- i.e., the state of Mina included in the blockchain proof Field;
// minimum window density in our consensus algorithm UInt32;
// consensus data relevant to the current staking epoch Field; UInt64; UInt32; Field; Field; Field;
// consensus data relevant to the next, upcoming staking epoch Field; UInt64; UInt32; Field; Field; Field;

You don't have to remember this, just type and let the intelligent code complete guide you.

Account reference

Here's the full list of values you can access on the zkApp account. Like the network states, these values have get() and requireEquals(). Balance and nonce also have requireBetween().

// the account balance; this might be nanoMINA or a custom token
this.account.balance.get(): UInt64;
// account nonce -- increases by 0 or 1 in every transaction
this.account.nonce.get(): UInt32;
// the account the zkApp delegates its stake to (default: its own address)
this.account.delegate.get(): PublicKey;
// boolean indicating whether an account is new (= didn't exist before the transaction)
this.account.isNew.get(): Bool;
// boolean indicating whether all 8 on-chain state fields where last changed by a transaction
// authorized by a zkApp proof (as opposed to a signature)
this.account.provedState.get(): Bool;
// hash receipt which includes all prior transaction to an account
this.account.receiptChainHash.get(): Field;

Bailing out

In some rare cases, you might, for whatever reason, want to get() an on-chain value without constraining it to any value. However, if you try this, o1js throws a helpful error reminding you to use requireEquals() and requireBetween(). As an escape hatch, if you want to get() a value and are really sure you do not want to constrain the on-chain value in any way, you can use requireNothing() on all of these fields (including on-chain state). Use requireNothing() at your own risk.


requireNothing() should be rarely used and could cause security issues through unexpected behavior if used improperly. Be certain you know what you're doing before using this.

Setting account fields

Just like on-chain state, some account fields can be written to. Again, the API is consistent with state: this.account.<field>.set(newValue).

For example, here's how to change permissions on an account:

setVerificationKey: {
auth: Permissions.proof(),
txnVersion: TransactionVersion.current(),

To set the delegate (the account that your smart contract delegates its stake to):


The fields that you can set are not the same as the fields that you can make assertions about.

Here is the full list of fields that have a .set():

// the account that this account delegates its MINA stake to
this.account.delegate.set(value: PublicKey);
// the verification key
this.account.verificationKey.set(value: VerificationKey);
// account permissions, to control authorization for performing actions on the account
this.account.permissions.set(value: Permissions);
// currently unused - could become URL holding zkApp metadata
this.account.zkappUri.set(value: string);
// token symbol of the token owned by this account — only relevant for token contracts!
this.account.tokenSymbol.set(value: string);
// parameters to control a vesting schedule, used in time-locked accounts
this.account.timing.set(value: Timing);

Accessing accounts other than the zkApp's account

The API described in this section (get / set / assertEquals / ...) can be used to access the zkApp account itself, but also any other account. Account updates are a flexible and powerful data structure that can express all kinds of updates, events, and preconditions you use to develop smart contracts. See Tutorial 10: Account Updates.

To create an account update to find the same account and network fields:

let accountUpdate = AccountUpdate.create(address);

// use the balance of this account
let balance = accountUpdate.account.balance.get();

// assert that this account is new

// set permissions this account

When setting fields on an account update, you must ensure that this same account update has the correct authorization to perform those actions.

For example, to initially set the verification key, the update requires a signature from the account owner:

// use createSigned to require a signature
let accountUpdate = AccountUpdate.createSigned(address);

// set the verification key on the account; could be used to deploy a zkApp from a zkApp