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-02-16 13:38:19 +00:00
import " ./Collateral.sol " ;
2022-06-13 08:40:18 +00:00
import " ./Proofs.sol " ;
2022-11-22 13:14:39 +00:00
import " ./libs/Utils.sol " ;
2022-11-24 08:32:55 +00:00
import " ./libs/Mappings.sol " ;
2022-02-16 09:50:00 +00:00
2022-11-17 05:03:12 +00:00
contract Marketplace is Collateral , Proofs {
2022-11-24 08:32:55 +00:00
using Mappings for Mappings . Mapping ;
2022-10-25 02:06:52 +00:00
2022-09-29 10:18:02 +00:00
type RequestId is bytes32 ;
type SlotId is bytes32 ;
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-02-16 09:50:00 +00:00
2022-11-24 11:07:23 +00:00
// PURCHASING
// address => RequestId
2022-11-24 08:32:55 +00:00
Mappings . Mapping private activeClientRequests ;
2022-11-24 07:49:16 +00:00
2022-11-24 11:07:23 +00:00
// SALES
2022-11-24 07:49:16 +00:00
// address => RequestId
2022-11-24 08:32:55 +00:00
Mappings . Mapping private activeHostRequests ;
2022-11-24 07:49:16 +00:00
// RequestId => SlotId
2022-11-24 08:32:55 +00:00
Mappings . Mapping private activeRequestSlots ;
2022-11-24 07:49:16 +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-24 11:04:18 +00:00
Mappings . ValueId [ ] storage valueIds =
activeClientRequests . getValueIds ( Mappings . toKeyId ( msg . sender ) ) ;
2022-11-24 11:11:28 +00:00
return _toRequestIds ( valueIds ) ;
2022-11-17 06:39:17 +00:00
}
2022-11-24 07:49:16 +00:00
function mySlots ( )
2022-11-16 04:52:22 +00:00
public
view
2022-11-17 01:39:41 +00:00
returns ( SlotId [ ] memory )
2022-11-16 04:52:22 +00:00
{
2022-11-24 07:49:16 +00:00
uint256 counter = 0 ;
2022-11-25 04:17:08 +00:00
uint256 totalSlots = activeRequestSlots . getValueCount ( ) ; // set this bigger than our possible filtered list size
2022-11-24 07:49:16 +00:00
if ( totalSlots == 0 ) {
return new SlotId [ ] ( 0 ) ;
2022-11-18 07:46:03 +00:00
}
2022-11-24 07:49:16 +00:00
bytes32 [ ] memory result = new bytes32 [ ] ( totalSlots ) ;
2022-11-24 11:04:18 +00:00
Mappings . ValueId [ ] storage valueIds =
activeHostRequests . getValueIds ( Mappings . toKeyId ( msg . sender ) ) ;
for ( uint256 i = 0 ; i < valueIds . length ; i ++ ) {
2022-11-24 07:49:16 +00:00
// There may exist slots that are still "active", but are part of a request
// that is expired but has not been set to the cancelled state yet. In that
// case, return an empty array.
2022-11-24 11:11:28 +00:00
Mappings . KeyId keyId = Mappings . toKeyId ( valueIds [ i ] ) ;
2022-11-24 11:04:18 +00:00
if ( activeRequestSlots . keyExists ( keyId ) ) {
Mappings . ValueId [ ] storage slotIds =
activeRequestSlots . getValueIds ( keyId ) ;
2022-11-24 07:49:16 +00:00
for ( uint256 j = 0 ; j < slotIds . length ; j ++ ) {
2022-11-24 11:04:18 +00:00
result [ counter ] = Mappings . ValueId . unwrap ( slotIds [ j ] ) ;
2022-11-24 07:49:16 +00:00
counter ++ ;
}
}
}
return _toSlotIds ( Utils . _resize ( result , counter ) ) ;
2022-11-15 05:53:31 +00:00
}
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 ;
2022-09-29 10:18:02 +00:00
_setProofEnd ( _toEndId ( id ) , context . endsAt ) ;
2022-09-29 10:07:55 +00:00
2022-11-24 11:04:18 +00:00
Mappings . KeyId addrBytes32 = Mappings . toKeyId ( request . client ) ;
activeClientRequests . insert ( addrBytes32 , _toValueId ( id ) ) ;
2022-11-24 07:49:16 +00:00
2022-11-24 11:04:18 +00:00
Mappings . KeyId keyId = _toKeyId ( id ) ;
if ( ! activeRequestSlots . keyExists ( keyId ) ) {
activeRequestSlots . insertKey ( keyId ) ;
2022-11-24 07:49:16 +00:00
}
2022-02-21 11:55:00 +00:00
2022-09-29 10:18:02 +00:00
_createLock ( _toLockId ( id ) , request . expiry ) ;
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 " ) ;
2022-09-29 10:18:02 +00:00
LockId lockId = _toLockId ( requestId ) ;
_lock ( msg . sender , lockId ) ;
2022-07-19 09:33:54 +00:00
2022-09-29 10:18:02 +00:00
ProofId proofId = _toProofId ( slotId ) ;
2022-10-26 08:58:14 +00:00
_expectProofs ( proofId , _toEndId ( requestId ) , request . ask . proofProbability ) ;
2022-09-29 10:18:02 +00:00
_submitProof ( proofId , 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-24 07:49:16 +00:00
2022-11-24 11:04:18 +00:00
Mappings . KeyId sender = Mappings . toKeyId ( msg . sender ) ;
2022-11-24 07:49:16 +00:00
// address => RequestId
2022-11-24 11:04:18 +00:00
activeHostRequests . insert ( sender , _toValueId ( requestId ) ) ;
2022-11-24 07:49:16 +00:00
// RequestId => SlotId
2022-11-24 11:04:18 +00:00
activeRequestSlots . insert ( _toKeyId ( requestId ) , _toValueId ( slotId ) ) ;
2022-11-24 07:49:16 +00:00
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-09-29 10:18:02 +00:00
_extendLockExpiryTo ( lockId , context . endsAt ) ;
2022-07-20 08:29:24 +00:00
emit RequestFulfilled ( requestId ) ;
}
2022-07-19 09:33:54 +00:00
}
2022-10-25 02:04:16 +00:00
function _freeSlot ( SlotId slotId )
internal
slotMustAcceptProofs ( slotId )
marketplaceInvariant
2022-11-11 02:33:02 +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.
2022-09-29 10:18:02 +00:00
_unexpectProofs ( _toProofId ( slotId ) ) ;
2022-09-16 05:00:54 +00:00
2022-11-24 11:04:18 +00:00
Mappings . ValueId valueId = _toValueId ( slotId ) ;
if ( activeRequestSlots . valueExists ( valueId ) ) {
activeRequestSlots . deleteValue ( valueId ) ;
2022-11-18 07:46:03 +00:00
}
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 ;
2022-09-29 10:31:57 +00:00
_setProofEnd ( _toEndId ( requestId ) , block . timestamp - 1 ) ;
2022-09-23 02:33:39 +00:00
context . endsAt = block . timestamp - 1 ;
2022-11-24 11:04:18 +00:00
activeClientRequests . deleteValue ( _toValueId ( requestId ) ) ;
activeRequestSlots . clearValues ( _toKeyId ( requestId ) ) ;
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-09-29 10:18:02 +00:00
function payoutSlot ( RequestId requestId , uint256 slotIndex )
2022-07-19 15:09:35 +00:00
public
marketplaceInvariant
{
2022-09-21 09:38:42 +00:00
require ( _isFinished ( requestId ) , " Contract not ended " ) ;
2022-09-21 09:57:26 +00:00
RequestContext storage context = _context ( requestId ) ;
2022-11-24 07:49:16 +00:00
// Request storage request = _request(requestId);
2022-09-21 09:57:26 +00:00
context . state = RequestState . Finished ;
2022-11-24 11:04:18 +00:00
Mappings . ValueId valueId = _toValueId ( requestId ) ;
if ( activeClientRequests . valueExists ( valueId ) ) {
activeClientRequests . deleteValue ( valueId ) ;
2022-11-24 07:49:16 +00:00
}
2022-09-29 10:18:02 +00:00
SlotId slotId = _toSlotId ( requestId , slotIndex ) ;
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-24 11:04:18 +00:00
activeRequestSlots . deleteValue ( _toValueId ( slotId ) ) ;
2022-11-25 04:17:08 +00:00
if ( activeRequestSlots . getValueCount ( ) == 0 ) {
2022-11-24 11:04:18 +00:00
activeRequestSlots . deleteKey ( _toKeyId ( requestId ) ) ;
activeHostRequests . deleteValue ( valueId ) ;
2022-11-24 07:49:16 +00:00
}
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-24 11:04:18 +00:00
activeClientRequests . deleteValue ( _toValueId ( requestId ) ) ;
activeRequestSlots . clearValues ( _toKeyId ( requestId ) ) ;
2022-11-24 07:49:16 +00:00
// TODO: handle dangling RequestId in activeHostRequests (for address)
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
}
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
}
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 ) {
2022-10-26 02:15:42 +00:00
uint256 end = _end ( _toEndId ( 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-11-24 11:04:18 +00:00
function _toRequestId ( Mappings . ValueId valueId )
internal
pure
returns ( RequestId )
{
return RequestId . wrap ( Mappings . ValueId . unwrap ( valueId ) ) ;
}
2022-11-24 11:11:28 +00:00
function _toRequestIds ( Mappings . ValueId [ ] memory array )
2022-10-25 02:06:52 +00:00
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-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 _toLockId ( RequestId requestId ) internal pure returns ( LockId ) {
return LockId . wrap ( RequestId . unwrap ( requestId ) ) ;
}
function _toProofId ( SlotId slotId ) internal pure returns ( ProofId ) {
return ProofId . wrap ( SlotId . unwrap ( slotId ) ) ;
2022-08-03 09:54:29 +00:00
}
2022-09-29 10:31:57 +00:00
function _toEndId ( RequestId requestId ) internal pure returns ( EndId ) {
return EndId . wrap ( RequestId . unwrap ( requestId ) ) ;
}
2022-09-29 10:18:02 +00:00
2022-11-24 11:04:18 +00:00
function _toKeyId ( RequestId requestId )
internal
pure
returns ( Mappings . KeyId )
{
return Mappings . KeyId . wrap ( RequestId . unwrap ( requestId ) ) ;
}
function _toValueId ( RequestId requestId )
internal
pure
returns ( Mappings . ValueId )
{
return Mappings . ValueId . wrap ( RequestId . unwrap ( requestId ) ) ;
}
function _toValueId ( SlotId slotId )
internal
pure
returns ( Mappings . ValueId )
{
return Mappings . ValueId . wrap ( SlotId . unwrap ( slotId ) ) ;
}
2022-09-29 10:18:02 +00:00
function _notEqual ( RequestId a , uint256 b ) internal pure returns ( bool ) {
return RequestId . unwrap ( a ) != bytes32 ( b ) ;
}
2022-02-16 09:50:00 +00:00
struct Request {
2022-02-17 10:00:18 +00:00
address client ;
2022-04-06 12:26:56 +00:00
Ask ask ;
Content content ;
uint256 expiry ; // time at which this request expires
bytes32 nonce ; // random nonce to differentiate between similar requests
}
struct Ask {
2022-08-02 09:41:49 +00:00
uint64 slots ; // the number of requested slots
uint256 slotSize ; // amount of storage per slot (in number of bytes)
2022-04-06 12:26:56 +00:00
uint256 duration ; // how long content should be stored (in seconds)
uint256 proofProbability ; // how often storage proofs are required
2022-07-20 09:07:20 +00:00
uint256 reward ; // amount of tokens paid per second per slot to hosts
2022-08-24 05:30:55 +00:00
uint64 maxSlotLoss ; // Max slots that can be lost without data considered to be lost
2022-04-06 12:26:56 +00:00
}
struct Content {
string cid ; // content id (if part of a larger set, the chunk cid)
Erasure erasure ; // Erasure coding attributes
PoR por ; // Proof of Retrievability parameters
}
struct Erasure {
uint64 totalChunks ; // the total number of chunks in the larger data set
}
struct PoR {
2022-04-07 13:44:56 +00:00
bytes u ; // parameters u_1..u_s
bytes publicKey ; // public key
bytes name ; // random name
2022-02-16 09:50:00 +00:00
}
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 ;
}
}