Skip to main content

Signature & Nonce Management

Core.sol provides centralized signature verification and nonce management for all EVVM services. This unified system ensures security consistency across the entire ecosystem and prevents replay attacks in multi-service transactions.

validateAndConsumeNonce

Function Type: external
Function Signature: validateAndConsumeNonce(address,bytes32,address,uint256,bool,bytes)

The primary function used by all EVVM services (NameService, Staking, P2PSwap, Treasury) to validate user signatures and consume nonces atomically. This is the foundation of the centralized signature verification system.

Key Features

  • Centralized Validation: Single point of signature verification for entire ecosystem
  • Atomic Operation: Signature validation and nonce consumption happen together
  • Service Authorization: Only smart contracts can call this function
  • User Filtering: Integrates with optional UserValidator for transaction filtering
  • Cross-Service Security: Prevents replay attacks between different services

Parameters

FieldTypeDescription
useraddressAddress of the transaction signer
hashPayloadbytes32Hash of the transaction parameters (generated by service-specific hash functions)
originExecutoraddressOptional tx.origin restriction. Use address(0) to allow any origin
nonceuint256Nonce to validate and consume
isAsyncExecbooltrue for asynchronous (parallel) nonces, false for synchronous (sequential)
signaturebytesUser's EIP-191 authorization signature

How Services Use This Function

All EVVM services follow this pattern:

// 1. Service generates hash of its specific operation parameters
bytes32 hashPayload = NameServiceHashUtils.hashDataForRegister(
username,
lockNumber,
amountToPay
);

// 2. Service calls Core.validateAndConsumeNonce
Core(coreAddress).validateAndConsumeNonce(
user,
hashPayload,
originExecutor,
nonce,
isAsyncExec,
signature
);

// 3. If no revert, signature is valid and nonce is consumed
// Service can now safely execute its logic

Workflow

  1. Contract Verification: Validates that msg.sender is a smart contract using CAUtils.verifyIfCA(). Reverts with MsgSenderIsNotAContract if called by an EOA.

  2. Signature Verification: Reconstructs and validates the signature:

    • Builds signature payload: buildSignaturePayload(evvmId, msg.sender, hashPayload, originExecutor, nonce, isAsyncExec)
    • Recovers signer using SignatureRecover.recoverSigner()
    • Compares recovered address with user parameter
    • Reverts with InvalidSignature on mismatch
  3. Origin Executor Validation: If originExecutor is not address(0), checks that tx.origin matches. Reverts with OriginIsNotTheOriginExecutor on mismatch.

  4. User Validation: Checks if user is allowed to execute transactions via canExecuteUserTransaction(user) (integrates with UserValidator if configured). Reverts with UserCannotExecuteTransaction if blocked.

  5. Nonce Management: Validates and consumes the nonce based on isAsyncExec:

    • Async (isAsyncExec = true):
      • Checks nonce status via asyncNonceStatus(user, nonce)
      • Reverts with AsyncNonceAlreadyUsed if already used
      • Reverts with AsyncNonceIsReservedByAnotherService if reserved by different service
      • Marks nonce as used: asyncNonce[user][nonce] = true
    • Sync (isAsyncExec = false):
      • Verifies nonce matches nextSyncNonce[user]
      • Reverts with SyncNonceMismatch on mismatch
      • Increments sync nonce: ++nextSyncNonce[user]

Security Features

Replay Attack Prevention:

  • Atomic signature verification and nonce consumption
  • Service-specific validation prevents cross-service replay
  • Reserved nonces prevent service interference

Service Isolation:

  • Each service provides unique hashPayload
  • msg.sender (service address) is part of signature payload
  • Signatures cannot be reused across services

User Protection:

  • Optional UserValidator integration for compliance filtering
  • Origin executor restrictions for additional security
  • Consistent validation rules across all services
For Service Developers

When building a custom EVVM service, always call validateAndConsumeNonce BEFORE executing any state changes. This ensures signatures are valid and prevents replay attacks.


Nonce Reservation System

Core.sol provides a nonce reservation system allowing users to pre-allocate async nonces to specific services. This prevents race conditions and ensures deterministic execution ordering.

reserveAsyncNonce

Function Type: external
Function Signature: reserveAsyncNonce(uint256,address)

Reserves an async nonce exclusively for a specific service address.

