datahaven-xyz/datahaven · error
Permit expired
Error message
Permit expired
What it means
Reverts the EIP-2612 permit precompile call because the deadline parameter encoded in the signed permit authorization is in the past: the current chain timestamp (converted from milliseconds to Ethereum-style seconds) now exceeds the supplied deadline, so the signature's validity window has closed and the approval can no longer be executed.
Solutions
- Submit the permit transaction before the deadline specified in the signed message
- Re-sign the permit with a later deadline (or the typical max uint256 for no expiry) and submit the new signature
- Synchronize the signer's clock and deadline calculation with the chain's timestamp, remembering the chain stores time in milliseconds while EIP-2612 deadlines are in seconds
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at operator/precompiles/erc20-balances/src/eip2612.rs:119 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of datahaven-xyz/datahaven@edcb13dbbc (2026-09-13).
Data as JSON: /api/errors/7369a8b1c84fa6b2.
Report an issue: GitHub.
Appendix: source
Thrown at operator/precompiles/erc20-balances/src/eip2612.rs:119
spender: Address,
value: U256,
deadline: U256,
v: u8,
r: H256,
s: H256,
) -> EvmResult {
// NoncesStorage: Blake2_128(16) + contract(20) + Blake2_128(16) + owner(20) + nonce(32)
handle.record_db_read::<Runtime>(104)?;
let owner: H160 = owner.into();
let spender: H160 = spender.into();
// Blockchain time is in ms while Ethereum use second timestamps.
let timestamp: u128 =
<Runtime as pallet_evm::Config>::Timestamp::now().unique_saturated_into();
let timestamp: U256 = U256::from(timestamp / 1000);
ensure!(deadline >= timestamp, revert("Permit expired"));
let nonce = NoncesStorage::<Instance>::get(owner);
let permit = Self::generate_permit(
handle.context().address,
owner,
spender,
value,
nonce,
deadline,
);
let mut sig = [0u8; 65];
sig[0..32].copy_from_slice(r.as_bytes());
sig[32..64].copy_from_slice(s.as_bytes());
sig[64] = v;
let signer = sp_io::crypto::secp256k1_ecdsa_recover(&sig, &permit)View on GitHub (pinned to edcb13dbbc)