Logo
Blockchain · Developer

o1js State Assertions: getAndRequireEquals vs getAndAssertEquals

20/10/2026
o1js state assertions on Mina zkApps

getAndRequireEquals is the most-googled method in o1js — the TypeScript DSL for writing zkApps on Mina Protocol — and the least documented. The short version: it reads an on-chain @state field and records a precondition on the account update, so the transaction is only valid if the chain state still matches when it is included in a block. This is how you get atomicity on a blockchain where your proof was generated minutes earlier on a laptop.

Why state reads need preconditions at all

A zkApp transaction is a zero-knowledge proof generated off-chain. When you prove it, the contract state says x = 10 — but by the time the transaction is included, another user may have changed x. The proof is only meaningful if it was computed against the state the chain actually had. Mina solves this with preconditions: assertions on the account update that validators check before applying it. If the precondition fails, the whole transaction is rejected.

getAndRequireEquals() couples the read and the precondition into one call — you get the value in your circuit and the guarantee that your proof is invalidated if the value changed underneath you.

get() vs getAndRequireEquals() vs requireEquals()

CallInside @method
this.x.get()Reads the value and sets the equality precondition — in current o1js this is exactly what getAndRequireEquals does.
this.x.getAndRequireEquals()Same as get(), but self-documenting: the precondition is explicit in the name.
this.x.requireEquals(v)Sets the precondition without returning the value — for constraints on state you don't otherwise use.
this.x.set(v)Writes new state (an action, not a precondition).
this.x.get() outside provable codeThrows — state can't be read outside a circuit. Off-chain, use fetch() or the account's appState.

Where did getAndAssertEquals go?

It was renamed, not removed. The assert* family was renamed to require* when o1js reworked its account-update API (the same rename hit assertEquals → requireEquals and the network preconditions). getAndAssertEquals() in old tutorials and GitHub issues is the same method as today's getAndRequireEquals() — old code just needs the name swap. The rename clarified that these are account-updatepreconditions, not in-circuit assert() calls that would fail the proof itself.

Worked example

class Counter extends SmartContract {
  @state(Field) num = State<Field>();

  @method async increment() {
    // read + precondition in one call
    const num = this.num.getAndRequireEquals();
    this.num.set(num.add(1));
  }

  @method async reset(newOwner: PublicKey) {
    // precondition without needing the value back
    this.num.requireEquals(Field(0));
    this.num.set(Field(0));
  }
}

The increment method encodes an optimistic-concurrency contract: if two users race, only the first transaction lands — the second sees a changednum and fails the precondition.

The error you're actually here for

Precondition unsatisfied (or a transaction silently stuck/failing) means a require* assertion didn't match chain state at inclusion time. Common causes:

  • Another transaction mutated the state between proving and inclusion — the design working as intended.
  • You read state with a plain get() on an old version where it didn't set the precondition, and your method consumed a stale value.
  • You wrote an in-circuit assert() where you needed an account-update require* — the proof builds fine but the semantics differ.
  • Network preconditions (this.network.timestamp, blockchainLength) set too tight a range.

Off-chain reads

Outside @method code there is no precondition machinery —get() throws. To display state in a UI, callawait this.x.fetch() (o1js ≥ 1.x) or query the account'sappState via Mina.getAccount(). Only provable code gets the read-and-require guarantee.

Frequently Asked Questions

What does getAndRequireEquals do in o1js?

It reads the current value of an on-chain @state field inside a@method and records an account-update precondition that the value must equal what the chain holds when the transaction is included. The proof becomes invalid if another transaction changes the state first.

Is getAndAssertEquals different from getAndRequireEquals?

No — same method, renamed. o1js renamed the assert* precondition API to require* to distinguish account-update preconditions from in-circuit assertions. Update old code by renaming; semantics are unchanged.

Is state.get() enough inside a @method?

Yes, in current o1js this.x.get() inside provable code sets the same equality precondition. getAndRequireEquals() is preferred in code where you want the concurrency guarantee to be visible — it's self-documenting.

Why can't I call state.get() outside a method?

Because a precondition only makes sense inside a transaction being proved. Off-chain reads go through fetch() or Mina.getAccount(), which return the raw appState without touching the account-update machinery.

Related Insights

Privacy & Cookie Preferences

We use cookies to enhance your experience, analyze site performance, and support our marketing efforts. Your privacy matters, and you can withdraw consent at any time.