Parameters

FieldTypeDescription
nonceuint256The async nonce value to reserve
serviceAddressaddressService contract that can use this nonce

Use Cases

  • Cross-chain operations: Reserve nonces for multi-step cross-chain transactions
  • Multi-signature workflows: Ensure specific executors process transactions
  • Service-specific queues: Create dedicated transaction queues per service
  • Front-running prevention: Block other services from using specific nonces

Workflow

  1. Service Validation: Checks that serviceAddress is not address(0). Reverts with InvalidServiceAddress if zero.
  2. Usage Check: Verifies nonce hasn't been used. Reverts with AsyncNonceAlreadyUsed if already consumed.
  3. Reservation Check: Ensures nonce isn't already reserved. Reverts with AsyncNonceAlreadyReserved if reserved.
  4. Reserve: Sets asyncNonceReservedPointers[msg.sender][nonce] = serviceAddress

Example

// Reserve nonces 100-105 for NameService operations
for (uint256 i = 100; i <= 105; i++) {
core.reserveAsyncNonce(i, nameServiceAddress);
}

// Now only NameService can consume these nonces for this user

revokeAsyncNonce

Function Type: external
Function Signature: revokeAsyncNonce(address,uint256)

Revokes a previously reserved async nonce, making it available for any service.

Parameters

FieldTypeDescription
useraddressAddress that reserved the nonce
nonceuint256The async nonce to revoke reservation for

Use Cases

  • Canceling operations: Free nonces from canceled transactions
  • Correcting mistakes: Fix accidental reservations
  • Reallocation: Reassign nonces to different services

Workflow

  1. Usage Check: Verifies nonce hasn't been used. Reverts with AsyncNonceAlreadyUsed if consumed.
  2. Reservation Check: Ensures nonce is currently reserved. Reverts with AsyncNonceNotReserved if not.
  3. Clear: Sets asyncNonceReservedPointers[user][nonce] = address(0)
Access Control

Currently, revokeAsyncNonce can be called by anyone. In production, consider implementing authorization checks to ensure only the user or authorized addresses can revoke reservations.


UserValidator System

Core.sol supports an optional UserValidator contract for transaction filtering and compliance requirements. This system allows blocking specific users from executing transactions without modifying Core.sol.

Overview

The UserValidator system provides:

  • Optional Filtering: Can be enabled/disabled without contract upgrades
  • Time-Delayed Governance: 1-day waiting period for validator changes
  • Flexible Implementation: Validator contract defines filtering logic
  • Ecosystem-Wide Effect: Affects all services using validateAndConsumeNonce

proposeUserValidator

Function Type: external (Admin only)
Function Signature: proposeUserValidator(address)

Proposes a new UserValidator contract address with a 1-day time-lock.

Parameters

FieldTypeDescription
newValidatoraddressAddress of proposed UserValidator contract

cancelUserValidatorProposal

Function Type: external (Admin only)
Function Signature: cancelUserValidatorProposal()

Cancels a pending UserValidator proposal before the time-lock expires.


acceptUserValidatorProposal

Function Type: external (Admin only)
Function Signature: acceptUserValidatorProposal()

Finalizes the UserValidator change after the 1-day time-lock period.

Requirements:

  • Time-lock period must have passed
  • Reverts with ProposalForUserValidatorNotReady if called too early

IUserValidator Interface

Custom UserValidator contracts must implement:

interface IUserValidator {
function canExecute(address user) external view returns (bool);
}

Implementation Examples:

// Whitelist-based validator
contract WhitelistValidator is IUserValidator {
mapping(address => bool) public whitelisted;

function canExecute(address user) external view returns (bool) {
return whitelisted[user];
}
}

// Blacklist-based validator
contract BlacklistValidator is IUserValidator {
mapping(address => bool) public blacklisted;

function canExecute(address user) external view returns (bool) {
return !blacklisted[user];
}
}

// KYC-based validator
contract KYCValidator is IUserValidator {
mapping(address => bool) public kycVerified;

function canExecute(address user) external view returns (bool) {
return kycVerified[user];
}
}
Integration with Services

When a UserValidator is active, validateAndConsumeNonce calls validator.canExecute(user) before processing any transaction. If it returns false, the transaction reverts with UserCannotExecuteTransaction.


For information on nonce getter functions, see: