-
Notifications
You must be signed in to change notification settings - Fork 17
feat(pricing): make pricing constants mutable with owner-controlled u… #325
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
517cfa3
feat(pricing): make pricing constants mutable with owner-controlled u…
rjan90 9efacd0
fix: make update-abi
rjan90 58df775
chore: make abi-gen
rjan90 79ada50
feat: integrate floor pricing with mutable pricing system
rjan90 f4b0e12
Update service_contracts/src/FilecoinWarmStorageService.sol
rjan90 6fae6e1
Update service_contracts/src/FilecoinWarmStorageService.sol
rjan90 b0667c7
Update service_contracts/src/FilecoinWarmStorageService.sol
rjan90 3d6388b
refactor: replace string with enum in PriceExceedsMaximum error
rjan90 09afd06
mv getCurrentPricingRates to View (#330)
wjmelements File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -97,6 +97,8 @@ contract FilecoinWarmStorageService is | |
| event ProviderApproved(uint256 indexed providerId); | ||
| event ProviderUnapproved(uint256 indexed providerId); | ||
|
|
||
| event PricingUpdated(uint256 storagePrice, uint256 minimumRate); | ||
|
|
||
| // ========================================================================= | ||
| // Structs | ||
|
|
||
|
|
@@ -193,16 +195,18 @@ contract FilecoinWarmStorageService is | |
| bytes32 private constant WITH_CDN_STRING_STORAGE_REPR = | ||
| 0x7769746843444e0000000000000000000000000000000000000000000000000e; | ||
|
|
||
| // Pricing constants | ||
| uint256 private immutable STORAGE_PRICE_PER_TIB_PER_MONTH; // 2.5 USDFC per TiB per month without CDN with correct decimals | ||
| // Pricing constants (CDN egress pricing is immutable) | ||
| uint256 private immutable CDN_EGRESS_PRICE_PER_TIB; // 7 USDFC per TiB of CDN egress | ||
| uint256 private immutable CACHE_MISS_EGRESS_PRICE_PER_TIB; // 7 USDFC per TiB of cache miss egress | ||
| uint256 private immutable MINIMUM_STORAGE_RATE_PER_MONTH; // 0.06 USDFC per month minimum pricing floor | ||
|
|
||
| // Fixed lockup amounts for CDN rails | ||
| uint256 private immutable DEFAULT_CDN_LOCKUP_AMOUNT; // 0.7 USDFC | ||
| uint256 private immutable DEFAULT_CACHE_MISS_LOCKUP_AMOUNT; // 0.3 USDFC | ||
|
|
||
| // Maximum pricing bounds (4x initial values) | ||
| uint256 private immutable MAX_STORAGE_PRICE_PER_TIB_PER_MONTH; // 10 USDFC (4x 2.5) | ||
| uint256 private immutable MAX_MINIMUM_STORAGE_RATE_PER_MONTH; // 0.24 USDFC (4x 0.06) | ||
|
|
||
| // Token decimals | ||
| uint8 private immutable TOKEN_DECIMALS; | ||
|
|
||
|
|
@@ -272,6 +276,10 @@ contract FilecoinWarmStorageService is | |
|
|
||
| PlannedUpgrade private nextUpgrade; | ||
|
|
||
| // Pricing rates (mutable for future adjustments) | ||
| uint256 private storagePricePerTibPerMonth; | ||
| uint256 private minimumStorageRatePerMonth; | ||
|
|
||
| event UpgradeAnnounced(PlannedUpgrade plannedUpgrade); | ||
|
|
||
| // ========================================================================= | ||
|
|
@@ -328,11 +336,13 @@ contract FilecoinWarmStorageService is | |
| // Read token decimals from the USDFC token contract | ||
| TOKEN_DECIMALS = _usdfc.decimals(); | ||
|
|
||
| // Initialize the fee constants based on the actual token decimals | ||
| STORAGE_PRICE_PER_TIB_PER_MONTH = (5 * 10 ** TOKEN_DECIMALS) / 2; // 2.5 USDFC | ||
| // Initialize the immutable pricing constants based on the actual token decimals | ||
| CDN_EGRESS_PRICE_PER_TIB = 7 * 10 ** TOKEN_DECIMALS; // 7 USDFC per TiB | ||
| CACHE_MISS_EGRESS_PRICE_PER_TIB = 7 * 10 ** TOKEN_DECIMALS; // 7 USDFC per TiB | ||
| MINIMUM_STORAGE_RATE_PER_MONTH = (6 * 10 ** TOKEN_DECIMALS) / 100; // 0.06 USDFC minimum | ||
|
|
||
| // Initialize maximum pricing bounds (4x initial values) | ||
| MAX_STORAGE_PRICE_PER_TIB_PER_MONTH = 10 * 10 ** TOKEN_DECIMALS; // 10 USDFC (4x 2.5) | ||
| MAX_MINIMUM_STORAGE_RATE_PER_MONTH = (24 * 10 ** TOKEN_DECIMALS) / 100; // 0.24 USDFC (4x 0.06) | ||
|
|
||
| // Initialize the lockup constants based on the actual token decimals | ||
| DEFAULT_CDN_LOCKUP_AMOUNT = (7 * 10 ** TOKEN_DECIMALS) / 10; // 0.7 USDFC | ||
|
|
@@ -383,6 +393,10 @@ contract FilecoinWarmStorageService is | |
|
|
||
| // Set commission rate | ||
| serviceCommissionBps = 0; // 0% | ||
|
|
||
| // Initialize mutable pricing variables | ||
| storagePricePerTibPerMonth = (5 * 10 ** TOKEN_DECIMALS) / 2; // 2.5 USDFC | ||
| minimumStorageRatePerMonth = (6 * 10 ** TOKEN_DECIMALS) / 100; // 0.06 USDFC | ||
| } | ||
|
|
||
| function announcePlannedUpgrade(PlannedUpgrade calldata plannedUpgrade) external onlyOwner { | ||
|
|
@@ -467,6 +481,40 @@ contract FilecoinWarmStorageService is | |
| serviceCommissionBps = newCommissionBps; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Updates the pricing rates for storage services | ||
| * @dev Only callable by the contract owner. Pass 0 to keep existing value unchanged. | ||
| * Price updates apply immediately to existing payment rails when they're recalculated | ||
| * (e.g., during piece additions/deletions or proving period updates). | ||
| * Maximum allowed values: 10 USDFC for storage, 0.24 USDFC for minimum rate. | ||
| * @param newStoragePrice New storage price per TiB per month (0 = no change, max 10 USDFC) | ||
| * @param newMinimumRate New minimum monthly storage rate (0 = no change, max 0.24 USDFC) | ||
| */ | ||
| function updatePricing(uint256 newStoragePrice, uint256 newMinimumRate) external onlyOwner { | ||
| require(newStoragePrice > 0 || newMinimumRate > 0, Errors.AtLeastOnePriceMustBeNonZero()); | ||
|
|
||
| if (newStoragePrice > 0) { | ||
| require( | ||
| newStoragePrice <= MAX_STORAGE_PRICE_PER_TIB_PER_MONTH, | ||
| Errors.PriceExceedsMaximum( | ||
| Errors.PriceType.Storage, MAX_STORAGE_PRICE_PER_TIB_PER_MONTH, newStoragePrice | ||
| ) | ||
| ); | ||
| storagePricePerTibPerMonth = newStoragePrice; | ||
| } | ||
| if (newMinimumRate > 0) { | ||
| require( | ||
| newMinimumRate <= MAX_MINIMUM_STORAGE_RATE_PER_MONTH, | ||
| Errors.PriceExceedsMaximum( | ||
| Errors.PriceType.MinimumRate, MAX_MINIMUM_STORAGE_RATE_PER_MONTH, newMinimumRate | ||
| ) | ||
| ); | ||
| minimumStorageRatePerMonth = newMinimumRate; | ||
| } | ||
|
|
||
| emit PricingUpdated(storagePricePerTibPerMonth, minimumStorageRatePerMonth); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Adds a provider ID to the approved list | ||
| * @dev Only callable by the contract owner. Reverts if already approved. | ||
|
|
@@ -1097,7 +1145,7 @@ contract FilecoinWarmStorageService is | |
| /// @param payer The address of the payer | ||
| function validatePayerOperatorApprovalAndFunds(FilecoinPayV1 payments, address payer) internal view { | ||
| // Calculate required lockup for minimum pricing | ||
| uint256 minimumLockupRequired = (MINIMUM_STORAGE_RATE_PER_MONTH * DEFAULT_LOCKUP_PERIOD) / EPOCHS_PER_MONTH; | ||
| uint256 minimumLockupRequired = (minimumStorageRatePerMonth * DEFAULT_LOCKUP_PERIOD) / EPOCHS_PER_MONTH; | ||
|
|
||
| // Check that payer has sufficient available funds | ||
| (,, uint256 availableFunds,) = payments.getAccountInfoIfSettled(usdfcTokenAddress, payer); | ||
|
|
@@ -1120,7 +1168,7 @@ contract FilecoinWarmStorageService is | |
| require(isApproved, Errors.OperatorNotApproved(payer, address(this))); | ||
|
|
||
| // Calculate minimum rate per epoch | ||
| uint256 minimumRatePerEpoch = MINIMUM_STORAGE_RATE_PER_MONTH / EPOCHS_PER_MONTH; | ||
| uint256 minimumRatePerEpoch = minimumStorageRatePerMonth / EPOCHS_PER_MONTH; | ||
|
|
||
| // Verify rate allowance is sufficient | ||
| require( | ||
|
|
@@ -1241,10 +1289,10 @@ contract FilecoinWarmStorageService is | |
| */ | ||
| function _calculateStorageRate(uint256 totalBytes) internal view returns (uint256) { | ||
| // Calculate natural size-based rate | ||
| uint256 naturalRate = calculateStorageSizeBasedRatePerEpoch(totalBytes, STORAGE_PRICE_PER_TIB_PER_MONTH); | ||
| uint256 naturalRate = calculateStorageSizeBasedRatePerEpoch(totalBytes, storagePricePerTibPerMonth); | ||
|
|
||
| // Calculate minimum rate (floor price converted to per-epoch) | ||
| uint256 minimumRate = MINIMUM_STORAGE_RATE_PER_MONTH / EPOCHS_PER_MONTH; | ||
| uint256 minimumRate = minimumStorageRatePerMonth / EPOCHS_PER_MONTH; | ||
|
|
||
| // Return whichever is higher: natural rate or minimum rate | ||
| return naturalRate > minimumRate ? naturalRate : minimumRate; | ||
|
|
@@ -1341,22 +1389,31 @@ contract FilecoinWarmStorageService is | |
| */ | ||
| function getServicePrice() external view returns (ServicePricing memory pricing) { | ||
| pricing = ServicePricing({ | ||
| pricePerTiBPerMonthNoCDN: STORAGE_PRICE_PER_TIB_PER_MONTH, | ||
| pricePerTiBPerMonthNoCDN: storagePricePerTibPerMonth, | ||
| pricePerTiBCdnEgress: CDN_EGRESS_PRICE_PER_TIB, | ||
| pricePerTiBCacheMissEgress: CACHE_MISS_EGRESS_PRICE_PER_TIB, | ||
| tokenAddress: usdfcTokenAddress, | ||
| epochsPerMonth: EPOCHS_PER_MONTH, | ||
| minimumPricePerMonth: MINIMUM_STORAGE_RATE_PER_MONTH | ||
| minimumPricePerMonth: minimumStorageRatePerMonth | ||
| }); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Get the current pricing rates | ||
| * @return storagePrice Current storage price per TiB per month | ||
| * @return minimumRate Current minimum monthly storage rate | ||
| */ | ||
| function getCurrentPricingRates() external view returns (uint256 storagePrice, uint256 minimumRate) { | ||
| return (storagePricePerTibPerMonth, minimumStorageRatePerMonth); | ||
|
||
| } | ||
|
|
||
| /** | ||
| * @notice Get the effective rates after commission for both service types | ||
| * @return serviceFee Service fee (per TiB per month) | ||
| * @return spPayment SP payment (per TiB per month) | ||
| */ | ||
| function getEffectiveRates() external view returns (uint256 serviceFee, uint256 spPayment) { | ||
| uint256 total = STORAGE_PRICE_PER_TIB_PER_MONTH; | ||
| uint256 total = storagePricePerTibPerMonth; | ||
|
|
||
| serviceFee = (total * serviceCommissionBps) / COMMISSION_MAX_BPS; | ||
| spPayment = total - serviceFee; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love having
ifs here and am not sure "Pass 0 to keep existing value unchanged." is all that helpful. It might help with footguns, perhaps, but now there's no way to set a floor of0, we'd have to use1to be our floor if we decided to undo that.But, not a big deal if we're just trying to get this over the line at this point.