diff --git a/certora/specs/Marketplace.spec b/certora/specs/Marketplace.spec index 64ba147..48f3564 100644 --- a/certora/specs/Marketplace.spec +++ b/certora/specs/Marketplace.spec @@ -5,7 +5,7 @@ using ERC20A as Token; methods { function Token.balanceOf(address) external returns (uint256) envfree; function Token.totalSupply() external returns (uint256) envfree; - function publicPeriodEnd(Periods.Period) external returns (uint64) envfree; + function publicPeriodEnd(Periods.Period) external returns (Marketplace.Timestamp) envfree; function generateSlotId(Marketplace.RequestId, uint64) external returns (Marketplace.SlotId) envfree; } diff --git a/contracts/Configuration.sol b/contracts/Configuration.sol index dd70be4..10d697a 100644 --- a/contracts/Configuration.sol +++ b/contracts/Configuration.sol @@ -20,8 +20,8 @@ struct CollateralConfig { } struct ProofConfig { - uint64 period; // proofs requirements are calculated per period (in seconds) - uint64 timeout; // mark proofs as missing before the timeout (in seconds) + Duration period; // proofs requirements are calculated per period (in seconds) + Duration timeout; // mark proofs as missing before the timeout (in seconds) uint8 downtime; // ignore this much recent blocks for proof requirements // Ensures the pointer does not remain in downtime for many consecutive // periods. For each period increase, move the pointer `pointerProduct` diff --git a/contracts/Periods.sol b/contracts/Periods.sol index 5e18ee1..189fb02 100644 --- a/contracts/Periods.sol +++ b/contracts/Periods.sol @@ -1,37 +1,45 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; +import "./Timestamps.sol"; + contract Periods { error Periods_InvalidSecondsPerPeriod(); - type Period is uint64; + type Period is uint40; - uint64 internal immutable _secondsPerPeriod; + Duration internal immutable _secondsPerPeriod; - constructor(uint64 secondsPerPeriod) { - if (secondsPerPeriod == 0) { + constructor(Duration secondsPerPeriod) { + if (secondsPerPeriod == Duration.wrap(0)) { revert Periods_InvalidSecondsPerPeriod(); } _secondsPerPeriod = secondsPerPeriod; } - function _periodOf(uint64 timestamp) internal view returns (Period) { - return Period.wrap(timestamp / _secondsPerPeriod); + function _periodOf(Timestamp timestamp) internal view returns (Period) { + return + Period.wrap( + Timestamp.unwrap(timestamp) / Duration.unwrap(_secondsPerPeriod) + ); } function _blockPeriod() internal view returns (Period) { - return _periodOf(uint64(block.timestamp)); + return _periodOf(Timestamps.currentTime()); } function _nextPeriod(Period period) internal pure returns (Period) { return Period.wrap(Period.unwrap(period) + 1); } - function _periodStart(Period period) internal view returns (uint64) { - return Period.unwrap(period) * _secondsPerPeriod; + function _periodStart(Period period) internal view returns (Timestamp) { + return + Timestamp.wrap( + Period.unwrap(period) * Duration.unwrap(_secondsPerPeriod) + ); } - function _periodEnd(Period period) internal view returns (uint64) { + function _periodEnd(Period period) internal view returns (Timestamp) { return _periodStart(_nextPeriod(period)); } diff --git a/contracts/Proofs.sol b/contracts/Proofs.sol index f48b377..87da0cc 100644 --- a/contracts/Proofs.sol +++ b/contracts/Proofs.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.28; import "./Configuration.sol"; import "./Requests.sol"; +import "./Timestamps.sol"; import "./Periods.sol"; import "./Groth16.sol"; @@ -11,6 +12,8 @@ import "./Groth16.sol"; * @notice Abstract contract that handles proofs tracking, validation and reporting functionality */ abstract contract Proofs is Periods { + using Timestamps for Timestamp; + error Proofs_InsufficientBlockHeight(); error Proofs_InvalidProof(); error Proofs_ProofAlreadySubmitted(); @@ -39,7 +42,7 @@ abstract contract Proofs is Periods { _verifier = verifier; } - mapping(SlotId => uint64) private _slotStarts; + mapping(SlotId => Timestamp) private _slotStarts; mapping(SlotId => uint64) private _missed; mapping(SlotId => mapping(Period => bool)) private _received; mapping(SlotId => mapping(Period => bool)) private _missing; @@ -73,7 +76,7 @@ abstract contract Proofs is Periods { * and saves the required probability. */ function _startRequiringProofs(SlotId id) internal { - _slotStarts[id] = uint64(block.timestamp); + _slotStarts[id] = Timestamps.currentTime(); } /** @@ -224,10 +227,10 @@ abstract contract Proofs is Periods { * - proof was already marked as missing */ function _markProofAsMissing(SlotId id, Period missedPeriod) internal { - uint256 end = _periodEnd(missedPeriod); - if (end >= block.timestamp) revert Proofs_PeriodNotEnded(); - if (block.timestamp >= end + _config.timeout) - revert Proofs_ValidationTimedOut(); + Timestamp end = _periodEnd(missedPeriod); + Timestamp current = Timestamps.currentTime(); + if (current <= end) revert Proofs_PeriodNotEnded(); + if (end.add(_config.timeout) <= current) revert Proofs_ValidationTimedOut(); if (_received[id][missedPeriod]) revert Proofs_ProofNotMissing(); if (!_isProofRequired(id, missedPeriod)) revert Proofs_ProofNotRequired(); if (_missing[id][missedPeriod]) revert Proofs_ProofAlreadyMarkedMissing();