2022-02-16 09:50:00 +00:00
// SPDX-License-Identifier: MIT
2022-09-29 10:18:02 +00:00
pragma solidity ^ 0 . 8 . 8 ;
2022-02-16 09:50:00 +00:00
import " @openzeppelin/contracts/token/ERC20/IERC20.sol " ;
2022-09-23 02:33:39 +00:00
import " @openzeppelin/contracts/utils/math/Math.sol " ;
2022-10-25 02:06:52 +00:00
import " @openzeppelin/contracts/utils/structs/EnumerableSet.sol " ;
2023-01-09 12:56:29 +00:00
import " ./Requests.sol " ;
2022-02-16 13:38:19 +00:00
import " ./Collateral.sol " ;
2022-06-13 08:40:18 +00:00
import " ./Proofs.sol " ;
2022-02-16 09:50:00 +00:00
2022-11-17 05:03:12 +00:00
contract Marketplace is Collateral , Proofs {
2022-10-25 02:06:52 +00:00
using EnumerableSet for EnumerableSet . Bytes32Set ;
2022-02-16 13:38:19 +00:00
uint256 public immutable collateral ;
2022-02-16 13:15:43 +00:00
MarketplaceFunds private funds ;
2022-09-29 10:18:02 +00:00
mapping ( RequestId => Request ) private requests ;
mapping ( RequestId => RequestContext ) private requestContexts ;
mapping ( SlotId => Slot ) private slots ;
2022-11-23 11:39:49 +00:00
mapping ( address => EnumerableSet . Bytes32Set ) private requestsPerClient ; // purchasing
2022-11-23 11:25:47 +00:00
mapping ( address => EnumerableSet . Bytes32Set ) private slotsPerHost ; // sales
2022-02-16 09:50:00 +00:00
2022-06-13 08:40:18 +00:00
constructor (
IERC20 _token ,
uint256 _collateral ,
uint256 _proofPeriod ,
uint256 _proofTimeout ,
uint8 _proofDowntime
)
2022-02-16 13:38:19 +00:00
Collateral ( _token )
2022-06-13 08:40:18 +00:00
Proofs ( _proofPeriod , _proofTimeout , _proofDowntime )
2022-02-16 13:38:19 +00:00
marketplaceInvariant
{
collateral = _collateral ;
2022-02-16 09:50:00 +00:00
}
2022-10-25 02:00:48 +00:00
function myRequests ( ) public view returns ( RequestId [ ] memory ) {
2022-11-23 11:39:49 +00:00
return _toRequestIds ( requestsPerClient [ msg . sender ] . values ( ) ) ;
2022-11-18 07:46:03 +00:00
}
2022-11-23 11:25:47 +00:00
function mySlots ( ) public view returns ( SlotId [ ] memory ) {
2022-11-28 10:51:19 +00:00
return _toSlotIds ( slotsPerHost [ msg . sender ] . values ( ) ) ;
2022-11-15 05:53:31 +00:00
}
2022-11-23 15:07:01 +00:00
function isWithdrawAllowed ( ) internal view override returns ( bool ) {
return slotsPerHost [ msg . sender ] . length ( ) == 0 ;
}
2022-11-16 04:52:22 +00:00
function _equals ( RequestId a , RequestId b ) internal pure returns ( bool ) {
return RequestId . unwrap ( a ) == RequestId . unwrap ( b ) ;
2022-11-04 00:38:34 +00:00
}
2022-02-16 13:15:43 +00:00
function requestStorage ( Request calldata request )
public
marketplaceInvariant
{
2022-02-17 10:00:18 +00:00
require ( request . client == msg . sender , " Invalid client address " ) ;
2022-02-21 11:55:00 +00:00
2022-09-29 10:18:02 +00:00
RequestId id = _toRequestId ( request ) ;
2022-02-17 10:09:35 +00:00
require ( requests [ id ] . client == address ( 0 ) , " Request already exists " ) ;
2022-02-21 11:55:00 +00:00
2022-02-16 09:50:00 +00:00
requests [ id ] = request ;
2022-09-29 10:07:55 +00:00
RequestContext storage context = _context ( id ) ;
// set contract end time to `duration` from now (time request was created)
context . endsAt = block . timestamp + request . ask . duration ;
2023-01-09 13:20:59 +00:00
_setProofEnd ( id , context . endsAt ) ;
2022-09-29 10:07:55 +00:00
2022-11-23 11:39:49 +00:00
requestsPerClient [ request . client ] . add ( RequestId . unwrap ( id ) ) ;
2022-02-21 11:55:00 +00:00
2022-07-20 09:07:20 +00:00
uint256 amount = price ( request ) ;
funds . received += amount ;
funds . balance += amount ;
transferFrom ( msg . sender , amount ) ;
2022-02-21 11:55:00 +00:00
2022-04-06 12:26:56 +00:00
emit StorageRequested ( id , request . ask ) ;
2022-02-16 09:50:00 +00:00
}
2022-07-19 09:33:54 +00:00
function fillSlot (
2022-09-29 10:18:02 +00:00
RequestId requestId ,
2022-07-19 09:33:54 +00:00
uint256 slotIndex ,
bytes calldata proof
2022-09-21 09:13:12 +00:00
) public requestMustAcceptProofs ( requestId ) marketplaceInvariant {
2022-09-13 07:14:57 +00:00
Request storage request = _request ( requestId ) ;
2022-07-20 08:44:22 +00:00
require ( slotIndex < request . ask . slots , " Invalid slot " ) ;
2022-07-19 09:33:54 +00:00
2022-09-29 10:18:02 +00:00
SlotId slotId = _toSlotId ( requestId , slotIndex ) ;
2022-07-19 09:33:54 +00:00
Slot storage slot = slots [ slotId ] ;
require ( slot . host == address ( 0 ) , " Slot already filled " ) ;
require ( balanceOf ( msg . sender ) >= collateral , " Insufficient collateral " ) ;
2023-01-09 13:20:59 +00:00
_expectProofs ( slotId , requestId , request . ask . proofProbability ) ;
_submitProof ( slotId , proof ) ;
2022-07-19 09:33:54 +00:00
slot . host = msg . sender ;
2022-08-17 05:26:44 +00:00
slot . requestId = requestId ;
2022-09-21 09:57:26 +00:00
RequestContext storage context = _context ( requestId ) ;
2022-08-03 09:54:29 +00:00
context . slotsFilled += 1 ;
2022-11-23 11:25:47 +00:00
slotsPerHost [ slot . host ] . add ( SlotId . unwrap ( slotId ) ) ;
2022-07-19 09:33:54 +00:00
emit SlotFilled ( requestId , slotIndex , slotId ) ;
2022-08-03 09:54:29 +00:00
if ( context . slotsFilled == request . ask . slots ) {
context . state = RequestState . Started ;
2022-09-21 09:38:42 +00:00
context . startedAt = block . timestamp ;
2022-07-20 08:29:24 +00:00
emit RequestFulfilled ( requestId ) ;
}
2022-07-19 09:33:54 +00:00
}
2022-11-23 14:29:58 +00:00
function freeSlot ( SlotId slotId ) public {
Slot storage slot = _slot ( slotId ) ;
require ( slot . host == msg . sender , " Slot filled by other host " ) ;
RequestState s = state ( slot . requestId ) ;
if ( s == RequestState . Finished || s == RequestState . Cancelled ) {
payoutSlot ( slot . requestId , slotId ) ;
} else if ( s == RequestState . Failed ) {
slotsPerHost [ msg . sender ] . remove ( SlotId . unwrap ( slotId ) ) ;
} else {
_forciblyFreeSlot ( slotId ) ;
}
}
2022-11-23 14:10:58 +00:00
function _forciblyFreeSlot ( SlotId slotId )
2022-10-25 02:04:16 +00:00
internal
slotMustAcceptProofs ( slotId )
marketplaceInvariant
2022-11-23 11:25:47 +00:00
// TODO: restrict senders that can call this function
2022-10-25 02:04:16 +00:00
{
2022-09-16 05:00:54 +00:00
Slot storage slot = _slot ( slotId ) ;
2022-09-29 10:18:02 +00:00
RequestId requestId = slot . requestId ;
2022-09-16 05:00:54 +00:00
RequestContext storage context = requestContexts [ requestId ] ;
// TODO: burn host's slot collateral except for repair costs + mark proof
// missing reward
// Slot collateral is not yet implemented as the design decision was
// not finalised.
2023-01-09 13:20:59 +00:00
_unexpectProofs ( slotId ) ;
2022-09-16 05:00:54 +00:00
2022-11-23 11:25:47 +00:00
slotsPerHost [ slot . host ] . remove ( SlotId . unwrap ( slotId ) ) ;
2022-09-16 05:00:54 +00:00
slot . host = address ( 0 ) ;
2022-09-29 10:18:02 +00:00
slot . requestId = RequestId . wrap ( 0 ) ;
2022-09-16 05:00:54 +00:00
context . slotsFilled -= 1 ;
emit SlotFreed ( requestId , slotId ) ;
2022-09-21 09:13:12 +00:00
Request storage request = _request ( requestId ) ;
2022-09-16 05:00:54 +00:00
uint256 slotsLost = request . ask . slots - context . slotsFilled ;
2022-10-26 08:58:14 +00:00
if (
slotsLost > request . ask . maxSlotLoss &&
context . state == RequestState . Started
) {
2022-09-16 05:00:54 +00:00
context . state = RequestState . Failed ;
2023-01-09 13:20:59 +00:00
_setProofEnd ( requestId , block . timestamp - 1 ) ;
2022-09-23 02:33:39 +00:00
context . endsAt = block . timestamp - 1 ;
2022-09-16 05:00:54 +00:00
emit RequestFailed ( requestId ) ;
// TODO: burn all remaining slot collateral (note: slot collateral not
// yet implemented)
// TODO: send client remaining funds
}
}
2022-10-25 02:04:16 +00:00
2022-11-23 14:29:58 +00:00
function payoutSlot ( RequestId requestId , SlotId slotId )
private
2022-07-19 15:09:35 +00:00
marketplaceInvariant
{
2022-11-23 15:07:01 +00:00
require (
_isFinished ( requestId ) || _isCancelled ( requestId ) ,
" Contract not ended "
) ;
2022-09-21 09:57:26 +00:00
RequestContext storage context = _context ( requestId ) ;
2022-10-25 02:06:52 +00:00
Request storage request = _request ( requestId ) ;
2022-09-21 09:57:26 +00:00
context . state = RequestState . Finished ;
2022-11-23 11:39:49 +00:00
requestsPerClient [ request . client ] . remove ( RequestId . unwrap ( requestId ) ) ;
2022-09-21 09:38:42 +00:00
Slot storage slot = _slot ( slotId ) ;
2022-07-19 15:09:35 +00:00
require ( ! slot . hostPaid , " Already paid " ) ;
2022-11-23 11:25:47 +00:00
slotsPerHost [ slot . host ] . remove ( SlotId . unwrap ( slotId ) ) ;
2022-07-20 09:07:20 +00:00
uint256 amount = pricePerSlot ( requests [ requestId ] ) ;
2022-07-19 15:09:35 +00:00
funds . sent += amount ;
funds . balance -= amount ;
slot . hostPaid = true ;
require ( token . transfer ( slot . host , amount ) , " Payment failed " ) ;
}
2022-08-17 05:26:04 +00:00
/// @notice Withdraws storage request funds back to the client that deposited them.
/// @dev Request must be expired, must be in RequestState.New, and the transaction must originate from the depositer address.
/// @param requestId the id of the request
2022-09-29 10:18:02 +00:00
function withdrawFunds ( RequestId requestId ) public marketplaceInvariant {
2022-09-07 05:25:01 +00:00
Request storage request = requests [ requestId ] ;
2022-08-04 02:14:36 +00:00
require ( block . timestamp > request . expiry , " Request not yet timed out " ) ;
require ( request . client == msg . sender , " Invalid client address " ) ;
2022-09-21 09:57:26 +00:00
RequestContext storage context = _context ( requestId ) ;
2022-08-04 02:14:36 +00:00
require ( context . state == RequestState . New , " Invalid state " ) ;
// Update request state to Cancelled. Handle in the withdraw transaction
// as there needs to be someone to pay for the gas to update the state
context . state = RequestState . Cancelled ;
2022-11-23 11:39:49 +00:00
requestsPerClient [ request . client ] . remove ( RequestId . unwrap ( requestId ) ) ;
2022-11-23 11:25:47 +00:00
2022-08-04 02:14:36 +00:00
emit RequestCancelled ( requestId ) ;
2022-09-07 05:25:01 +00:00
// TODO: To be changed once we start paying out hosts for the time they
// fill a slot. The amount that we paid to hosts will then have to be
// deducted from the price.
uint256 amount = _price ( request ) ;
funds . sent += amount ;
funds . balance -= amount ;
require ( token . transfer ( msg . sender , amount ) , " Withdraw failed " ) ;
2022-08-04 02:14:36 +00:00
}
2022-08-17 05:26:44 +00:00
/// @notice Return true if the request state is RequestState.Cancelled or if the request expiry time has elapsed and the request was never started.
2022-08-17 05:26:04 +00:00
/// @dev Handles the case when a request may have been cancelled, but the client has not withdrawn its funds yet, and therefore the state has not yet been updated.
/// @param requestId the id of the request
/// @return true if request is cancelled
2022-09-29 10:18:02 +00:00
function _isCancelled ( RequestId requestId ) internal view returns ( bool ) {
2022-09-21 09:13:12 +00:00
RequestContext storage context = _context ( requestId ) ;
2022-08-12 01:40:04 +00:00
return
context . state == RequestState . Cancelled ||
2022-10-25 02:04:16 +00:00
( context . state == RequestState . New &&
block . timestamp > _request ( requestId ) . expiry ) ;
2022-08-12 01:40:04 +00:00
}
2022-09-21 09:38:42 +00:00
/// @notice Return true if the request state is RequestState.Finished or if the request duration has elapsed and the request was started.
/// @dev Handles the case when a request may have been finished, but the state has not yet been updated by a transaction.
/// @param requestId the id of the request
/// @return true if request is finished
2022-09-29 10:18:02 +00:00
function _isFinished ( RequestId requestId ) internal view returns ( bool ) {
2022-09-21 09:57:26 +00:00
RequestContext memory context = _context ( requestId ) ;
2022-09-21 09:38:42 +00:00
return
context . state == RequestState . Finished ||
2022-10-25 02:04:16 +00:00
( context . state == RequestState . Started &&
block . timestamp > context . endsAt ) ;
2022-09-21 09:38:42 +00:00
}
2022-08-22 06:16:45 +00:00
/// @notice Return id of request that slot belongs to
/// @dev Returns requestId that is mapped to the slotId
/// @param slotId id of the slot
/// @return if of the request the slot belongs to
2022-09-29 10:18:02 +00:00
function _getRequestIdForSlot ( SlotId slotId )
internal
view
returns ( RequestId )
{
2022-08-22 06:16:45 +00:00
Slot memory slot = _slot ( slotId ) ;
2022-09-29 10:18:02 +00:00
require ( _notEqual ( slot . requestId , 0 ) , " Missing request id " ) ;
2022-08-22 06:16:45 +00:00
return slot . requestId ;
}
2022-08-17 05:26:44 +00:00
/// @notice Return true if the request state the slot belongs to is RequestState.Cancelled or if the request expiry time has elapsed and the request was never started.
/// @dev Handles the case when a request may have been cancelled, but the client has not withdrawn its funds yet, and therefore the state has not yet been updated.
/// @param slotId the id of the slot
/// @return true if request is cancelled
2022-09-29 10:18:02 +00:00
function _isSlotCancelled ( SlotId slotId ) internal view returns ( bool ) {
RequestId requestId = _getRequestIdForSlot ( slotId ) ;
2022-08-22 06:16:45 +00:00
return _isCancelled ( requestId ) ;
2022-08-17 05:26:44 +00:00
}
2022-09-29 10:18:02 +00:00
function _host ( SlotId slotId ) internal view returns ( address ) {
2022-07-20 08:10:22 +00:00
return slots [ slotId ] . host ;
2022-02-21 10:31:37 +00:00
}
2023-01-09 12:38:12 +00:00
function getHost ( SlotId slotId ) public view returns ( address ) {
return _host ( slotId ) ;
}
2022-09-29 10:18:02 +00:00
function _request ( RequestId requestId )
internal
view
returns ( Request storage )
{
2022-09-21 09:57:26 +00:00
Request storage request = requests [ requestId ] ;
2022-09-13 07:14:57 +00:00
require ( request . client != address ( 0 ) , " Unknown request " ) ;
2022-09-13 07:13:11 +00:00
return request ;
2022-02-22 08:25:42 +00:00
}
2023-01-09 12:38:12 +00:00
function getRequest ( RequestId requestId )
public
view
returns ( Request memory )
{
return _request ( requestId ) ;
}
2022-09-29 10:18:02 +00:00
function _slot ( SlotId slotId ) internal view returns ( Slot storage ) {
2022-09-13 07:14:57 +00:00
Slot storage slot = slots [ slotId ] ;
2022-08-22 06:16:45 +00:00
require ( slot . host != address ( 0 ) , " Slot empty " ) ;
return slot ;
}
2022-09-29 10:18:02 +00:00
function _context ( RequestId requestId )
internal
view
returns ( RequestContext storage )
{
2022-09-08 07:56:01 +00:00
return requestContexts [ requestId ] ;
}
2022-06-13 09:49:25 +00:00
function proofPeriod ( ) public view returns ( uint256 ) {
return _period ( ) ;
}
function proofTimeout ( ) public view returns ( uint256 ) {
return _timeout ( ) ;
}
2022-09-29 10:31:57 +00:00
function proofEnd ( SlotId slotId ) public view returns ( uint256 ) {
2022-10-26 08:48:09 +00:00
return requestEnd ( _slot ( slotId ) . requestId ) ;
2022-06-13 09:49:25 +00:00
}
2022-10-25 12:49:37 +00:00
function requestEnd ( RequestId requestId ) public view returns ( uint256 ) {
2023-01-09 13:20:59 +00:00
uint256 end = _end ( requestId ) ;
2022-10-26 08:58:14 +00:00
if ( _requestAcceptsProofs ( requestId ) ) {
2022-10-26 02:15:42 +00:00
return end ;
} else {
return Math . min ( end , block . timestamp - 1 ) ;
}
2022-10-25 12:49:37 +00:00
}
2022-08-04 02:14:36 +00:00
function _price (
uint64 numSlots ,
uint256 duration ,
2022-10-25 02:04:16 +00:00
uint256 reward
) internal pure returns ( uint256 ) {
2022-08-04 02:14:36 +00:00
return numSlots * duration * reward ;
}
function _price ( Request memory request ) internal pure returns ( uint256 ) {
return _price ( request . ask . slots , request . ask . duration , request . ask . reward ) ;
}
2022-07-20 09:07:20 +00:00
function price ( Request calldata request ) private pure returns ( uint256 ) {
2022-08-04 02:14:36 +00:00
return _price ( request . ask . slots , request . ask . duration , request . ask . reward ) ;
2022-07-20 09:07:20 +00:00
}
function pricePerSlot ( Request memory request ) private pure returns ( uint256 ) {
return request . ask . duration * request . ask . reward ;
}
2022-09-29 10:18:02 +00:00
function state ( RequestId requestId ) public view returns ( RequestState ) {
2022-09-08 07:56:01 +00:00
if ( _isCancelled ( requestId ) ) {
return RequestState . Cancelled ;
2022-09-22 02:21:49 +00:00
} else if ( _isFinished ( requestId ) ) {
2022-09-21 09:57:26 +00:00
return RequestState . Finished ;
2022-09-08 07:56:01 +00:00
} else {
RequestContext storage context = _context ( requestId ) ;
return context . state ;
}
}
2022-09-29 10:18:02 +00:00
/// @notice returns true when the request is accepting proof submissions from hosts occupying slots.
/// @dev Request state must be new or started, and must not be cancelled, finished, or failed.
/// @param slotId id of the slot, that is mapped to a request, for which to obtain state info
function _slotAcceptsProofs ( SlotId slotId ) internal view returns ( bool ) {
RequestId requestId = _getRequestIdForSlot ( slotId ) ;
return _requestAcceptsProofs ( requestId ) ;
}
2022-09-08 07:56:01 +00:00
/// @notice returns true when the request is accepting proof submissions from hosts occupying slots.
/// @dev Request state must be new or started, and must not be cancelled, finished, or failed.
/// @param requestId id of the request for which to obtain state info
2022-10-25 02:04:16 +00:00
function _requestAcceptsProofs ( RequestId requestId )
internal
view
returns ( bool )
{
2022-09-08 07:56:01 +00:00
RequestState s = state ( requestId ) ;
return s == RequestState . New || s == RequestState . Started ;
}
2022-09-29 10:18:02 +00:00
function _toRequestId ( Request memory request )
internal
pure
returns ( RequestId )
{
return RequestId . wrap ( keccak256 ( abi . encode ( request ) ) ) ;
}
2022-10-25 02:06:52 +00:00
function _toRequestIds ( bytes32 [ ] memory array )
private
pure
returns ( RequestId [ ] memory result )
2022-11-04 00:38:34 +00:00
{
// solhint-disable-next-line no-inline-assembly
assembly {
result : = array
}
}
function _toSlotIds ( bytes32 [ ] memory array )
private
pure
returns ( SlotId [ ] memory result )
2022-10-25 02:06:52 +00:00
{
// solhint-disable-next-line no-inline-assembly
assembly {
result : = array
}
}
2022-11-22 13:14:39 +00:00
function _toBytes32s ( RequestId [ ] memory array )
private
pure
returns ( bytes32 [ ] memory result )
{
// solhint-disable-next-line no-inline-assembly
assembly {
result : = array
}
}
2022-10-25 02:04:16 +00:00
function _toSlotId ( RequestId requestId , uint256 slotIndex )
2022-09-29 10:18:02 +00:00
internal
pure
returns ( SlotId )
{
return SlotId . wrap ( keccak256 ( abi . encode ( requestId , slotIndex ) ) ) ;
}
function _notEqual ( RequestId a , uint256 b ) internal pure returns ( bool ) {
return RequestId . unwrap ( a ) != bytes32 ( b ) ;
}
2022-08-03 09:54:29 +00:00
enum RequestState {
2022-10-25 02:04:16 +00:00
New , // [default] waiting to fill slots
Started , // all slots filled, accepting regular proofs
Cancelled , // not enough slots filled before expiry
Finished , // successfully completed
Failed // too many nodes have failed to provide proofs, data lost
2022-08-03 09:54:29 +00:00
}
struct RequestContext {
2022-07-20 08:29:24 +00:00
uint256 slotsFilled ;
2022-08-03 09:54:29 +00:00
RequestState state ;
2022-09-21 09:38:42 +00:00
uint256 startedAt ;
2022-09-21 09:57:26 +00:00
uint256 endsAt ;
2022-07-20 08:29:24 +00:00
}
2022-07-19 09:33:54 +00:00
struct Slot {
address host ;
2022-07-19 15:09:35 +00:00
bool hostPaid ;
2022-09-29 10:18:02 +00:00
RequestId requestId ;
2022-07-19 09:33:54 +00:00
}
2022-09-29 10:18:02 +00:00
event StorageRequested ( RequestId requestId , Ask ask ) ;
event RequestFulfilled ( RequestId indexed requestId ) ;
event RequestFailed ( RequestId indexed requestId ) ;
2022-07-19 09:33:54 +00:00
event SlotFilled (
2022-09-29 10:18:02 +00:00
RequestId indexed requestId ,
2022-07-19 09:33:54 +00:00
uint256 indexed slotIndex ,
2022-09-29 10:18:02 +00:00
SlotId slotId
2022-07-19 09:33:54 +00:00
) ;
2022-09-29 10:18:02 +00:00
event SlotFreed ( RequestId indexed requestId , SlotId slotId ) ;
event RequestCancelled ( RequestId indexed requestId ) ;
2022-02-16 09:50:00 +00:00
2022-02-16 13:15:43 +00:00
modifier marketplaceInvariant ( ) {
MarketplaceFunds memory oldFunds = funds ;
2022-02-16 09:50:00 +00:00
_ ;
2022-02-16 13:15:43 +00:00
assert ( funds . received >= oldFunds . received ) ;
assert ( funds . sent >= oldFunds . sent ) ;
assert ( funds . received == funds . balance + funds . sent ) ;
2022-02-16 09:50:00 +00:00
}
2022-09-08 07:56:01 +00:00
/// @notice Modifier that requires the request state to be that which is accepting proof submissions from hosts occupying slots.
/// @dev Request state must be new or started, and must not be cancelled, finished, or failed.
/// @param slotId id of the slot, that is mapped to a request, for which to obtain state info
2022-09-29 10:18:02 +00:00
modifier slotMustAcceptProofs ( SlotId slotId ) {
RequestId requestId = _getRequestIdForSlot ( slotId ) ;
2022-09-08 07:56:01 +00:00
require ( _requestAcceptsProofs ( requestId ) , " Slot not accepting proofs " ) ;
_ ;
}
2022-09-21 09:13:12 +00:00
/// @notice Modifier that requires the request state to be that which is accepting proof submissions from hosts occupying slots.
/// @dev Request state must be new or started, and must not be cancelled, finished, or failed.
/// @param requestId id of the request, for which to obtain state info
2022-09-29 10:18:02 +00:00
modifier requestMustAcceptProofs ( RequestId requestId ) {
2022-09-21 09:13:12 +00:00
require ( _requestAcceptsProofs ( requestId ) , " Request not accepting proofs " ) ;
_ ;
}
2022-02-16 13:15:43 +00:00
struct MarketplaceFunds {
2022-02-16 09:50:00 +00:00
uint256 balance ;
uint256 received ;
uint256 sent ;
}
}