|
|
@ -16,11 +16,12 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
IERC20 public immutable token;
|
|
|
|
IERC20 public immutable token;
|
|
|
|
MarketplaceConfig public config;
|
|
|
|
MarketplaceConfig public config;
|
|
|
|
|
|
|
|
|
|
|
|
MarketplaceFunds private _funds;
|
|
|
|
|
|
|
|
mapping(RequestId => Request) private _requests;
|
|
|
|
mapping(RequestId => Request) private _requests;
|
|
|
|
mapping(RequestId => RequestContext) private _requestContexts;
|
|
|
|
mapping(RequestId => RequestContext) private _requestContexts;
|
|
|
|
mapping(SlotId => Slot) internal _slots;
|
|
|
|
mapping(SlotId => Slot) internal _slots;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MarketplaceTotals internal _marketplaceTotals;
|
|
|
|
|
|
|
|
|
|
|
|
struct RequestContext {
|
|
|
|
struct RequestContext {
|
|
|
|
RequestState state;
|
|
|
|
RequestState state;
|
|
|
|
uint256 slotsFilled;
|
|
|
|
uint256 slotsFilled;
|
|
|
@ -48,7 +49,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
constructor(
|
|
|
|
constructor(
|
|
|
|
IERC20 token_,
|
|
|
|
IERC20 token_,
|
|
|
|
MarketplaceConfig memory configuration
|
|
|
|
MarketplaceConfig memory configuration
|
|
|
|
) Proofs(configuration.proofs) marketplaceInvariant {
|
|
|
|
) Proofs(configuration.proofs) {
|
|
|
|
token = token_;
|
|
|
|
token = token_;
|
|
|
|
|
|
|
|
|
|
|
|
require(configuration.collateral.repairRewardPercentage <= 100, "Must be less than 100");
|
|
|
|
require(configuration.collateral.repairRewardPercentage <= 100, "Must be less than 100");
|
|
|
@ -57,9 +58,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
config = configuration;
|
|
|
|
config = configuration;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function requestStorage(
|
|
|
|
function requestStorage(Request calldata request) public {
|
|
|
|
Request calldata request
|
|
|
|
|
|
|
|
) public marketplaceInvariant {
|
|
|
|
|
|
|
|
require(request.client == msg.sender, "Invalid client address");
|
|
|
|
require(request.client == msg.sender, "Invalid client address");
|
|
|
|
|
|
|
|
|
|
|
|
RequestId id = request.id();
|
|
|
|
RequestId id = request.id();
|
|
|
@ -71,8 +70,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
_addToMyRequests(request.client, id);
|
|
|
|
_addToMyRequests(request.client, id);
|
|
|
|
|
|
|
|
|
|
|
|
uint256 amount = request.price();
|
|
|
|
uint256 amount = request.price();
|
|
|
|
_funds.received += amount;
|
|
|
|
_marketplaceTotals.received += amount;
|
|
|
|
_funds.balance += amount;
|
|
|
|
|
|
|
|
_transferFrom(msg.sender, amount);
|
|
|
|
_transferFrom(msg.sender, amount);
|
|
|
|
|
|
|
|
|
|
|
|
emit StorageRequested(id, request.ask);
|
|
|
|
emit StorageRequested(id, request.ask);
|
|
|
@ -104,8 +102,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
// Collect collateral
|
|
|
|
// Collect collateral
|
|
|
|
uint256 collateralAmount = request.ask.collateral;
|
|
|
|
uint256 collateralAmount = request.ask.collateral;
|
|
|
|
_transferFrom(msg.sender, collateralAmount);
|
|
|
|
_transferFrom(msg.sender, collateralAmount);
|
|
|
|
_funds.received += collateralAmount;
|
|
|
|
_marketplaceTotals.received += collateralAmount;
|
|
|
|
_funds.balance += collateralAmount;
|
|
|
|
|
|
|
|
slot.currentCollateral = collateralAmount;
|
|
|
|
slot.currentCollateral = collateralAmount;
|
|
|
|
|
|
|
|
|
|
|
|
_addToMySlots(slot.host, slotId);
|
|
|
|
_addToMySlots(slot.host, slotId);
|
|
|
@ -142,9 +139,6 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
if (missingProofs(slotId) % config.collateral.slashCriterion == 0) {
|
|
|
|
if (missingProofs(slotId) % config.collateral.slashCriterion == 0) {
|
|
|
|
uint256 slashedAmount = (request.ask.collateral * config.collateral.slashPercentage) / 100;
|
|
|
|
uint256 slashedAmount = (request.ask.collateral * config.collateral.slashPercentage) / 100;
|
|
|
|
slot.currentCollateral -= slashedAmount;
|
|
|
|
slot.currentCollateral -= slashedAmount;
|
|
|
|
_funds.slashed += slashedAmount;
|
|
|
|
|
|
|
|
_funds.balance -= slashedAmount;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (missingProofs(slotId) / config.collateral.slashCriterion >= config.collateral.maxNumberOfSlashes) {
|
|
|
|
if (missingProofs(slotId) / config.collateral.slashCriterion >= config.collateral.maxNumberOfSlashes) {
|
|
|
|
// When the number of slashings is at or above the allowed amount,
|
|
|
|
// When the number of slashings is at or above the allowed amount,
|
|
|
|
// free the slot.
|
|
|
|
// free the slot.
|
|
|
@ -153,7 +147,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function _forciblyFreeSlot(SlotId slotId) internal marketplaceInvariant {
|
|
|
|
function _forciblyFreeSlot(SlotId slotId) internal {
|
|
|
|
Slot storage slot = _slots[slotId];
|
|
|
|
Slot storage slot = _slots[slotId];
|
|
|
|
RequestId requestId = slot.requestId;
|
|
|
|
RequestId requestId = slot.requestId;
|
|
|
|
RequestContext storage context = _requestContexts[requestId];
|
|
|
|
RequestContext storage context = _requestContexts[requestId];
|
|
|
@ -182,7 +176,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
function _payoutSlot(
|
|
|
|
function _payoutSlot(
|
|
|
|
RequestId requestId,
|
|
|
|
RequestId requestId,
|
|
|
|
SlotId slotId
|
|
|
|
SlotId slotId
|
|
|
|
) private requestIsKnown(requestId) marketplaceInvariant {
|
|
|
|
) private requestIsKnown(requestId) {
|
|
|
|
RequestContext storage context = _requestContexts[requestId];
|
|
|
|
RequestContext storage context = _requestContexts[requestId];
|
|
|
|
Request storage request = _requests[requestId];
|
|
|
|
Request storage request = _requests[requestId];
|
|
|
|
context.state = RequestState.Finished;
|
|
|
|
context.state = RequestState.Finished;
|
|
|
@ -192,8 +186,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
_removeFromMySlots(slot.host, slotId);
|
|
|
|
_removeFromMySlots(slot.host, slotId);
|
|
|
|
|
|
|
|
|
|
|
|
uint256 amount = _requests[requestId].pricePerSlot() + slot.currentCollateral;
|
|
|
|
uint256 amount = _requests[requestId].pricePerSlot() + slot.currentCollateral;
|
|
|
|
_funds.sent += amount;
|
|
|
|
_marketplaceTotals.sent += amount;
|
|
|
|
_funds.balance -= amount;
|
|
|
|
|
|
|
|
slot.state = SlotState.Paid;
|
|
|
|
slot.state = SlotState.Paid;
|
|
|
|
require(token.transfer(slot.host, amount), "Payment failed");
|
|
|
|
require(token.transfer(slot.host, amount), "Payment failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -201,7 +194,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
/// @notice Withdraws storage request funds back to the client that deposited them.
|
|
|
|
/// @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.
|
|
|
|
/// @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
|
|
|
|
/// @param requestId the id of the request
|
|
|
|
function withdrawFunds(RequestId requestId) public marketplaceInvariant {
|
|
|
|
function withdrawFunds(RequestId requestId) public {
|
|
|
|
Request storage request = _requests[requestId];
|
|
|
|
Request storage request = _requests[requestId];
|
|
|
|
require(block.timestamp > request.expiry, "Request not yet timed out");
|
|
|
|
require(block.timestamp > request.expiry, "Request not yet timed out");
|
|
|
|
require(request.client == msg.sender, "Invalid client address");
|
|
|
|
require(request.client == msg.sender, "Invalid client address");
|
|
|
@ -219,8 +212,7 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
// fill a slot. The amount that we paid to hosts will then have to be
|
|
|
|
// fill a slot. The amount that we paid to hosts will then have to be
|
|
|
|
// deducted from the price.
|
|
|
|
// deducted from the price.
|
|
|
|
uint256 amount = request.price();
|
|
|
|
uint256 amount = request.price();
|
|
|
|
_funds.sent += amount;
|
|
|
|
_marketplaceTotals.sent += amount;
|
|
|
|
_funds.balance -= amount;
|
|
|
|
|
|
|
|
require(token.transfer(msg.sender, amount), "Withdraw failed");
|
|
|
|
require(token.transfer(msg.sender, amount), "Withdraw failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -322,19 +314,8 @@ contract Marketplace is Proofs, StateRetrieval {
|
|
|
|
event SlotFreed(RequestId indexed requestId, SlotId slotId);
|
|
|
|
event SlotFreed(RequestId indexed requestId, SlotId slotId);
|
|
|
|
event RequestCancelled(RequestId indexed requestId);
|
|
|
|
event RequestCancelled(RequestId indexed requestId);
|
|
|
|
|
|
|
|
|
|
|
|
modifier marketplaceInvariant() {
|
|
|
|
struct MarketplaceTotals {
|
|
|
|
MarketplaceFunds memory oldFunds = _funds;
|
|
|
|
|
|
|
|
_;
|
|
|
|
|
|
|
|
assert(_funds.received >= oldFunds.received);
|
|
|
|
|
|
|
|
assert(_funds.sent >= oldFunds.sent);
|
|
|
|
|
|
|
|
assert(_funds.slashed >= oldFunds.slashed);
|
|
|
|
|
|
|
|
assert(_funds.received == _funds.balance + _funds.sent + _funds.slashed);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct MarketplaceFunds {
|
|
|
|
|
|
|
|
uint256 balance;
|
|
|
|
|
|
|
|
uint256 received;
|
|
|
|
uint256 received;
|
|
|
|
uint256 sent;
|
|
|
|
uint256 sent;
|
|
|
|
uint256 slashed;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|