As outlined in the tranasction flow, a call to validateNonceUsage is made to the NonceHolder system contract before each transaction starts, in order to check whether the provided nonce of a transaction has already been used or not.

The bootloader enforces that the nonce:

  1. Has not already been used before transaction validation begins.
  2. The nonce is used (typically incremented) during transaction validation.

Considering nonces in your smart contract account

As mentioned above, you must “use” the nonce in the validation step. To mark a nonce as used there are two options:

  1. Increment the minNonce: All nonces less than minNonce will become used.
  2. Set a non-zero value under the nonce via setValueUnderNonce.

A convenience method, incrementMinNonceIfEquals is exposed from the NonceHolder system contract. For example, inside of your smart contract wallet, you can use it to increment the minNonce of your account.

In order to use the NonceHolder system contract, the isSystem flag must be set to true in the transaction, which can be done by using the SystemContractsCaller library shown below. Learn more about using system contracts.

// Required imports
import "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol";
import {SystemContractsCaller} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol";
import {NONCE_HOLDER_SYSTEM_CONTRACT, INonceHolder} from "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol";
import {TransactionHelper} from "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol";

function validateTransaction(
    bytes32,
    bytes32,
    Transaction calldata _transaction
) external payable onlyBootloader returns (bytes4 magic) {

    // Increment nonce during validation
    SystemContractsCaller.systemCallWithPropagatedRevert(
        uint32(gasleft()),
        address(NONCE_HOLDER_SYSTEM_CONTRACT),
        0,
        abi.encodeCall(
            INonceHolder.incrementMinNonceIfEquals,
            (_transaction.nonce)
        )
    );

    // ... rest of validation logic here

}