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
| Field | Type | Description |
|---|---|---|
user | address | Address of the transaction signer |
hashPayload | bytes32 | Hash of the transaction parameters (generated by service-specific hash functions) |
originExecutor | address | Optional tx.origin restriction. Use address(0) to allow any origin |
nonce | uint256 | Nonce to validate and consume |
isAsyncExec | bool | true for asynchronous (parallel) nonces, false for synchronous (sequential) |
signature | bytes | User'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
-
Contract Verification: Validates that
msg.senderis a smart contract usingCAUtils.verifyIfCA(). Reverts withMsgSenderIsNotAContractif called by an EOA. -
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
userparameter - Reverts with
InvalidSignatureon mismatch
- Builds signature payload:
-
Origin Executor Validation: If
originExecutoris notaddress(0), checks thattx.originmatches. Reverts withOriginIsNotTheOriginExecutoron mismatch. -
User Validation: Checks if user is allowed to execute transactions via
canExecuteUserTransaction(user)(integrates with UserValidator if configured). Reverts withUserCannotExecuteTransactionif blocked. -
Nonce Management: Validates and consumes the nonce based on
isAsyncExec:- Async (isAsyncExec = true):
- Checks nonce status via
asyncNonceStatus(user, nonce) - Reverts with
AsyncNonceAlreadyUsedif already used - Reverts with
AsyncNonceIsReservedByAnotherServiceif reserved by different service - Marks nonce as used:
asyncNonce[user][nonce] = true
- Checks nonce status via
- Sync (isAsyncExec = false):
- Verifies nonce matches
nextSyncNonce[user] - Reverts with
SyncNonceMismatchon mismatch - Increments sync nonce:
++nextSyncNonce[user]
- Verifies nonce matches
- Async (isAsyncExec = true):
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
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
| Field | Type | Description |
|---|---|---|
nonce | uint256 | The async nonce value to reserve |
serviceAddress | address | Service 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
- Service Validation: Checks that
serviceAddressis notaddress(0). Reverts withInvalidServiceAddressif zero. - Usage Check: Verifies nonce hasn't been used. Reverts with
AsyncNonceAlreadyUsedif already consumed. - Reservation Check: Ensures nonce isn't already reserved. Reverts with
AsyncNonceAlreadyReservedif reserved. - 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
| Field | Type | Description |
|---|---|---|
user | address | Address that reserved the nonce |
nonce | uint256 | The 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
- Usage Check: Verifies nonce hasn't been used. Reverts with
AsyncNonceAlreadyUsedif consumed. - Reservation Check: Ensures nonce is currently reserved. Reverts with
AsyncNonceNotReservedif not. - Clear: Sets
asyncNonceReservedPointers[user][nonce] = address(0)
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
| Field | Type | Description |
|---|---|---|
newValidator | address | Address 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
ProposalForUserValidatorNotReadyif 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];
}
}
When a UserValidator is active, validateAndConsumeNonce calls validator.canExecute(user) before processing any transaction. If it returns false, the transaction reverts with UserCannotExecuteTransaction.
Related Functions
For information on nonce getter functions, see: