|
| 1 | +## Specification |
| 2 | + |
| 3 | +### FilBeamOperator (Operator) Contract |
| 4 | + |
| 5 | +#### Overview |
| 6 | + |
| 7 | +The Filecoin Beam (FilBeamOperator) contract is responsible for managing CDN (cache-hit) and cache-miss data set egress usage data reported by the off-chain rollup worker and settlement of payment rails. Payment rails are managed by the Filecoin Warm Storage Service (FWSS) contract. The FilBeamOperator contract interacts with the FWSS contract to facilitate fund transfers based on reported usage data with rate-based billing. |
| 8 | + |
| 9 | +#### Initialization |
| 10 | +**Method**: `constructor(address fwssAddress, uint256 _cdnRatePerByte, uint256 _cacheMissRatePerByte, address _filBeamOperatorController)` |
| 11 | + |
| 12 | +**Parameters**: |
| 13 | +- `address fwssAddress`: Address of the FWSS contract |
| 14 | +- `uint256 _cdnRatePerByte`: Rate per byte for CDN usage billing (must be > 0) |
| 15 | +- `uint256 _cacheMissRatePerByte`: Rate per byte for cache-miss usage billing (must be > 0) |
| 16 | +- `address _filBeamOperatorController`: Address authorized to report usage and terminate payment rails |
| 17 | + |
| 18 | +**Owner**: |
| 19 | +- The deployer (msg.sender) automatically becomes the contract owner |
| 20 | + |
| 21 | +**Validations**: |
| 22 | +- FWSS address cannot be zero address |
| 23 | +- Both rates must be greater than zero |
| 24 | +- FilBeamOperator controller cannot be zero address |
| 25 | + |
| 26 | +#### Data Structure |
| 27 | +**DataSetUsage Struct**: |
| 28 | +- `uint256 cdnAmount`: Accumulated CDN settlement amount between settlements (calculated at report time) |
| 29 | +- `uint256 cacheMissAmount`: Accumulated cache-miss settlement amount between settlements (calculated at report time) |
| 30 | +- `uint256 maxReportedEpoch`: Highest epoch number reported for this dataset (0 indicates uninitialized dataset) |
| 31 | +- `uint256 lastCDNSettlementEpoch`: Last epoch settled for CDN payment rail |
| 32 | +- `uint256 lastCacheMissSettlementEpoch`: Last epoch settled for cache-miss payment rail |
| 33 | + |
| 34 | +#### Usage Reporting |
| 35 | + |
| 36 | +**Method**: `recordUsageRollups(uint256 toEpoch, uint256[] dataSetIds, uint256[] cdnBytesUsed, uint256[] cacheMissBytesUsed)` |
| 37 | + |
| 38 | +- **Access**: FilBeamOperator controller only |
| 39 | +- **Purpose**: Accepts multiple usage reports in a single transaction for improved gas efficiency |
| 40 | +- **toEpoch Parameter**: Single epoch number up to which usage is reported for all datasets in the batch |
| 41 | +- **Epoch Requirements**: |
| 42 | + - Epoch must be > 0 |
| 43 | + - Epoch must be greater than previously reported epochs for each dataset |
| 44 | + - Each epoch can only be reported once per dataset |
| 45 | +- **Usage Requirements**: |
| 46 | + - Usage is converted to settlement amounts using current rates at report time |
| 47 | + - Amounts accumulate in the dataset between settlements |
| 48 | +- **Parameter Requirements**: |
| 49 | + - All arrays must have equal length |
| 50 | + - All datasets in the batch report usage up to the same toEpoch |
| 51 | +- **Batch Processing**: |
| 52 | + - Processes all reports atomically (all succeed or all fail) |
| 53 | + - Maintains epoch ordering and validation rules per dataset |
| 54 | + - Prevents duplicate epoch reporting within the batch |
| 55 | +- **State Updates**: |
| 56 | + - Initialize dataset on first report (sets maxReportedEpoch to non-zero value) |
| 57 | + - Calculate amounts: `cdnAmount = cdnBytesUsed * cdnRatePerByte`, `cacheMissAmount = cacheMissBytesUsed * cacheMissRatePerByte` |
| 58 | + - Accumulate calculated amounts |
| 59 | + - Update max reported epoch to toEpoch |
| 60 | +- **Events**: Emits individual `UsageReported` event for each processed report (contains bytes, not amounts) |
| 61 | + |
| 62 | +#### Payment Rail Settlement |
| 63 | + |
| 64 | +**Method**: `settleCDNPaymentRails(uint256[] dataSetIds)` |
| 65 | + |
| 66 | +- **Access**: Publicly callable (anyone can trigger settlement) |
| 67 | +- **Purpose**: Settles CDN payment rails for multiple datasets in a single transaction |
| 68 | +- **Calculation Period**: From last CDN settlement epoch + 1 to max reported epoch |
| 69 | +- **Settlement Logic**: |
| 70 | + - Retrieves rail ID from FWSS DataSetInfo |
| 71 | + - Fetches rail details from Payments contract to get `lockupFixed` |
| 72 | + - Calculates settleable amount: `min(accumulated_amount, rail.lockupFixed)` |
| 73 | + - Only calls FWSS contract if settleable amount > 0 |
| 74 | + - Reduces accumulated CDN amount by settled amount (may leave remainder) |
| 75 | +- **State Updates**: |
| 76 | + - Update last CDN settlement epoch to max reported epoch |
| 77 | + - Reduce accumulated amount by settled amount (not reset to zero if partial) |
| 78 | +- **Requirements**: None - gracefully skips datasets that cannot be settled |
| 79 | +- **Batch Processing**: |
| 80 | + - Processes each dataset independently (non-reverting) |
| 81 | + - Skips uninitialized datasets or those without new usage |
| 82 | + - Skips datasets without valid rail configuration |
| 83 | + - Continues processing even if some datasets cannot be settled |
| 84 | +- **Partial Settlement**: Supports partial settlements when `accumulated_amount > lockupFixed` |
| 85 | +- **Events**: Emits `CDNSettlement` event with actual settled amount (may be less than accumulated) |
| 86 | +- **Independent Operation**: Can be called independently of cache-miss settlement |
| 87 | + |
| 88 | +**Method**: `settleCacheMissPaymentRails(uint256[] dataSetIds)` |
| 89 | + |
| 90 | +- **Access**: Publicly callable (typically called by Storage Providers) |
| 91 | +- **Purpose**: Settles cache-miss payment rails for multiple datasets in a single transaction |
| 92 | +- **Calculation Period**: From last cache-miss settlement epoch + 1 to max reported epoch |
| 93 | +- **Settlement Logic**: |
| 94 | + - Retrieves rail ID from FWSS DataSetInfo |
| 95 | + - Fetches rail details from Payments contract to get `lockupFixed` |
| 96 | + - Calculates settleable amount: `min(accumulated_amount, rail.lockupFixed)` |
| 97 | + - Only calls FWSS contract if settleable amount > 0 |
| 98 | + - Reduces accumulated cache-miss amount by settled amount (may leave remainder) |
| 99 | +- **State Updates**: |
| 100 | + - Update last cache-miss settlement epoch to max reported epoch |
| 101 | + - Reduce accumulated amount by settled amount (not reset to zero if partial) |
| 102 | +- **Requirements**: None - gracefully skips datasets that cannot be settled |
| 103 | +- **Batch Processing**: |
| 104 | + - Processes each dataset independently (non-reverting) |
| 105 | + - Skips uninitialized datasets or those without new usage |
| 106 | + - Skips datasets without valid rail configuration |
| 107 | + - Continues processing even if some datasets cannot be settled |
| 108 | +- **Partial Settlement**: Supports partial settlements when `accumulated_amount > lockupFixed` |
| 109 | +- **Events**: Emits `CacheMissSettlement` event with actual settled amount (may be less than accumulated) |
| 110 | +- **Independent Operation**: Can be called independently of CDN settlement |
| 111 | + |
| 112 | +#### Payment Rail Termination |
| 113 | +**Method**: `terminateCDNPaymentRails(uint256 dataSetId)` |
| 114 | + |
| 115 | +- **Access**: FilBeamOperator controller only |
| 116 | +- **Requirements**: Dataset must be initialized |
| 117 | +- **Process**: Forward termination call to FWSS contract |
| 118 | +- **Events**: Emits `PaymentRailsTerminated` event |
| 119 | + |
| 120 | +#### Data Access |
| 121 | +**Method**: `getDataSetUsage(uint256 dataSetId)` |
| 122 | + |
| 123 | +**Returns**: |
| 124 | +- `uint256 cdnAmount`: Current accumulated CDN settlement amount |
| 125 | +- `uint256 cacheMissAmount`: Current accumulated cache-miss settlement amount |
| 126 | +- `uint256 maxReportedEpoch`: Highest reported epoch (0 indicates uninitialized dataset) |
| 127 | +- `uint256 lastCDNSettlementEpoch`: Last CDN settlement epoch |
| 128 | +- `uint256 lastCacheMissSettlementEpoch`: Last cache-miss settlement epoch |
| 129 | + |
| 130 | +#### Ownership Management |
| 131 | +**Method**: `transferOwnership(address newOwner)` |
| 132 | + |
| 133 | +- **Access**: Contract owner only |
| 134 | +- **Requirements**: New owner cannot be zero address |
| 135 | +- **Purpose**: Transfer contract ownership |
| 136 | + |
| 137 | +#### FilBeamOperator Controller Management |
| 138 | +**Method**: `setFilBeamOperatorController(address _filBeamOperatorController)` |
| 139 | + |
| 140 | +- **Access**: Contract owner only |
| 141 | +- **Requirements**: FilBeamOperator controller cannot be zero address |
| 142 | +- **Purpose**: Update the authorized address for usage reporting and payment rail termination |
| 143 | +- **Events**: Emits `FilBeamOperatorControllerUpdated` event |
| 144 | + |
| 145 | +#### Events |
| 146 | +- `UsageReported(uint256 indexed dataSetId, uint256 indexed fromEpoch, uint256 indexed toEpoch, uint256 cdnBytesUsed, uint256 cacheMissBytesUsed)` |
| 147 | +- `CDNSettlement(uint256 indexed dataSetId, uint256 fromEpoch, uint256 toEpoch, uint256 cdnAmount)` |
| 148 | +- `CacheMissSettlement(uint256 indexed dataSetId, uint256 fromEpoch, uint256 toEpoch, uint256 cacheMissAmount)` |
| 149 | +- `PaymentRailsTerminated(uint256 indexed dataSetId)` |
| 150 | +- `FilBeamOperatorControllerUpdated(address indexed oldController, address indexed newController)` |
| 151 | + |
| 152 | +#### Access Control |
| 153 | +- **Owner**: Address authorized to manage contract ownership and set FilBeamOperator controller |
| 154 | +- **FilBeamOperator Controller**: Address authorized to report usage and terminate payment rails |
| 155 | + |
| 156 | +#### Error Conditions |
| 157 | +- `OwnableUnauthorizedAccount(address)`: Caller is not the contract owner |
| 158 | +- `Unauthorized()`: Caller is not the FilBeamOperator controller |
| 159 | +- `InvalidEpoch()`: Invalid epoch number or ordering (used in usage reporting) |
| 160 | +- `InvalidUsageAmount()`: Invalid array lengths in batch operations |
| 161 | +- `InvalidRate()`: Invalid rate configuration (zero rates at deployment) |
| 162 | +- `InvalidAddress()`: Invalid address (zero address) provided |
| 163 | + |
| 164 | +### Filecoin Warm Storage Service (FWSS) Contract Interface |
| 165 | + |
| 166 | +**Method**: `settleFilBeamPaymentRails(uint256 dataSetId, uint256 cdnAmount, uint256 cacheMissAmount)` |
| 167 | +- **Purpose**: Settle CDN or cache-miss payment rails based on calculated amounts |
| 168 | +- **Access**: Callable only by FilBeamOperator contract |
| 169 | +- **Parameters**: Either cdnAmount or cacheMissAmount will be zero depending on settlement type |
| 170 | + |
| 171 | +**Method**: `terminateCDNPaymentRails(uint256 dataSetId)` |
| 172 | +- **Purpose**: Terminate CDN payment rails for a specific dataset |
| 173 | +- **Access**: Callable only by FilBeamOperator contract |
| 174 | + |
| 175 | +### Key Implementation Features |
| 176 | + |
| 177 | +#### Rate-Based Settlement |
| 178 | +- Immutable rates per byte for both CDN and cache-miss usage set at contract deployment |
| 179 | +- Settlement amounts calculated at report time as: `usage * rate` |
| 180 | +- Rates cannot be changed after deployment, ensuring predictable pricing |
| 181 | + |
| 182 | +#### Independent Settlement Rails |
| 183 | +- CDN and cache-miss settlements operate independently |
| 184 | +- Each rail tracks its own settlement epoch |
| 185 | +- Allows flexible settlement patterns for different stakeholders |
| 186 | + |
| 187 | +#### Amount Accumulation |
| 188 | +- Settlement amounts (calculated at report time) accumulate between settlements |
| 189 | +- Only unsettled amounts are stored in contract state |
| 190 | +- Settlement reduces accumulated amounts by settled amount (supports partial settlements) |
| 191 | + |
| 192 | +#### Epoch Management |
| 193 | +- Strict epoch ordering enforcement |
| 194 | +- Prevents duplicate epoch reporting |
| 195 | +- Supports batched reporting of multiple epochs via `recordUsageRollups` method for gas efficiency |
| 196 | +- Independent epoch tracking per dataset |
| 197 | + |
| 198 | +#### Payments Contract Integration |
| 199 | +- Integrates with external Payments contract to enforce lockup limits |
| 200 | +- Retrieves rail information including `lockupFixed` to determine maximum settleable amount |
| 201 | +- Supports partial settlements when accumulated amount exceeds available lockup |
| 202 | +- Gracefully handles missing or invalid rails by skipping settlement |
| 203 | +- Multiple settlement calls may be required to fully settle large accumulated amounts |
0 commit comments