Skip to main content

Please note that zkApp programmability is not yet available on Mina Mainnet, but zkApps can now be deployed to Berkeley Testnet.

On-Chain Values

We already saw how you can access the current on-chain state of a zkApp account. Similarly, you can access many other on-chain values in a zkApp.

Just to give you an idea, here are two possible use cases:

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

We group on-chain values in two categories:

  • 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

The subfields of both categories are are accessible on and this.account in your smart contract. For example, the timestamp is on, and it has four methods on it:;;, upper);

With two of them you are already familiar: On-chain state has the same get() and assertEquals() methods. assertBetween() gives you even more power: it allows you to make assert that the timestamp is between lower and upper (inclusive).

Example: restricting timestamps

Let's see how assertBetween() can be used in the voting example mentioned earlier. Assume we want to allow voting throughout September 2022. Timestamps are represented as a UInt64 in milliseconds since the UNIX epoch. We can use the JS Date object to easily convert to this representation. In the simplest case, our 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 vote(...) {, endDate);
// ...

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

In addition to using a predefined range, you can also construct a range that depends on another variable, such as the current time. For example, a DEX with an order book could support orders that expire after an hour. So, the range should be [now, now + 1h], such as below:

const now =;, now.add(60 * 60 * 1000));

Network reference

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

All of those fields have a get() and an assertEquals() method, and the subset that represent "ordered values" (those that are UInt32 or UInt64), also have assertBetween().

Of course, there's no need to remember this -- just type and let IntelliSense guide you!

// 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;

Account reference

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

// 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. If you try this, you'll see that SnarkyJS throws a helpful error reminding you to use assertEquals() and asserBetween(). As an escape hatch, if you want to get() a value and are really sure you want to not constrain the on-chain value in any way, there's assertNothing() on all of these fields (including on-chain state). Use at your own risk.


assertNothing() 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 you can change permissions on an account:

setVerificationKey: Permissions.impossible(),

And here's how you can set the delegate (the account that your smart contract delegates its stake to):


The fields that you can set are not the same as those that you can make assertions about. This is the full list that have a .set(), with short descriptions:

// 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 other accounts than the zkApp's

The API described in this section (get / set / assertEquals / ...) can not only be used to access the zkApp account itself, but also any other account. To do so, just create an account update — you'll find the same account / network fields API on it:

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 have to make sure that this same account update has the correct authorization to perform those actions. For example, to initially set the verification key, the update will likely need 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