@@ -9,8 +9,6 @@ import {ERC1967Utils} from "../lib/openzeppelin-contracts/contracts/proxy/ERC196
99import {Initializable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol " ;
1010import {UUPSUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/UUPSUpgradeable.sol " ;
1111import {OwnableUpgradeable} from "../lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol " ;
12- import {IPyth} from "@pythnetwork/pyth-sdk-solidity/IPyth.sol " ;
13- import {PythStructs} from "@pythnetwork/pyth-sdk-solidity/PythStructs.sol " ;
1412import {IPDPTypes} from "./interfaces/IPDPTypes.sol " ;
1513
1614/// @title PDPListener
@@ -46,10 +44,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
4644 uint256 public constant MAX_ENQUEUED_REMOVALS = 2000 ;
4745 address public constant RANDOMNESS_PRECOMPILE = 0xfE00000000000000000000000000000000000006 ;
4846 uint256 public constant EXTRA_DATA_MAX_SIZE = 2048 ;
49- IPyth public constant PYTH = IPyth (0xA2aa501b19aff244D90cc15a4Cf739D2725B5729 );
50-
51- // FIL/USD price feed query ID on the Pyth network
52- bytes32 public constant FIL_USD_PRICE_FEED_ID = 0x150ac9b959aee0051e4091f0ef5216d941f590e1c5e7f91cf7635b5c11628c0e ;
47+ uint256 public constant SECONDS_IN_DAY = 86400 ;
5348 uint256 public constant NO_CHALLENGE_SCHEDULED = 0 ;
5449 uint256 public constant NO_PROVEN_EPOCH = 0 ;
5550
@@ -64,7 +59,8 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
6459 event PiecesAdded (uint256 indexed setId , uint256 [] pieceIds , Cids.Cid[] pieceCids );
6560 event PiecesRemoved (uint256 indexed setId , uint256 [] pieceIds );
6661
67- event ProofFeePaid (uint256 indexed setId , uint256 fee , uint64 price , int32 expo );
62+ event ProofFeePaid (uint256 indexed setId , uint256 fee );
63+ event FeeUpdateProposed (uint256 currentFee , uint256 newFee , uint256 effectiveTime );
6864
6965 event PossessionProven (uint256 indexed setId , IPDPTypes.PieceIdAndOffset[] challenges );
7066 event NextProvingPeriod (uint256 indexed setId , uint256 challengeEpoch , uint256 leafCount );
@@ -142,6 +138,15 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
142138 mapping (uint256 => address ) dataSetProposedStorageProvider;
143139 mapping (uint256 => uint256 ) dataSetLastProvenEpoch;
144140
141+ // Packed fee status
142+ struct FeeStatus {
143+ uint96 currentFeePerTiB;
144+ uint96 nextFeePerTiB;
145+ uint64 transitionTime;
146+ }
147+
148+ FeeStatus private feeStatus;
149+
145150 // Methods
146151
147152 /// @custom:oz-upgrades-unsafe-allow constructor
@@ -154,6 +159,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
154159 __UUPSUpgradeable_init ();
155160 challengeFinality = _challengeFinality;
156161 nextDataSetId = 1 ; // Data sets start at 1
162+ feeStatus.nextFeePerTiB = PDPFees.DEFAULT_FEE_PER_TIB;
157163 }
158164
159165 string public constant VERSION = "2.1.0 " ;
@@ -575,7 +581,7 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
575581 //
576582 // (add 32 bytes to the `callDataSize` to also account for the `setId` calldata param)
577583 uint256 gasUsed = (initialGas - gasleft ()) + ((calculateCallDataSize (proofs) + 32 ) * 1300 );
578- uint256 refund = calculateAndBurnProofFee (setId, gasUsed );
584+ uint256 refund = calculateAndBurnProofFee (setId);
579585
580586 {
581587 address listenerAddr = dataSetListener[setId];
@@ -595,29 +601,43 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
595601 }
596602 }
597603
598- function calculateProofFee (uint256 setId , uint256 estimatedGasFee ) public view returns (uint256 ) {
604+ function calculateProofFee (uint256 setId ) public view returns (uint256 ) {
599605 uint256 rawSize = 32 * challengeRange[setId];
600- (uint64 filUsdPrice , int32 filUsdPriceExpo ) = getFILUSDPrice ();
606+ return calculateProofFeeForSize (rawSize);
607+ }
601608
602- return PDPFees. proofFeeWithGasFeeBound (
603- estimatedGasFee, filUsdPrice, filUsdPriceExpo, rawSize, block . number - dataSetLastProvenEpoch[setId]
604- );
609+ function calculateProofFeeForSize ( uint256 rawSize ) public view returns ( uint256 ) {
610+ require (rawSize > 0 , " failed to validate: raw size must be greater than 0 " );
611+ return PDPFees. calculateProofFee (rawSize, _currentFeePerTiB () );
605612 }
606613
607- function calculateAndBurnProofFee (uint256 setId , uint256 gasUsed ) internal returns (uint256 refund ) {
608- uint256 estimatedGasFee = gasUsed * block .basefee ;
614+ function calculateAndBurnProofFee (uint256 setId ) internal returns (uint256 refund ) {
609615 uint256 rawSize = 32 * challengeRange[setId];
610- ( uint64 filUsdPrice , int32 filUsdPriceExpo ) = getFILUSDPrice ( );
616+ uint256 proofFee = calculateProofFeeForSize (rawSize );
611617
612- uint256 proofFee = PDPFees.proofFeeWithGasFeeBound (
613- estimatedGasFee, filUsdPrice, filUsdPriceExpo, rawSize, block .number - dataSetLastProvenEpoch[setId]
614- );
615618 burnFee (proofFee);
616- emit ProofFeePaid (setId, proofFee, filUsdPrice, filUsdPriceExpo );
619+ emit ProofFeePaid (setId, proofFee);
617620
618621 return msg .value - proofFee; // burnFee asserts that proofFee <= msg.value;
619622 }
620623
624+ function _currentFeePerTiB () internal view returns (uint96 ) {
625+ return block .timestamp >= feeStatus.transitionTime ? feeStatus.nextFeePerTiB : feeStatus.currentFeePerTiB;
626+ }
627+
628+ // Public getters for packed fee status
629+ function feePerTiB () public view returns (uint96 ) {
630+ return _currentFeePerTiB ();
631+ }
632+
633+ function proposedFeePerTiB () public view returns (uint96 ) {
634+ return feeStatus.nextFeePerTiB;
635+ }
636+
637+ function feeEffectiveTime () public view returns (uint64 ) {
638+ return feeStatus.transitionTime;
639+ }
640+
621641 function calculateCallDataSize (IPDPTypes.Proof[] calldata proofs ) internal pure returns (uint256 ) {
622642 uint256 callDataSize = 0 ;
623643 for (uint256 i = 0 ; i < proofs.length ; i++ ) {
@@ -837,10 +857,15 @@ contract PDPVerifier is Initializable, UUPSUpgradeable, OwnableUpgradeable {
837857 return BitOps.ctz (index + 1 );
838858 }
839859
840- // Add function to get FIL/USD price
841- function getFILUSDPrice () public view returns (uint64 , int32 ) {
842- PythStructs.Price memory priceData = PYTH.getPriceUnsafe (FIL_USD_PRICE_FEED_ID);
843- require (priceData.price > 0 , "failed to validate: price must be greater than 0 " );
844- return (uint64 (priceData.price), priceData.expo);
860+ /// @notice Proposes a new proof fee with 7-day delay
861+ /// @param newFeePerTiB The new fee per TiB in AttoFIL
862+ function updateProofFee (uint256 newFeePerTiB ) external onlyOwner {
863+ // Auto-commit any pending update that has reached its transition time
864+ if (block .timestamp >= feeStatus.transitionTime) {
865+ feeStatus.currentFeePerTiB = feeStatus.nextFeePerTiB;
866+ }
867+ feeStatus.nextFeePerTiB = uint96 (newFeePerTiB);
868+ feeStatus.transitionTime = uint64 (block .timestamp + 7 days);
869+ emit FeeUpdateProposed (feeStatus.currentFeePerTiB, newFeePerTiB, feeStatus.transitionTime);
845870 }
846871}
0 commit comments