feat: protocol fee

This commit is contained in:
Adam Uhlíř 2025-03-24 17:36:21 +01:00
parent 129e82f707
commit da59b7f31c
No known key found for this signature in database
GPG Key ID: 1D17A9E81F76155B
7 changed files with 114 additions and 34 deletions

View File

@ -20,7 +20,8 @@ const DEFAULT_CONFIGURATION = {
reservations: { reservations: {
maxReservations: 3, maxReservations: 3,
}, },
requestDurationLimit: 60*60*24*30 // 30 days requestDurationLimit: 60*60*24*30, // 30 days
protocolFeePermille: 5, // dictates how much of the request price (defined by its ask) should go to protocol fee that is burned; specified in a per mille
} }
function loadConfiguration(name) { function loadConfiguration(name) {

View File

@ -4,6 +4,7 @@ module.exports = {
maxNumberOfSlashes: 2, maxNumberOfSlashes: 2,
slashPercentage: 20, slashPercentage: 20,
validatorRewardPercentage: 20, // percentage of the slashed amount going to the validators validatorRewardPercentage: 20, // percentage of the slashed amount going to the validators
protocolFeePermille: 5, // dictates how much of the request price (defined by its ask) should go to protocol fee that is burned; specified in a per mille
}, },
proofs: { proofs: {
// period has to be less than downtime * blocktime // period has to be less than downtime * blocktime

View File

@ -9,6 +9,7 @@ struct MarketplaceConfig {
ProofConfig proofs; ProofConfig proofs;
SlotReservationsConfig reservations; SlotReservationsConfig reservations;
Duration requestDurationLimit; Duration requestDurationLimit;
uint16 protocolFeePermille; // dictates how much of the request price (defined by its ask) should go to protocol fee that is burned; specified in a per mille
} }
struct CollateralConfig { struct CollateralConfig {

View File

@ -37,6 +37,7 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
error Marketplace_SlotIsFree(); error Marketplace_SlotIsFree();
error Marketplace_ReservationRequired(); error Marketplace_ReservationRequired();
error Marketplace_DurationExceedsLimit(); error Marketplace_DurationExceedsLimit();
error Marketplace_ProtocolFeePermilleTooHigh();
using SafeERC20 for IERC20; using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.Bytes32Set; using EnumerableSet for EnumerableSet.Bytes32Set;
@ -84,6 +85,12 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
) SlotReservations(config.reservations) Proofs(config.proofs, verifier) { ) SlotReservations(config.reservations) Proofs(config.proofs, verifier) {
_vault = vault_; _vault = vault_;
config.collateral.checkCorrectness(); config.collateral.checkCorrectness();
require(
config.protocolFeePermille <= 1000,
Marketplace_ProtocolFeePermilleTooHigh()
);
_config = config; _config = config;
} }
@ -149,6 +156,8 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
TokensPerSecond pricePerSecond = request.ask.pricePerSecond(); TokensPerSecond pricePerSecond = request.ask.pricePerSecond();
uint128 price = pricePerSecond.accumulate(request.ask.duration); uint128 price = pricePerSecond.accumulate(request.ask.duration);
_collectProtocolFee(request.client, request.ask);
FundId fund = id.asFundId(); FundId fund = id.asFundId();
AccountId account = _vault.clientAccount(request.client); AccountId account = _vault.clientAccount(request.client);
_vault.lock(fund, expiresAt, endsAt); _vault.lock(fund, expiresAt, endsAt);
@ -158,6 +167,15 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
emit StorageRequested(id, request.ask, expiresAt); emit StorageRequested(id, request.ask, expiresAt);
} }
/**
* Calculates the protocol fee, which is then burned.
* @param ask Request's ask
*/
function _collectProtocolFee(address from, Ask memory ask) private {
uint256 fee = protocolFeeForRequestAsk(ask);
_vault.getToken().safeTransferFrom(from, address(0xdead), fee);
}
/** /**
* @notice Fills a slot. Reverts if an invalid proof of the slot data is * @notice Fills a slot. Reverts if an invalid proof of the slot data is
provided. provided.
@ -466,6 +484,13 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
return _requestContexts[requestId].expiresAt; return _requestContexts[requestId].expiresAt;
} }
function protocolFeeForRequestAsk(Ask memory ask) public view returns(uint256) {
TokensPerSecond pricePerSecond = ask.pricePerSecond();
uint128 requestPrice = pricePerSecond.accumulate(ask.duration);
return (requestPrice/1000) * _config.protocolFeePermille;
}
function getHost(SlotId slotId) public view returns (address) { function getHost(SlotId slotId) public view returns (address) {
return _slots[slotId].host; return _slots[slotId].host;
} }

View File

@ -25,8 +25,10 @@ const {
} = require("./marketplace") } = require("./marketplace")
const { const {
maxPrice, maxPrice,
maxPriceWithProtocolFee,
pricePerSlotPerSecond, pricePerSlotPerSecond,
payoutForDuration, payoutForDuration,
protocolFee
} = require("./price") } = require("./price")
const { collateralPerSlot, repairReward } = require("./collateral") const { collateralPerSlot, repairReward } = require("./collateral")
const { const {
@ -91,6 +93,14 @@ describe("Marketplace constructor", function () {
Marketplace.deploy(config, vault.address, verifier.address) Marketplace.deploy(config, vault.address, verifier.address)
).to.be.revertedWith("Marketplace_MaximumSlashingTooHigh") ).to.be.revertedWith("Marketplace_MaximumSlashingTooHigh")
}) })
it("should reject when protocol fee permille exceeds 1000%%", async () => {
config.protocolFeePermille = 1001
await expect(
Marketplace.deploy(config, vault.address, verifier.address)
).to.be.revertedWith("Marketplace_ProtocolFeePermilleTooHigh")
})
}) })
describe("Marketplace", function () { describe("Marketplace", function () {
@ -158,7 +168,7 @@ describe("Marketplace", function () {
}) })
it("emits event when storage is requested", async function () { it("emits event when storage is requested", async function () {
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
const now = await currentTime() const now = await currentTime()
await setNextBlockTimestamp(now) await setNextBlockTimestamp(now)
const expectedExpiry = now + request.expiry const expectedExpiry = now + request.expiry
@ -168,7 +178,7 @@ describe("Marketplace", function () {
}) })
it("allows retrieval of request details", async function () { it("allows retrieval of request details", async function () {
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
const id = requestId(request) const id = requestId(request)
expect(await marketplace.getRequest(id)).to.be.request(request) expect(await marketplace.getRequest(id)).to.be.request(request)
@ -176,7 +186,7 @@ describe("Marketplace", function () {
it("rejects request with invalid client address", async function () { it("rejects request with invalid client address", async function () {
let invalid = { ...request, client: host.address } let invalid = { ...request, client: host.address }
await token.approve(marketplace.address, maxPrice(invalid)) await token.approve(marketplace.address, maxPriceWithProtocolFee(invalid, config))
await expect(marketplace.requestStorage(invalid)).to.be.revertedWith( await expect(marketplace.requestStorage(invalid)).to.be.revertedWith(
"Marketplace_InvalidClientAddress" "Marketplace_InvalidClientAddress"
) )
@ -191,7 +201,7 @@ describe("Marketplace", function () {
}) })
it("rejects request with insufficient payment", async function () { it("rejects request with insufficient payment", async function () {
let insufficient = maxPrice(request) - 1 let insufficient = maxPriceWithProtocolFee(request, config) - 1
await token.approve(marketplace.address, insufficient) await token.approve(marketplace.address, insufficient)
await expect(marketplace.requestStorage(request)).to.be.revertedWith( await expect(marketplace.requestStorage(request)).to.be.revertedWith(
"ERC20InsufficientAllowance" "ERC20InsufficientAllowance"
@ -199,7 +209,7 @@ describe("Marketplace", function () {
}) })
it("rejects request when expiry out of bounds", async function () { it("rejects request when expiry out of bounds", async function () {
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
request.expiry = request.ask.duration + 1 request.expiry = request.ask.duration + 1
await expect(marketplace.requestStorage(request)).to.be.revertedWith( await expect(marketplace.requestStorage(request)).to.be.revertedWith(
@ -227,7 +237,7 @@ describe("Marketplace", function () {
}) })
it("rejects resubmission of request", async function () { it("rejects resubmission of request", async function () {
await token.approve(marketplace.address, maxPrice(request) * 2) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config) * 2)
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
await expect(marketplace.requestStorage(request)).to.be.revertedWith( await expect(marketplace.requestStorage(request)).to.be.revertedWith(
"Marketplace_RequestAlreadyExists" "Marketplace_RequestAlreadyExists"
@ -276,7 +286,7 @@ describe("Marketplace", function () {
describe("filling a slot with collateral", function () { describe("filling a slot with collateral", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
await token.approve(marketplace.address, collateralPerSlot(request)) await token.approve(marketplace.address, collateralPerSlot(request))
@ -356,7 +366,7 @@ describe("Marketplace", function () {
it("is rejected when request is cancelled", async function () { it("is rejected when request is cancelled", async function () {
switchAccount(client) switchAccount(client)
let expired = { ...request, expiry: hours(1) + 1 } let expired = { ...request, expiry: hours(1) + 1 }
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(expired) await marketplace.requestStorage(expired)
await waitUntilCancelled(marketplace, expired) await waitUntilCancelled(marketplace, expired)
switchAccount(host) switchAccount(host)
@ -395,7 +405,7 @@ describe("Marketplace", function () {
marketplace.address, marketplace.address,
collateralPerSlot(request) * lastSlot collateralPerSlot(request) * lastSlot
) )
await token.approve(marketplace.address, maxPrice(request) * lastSlot) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config) * lastSlot)
for (let i = 0; i <= lastSlot; i++) { for (let i = 0; i <= lastSlot; i++) {
await marketplace.reserveSlot(slot.request, i) await marketplace.reserveSlot(slot.request, i)
await marketplace.fillSlot(slot.request, i, proof) await marketplace.fillSlot(slot.request, i, proof)
@ -415,7 +425,7 @@ describe("Marketplace", function () {
describe("filling slot without collateral", function () { describe("filling slot without collateral", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
}) })
@ -442,7 +452,7 @@ describe("Marketplace", function () {
describe("submitting proofs when slot is filled", function () { describe("submitting proofs when slot is filled", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -480,7 +490,7 @@ describe("Marketplace", function () {
var requestTime var requestTime
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
requestTime = await currentTime() requestTime = await currentTime()
switchAccount(host) switchAccount(host)
@ -524,7 +534,7 @@ describe("Marketplace", function () {
id = slotId(slot) id = slotId(slot)
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -563,7 +573,7 @@ describe("Marketplace", function () {
describe("paying out a slot", function () { describe("paying out a slot", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -643,7 +653,7 @@ describe("Marketplace", function () {
describe("fulfilling a request", function () { describe("fulfilling a request", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -699,7 +709,7 @@ describe("Marketplace", function () {
describe("withdrawing funds", function () { describe("withdrawing funds", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
// wait a bit, so that there are funds for the client to withdraw // wait a bit, so that there are funds for the client to withdraw
@ -784,13 +794,13 @@ describe("Marketplace", function () {
const startBalance = await token.balanceOf(client.address) const startBalance = await token.balanceOf(client.address)
await marketplace.withdrawFunds(slot.request) await marketplace.withdrawFunds(slot.request)
const endBalance = await token.balanceOf(client.address) const endBalance = await token.balanceOf(client.address)
expect(endBalance - startBalance).to.equal(maxPrice(request)) expect(endBalance - startBalance).to.equal(maxPriceWithProtocolFee(request, config) - protocolFee(request, config))
}) })
it("refunds the client for the remaining time when request fails", async function () { it("refunds the client for the remaining time when request fails", async function () {
await waitUntilStarted(marketplace, request, proof, token) await waitUntilStarted(marketplace, request, proof, token)
await waitUntilFailed(marketplace, request) await waitUntilFailed(marketplace, request)
const failedAt = await currentTime() const startedAt = await currentTime()
await waitUntilFinished(marketplace, requestId(request)) await waitUntilFinished(marketplace, requestId(request))
const finishedAt = await currentTime() const finishedAt = await currentTime()
@ -800,10 +810,7 @@ describe("Marketplace", function () {
await marketplace.withdrawFunds(slot.request) await marketplace.withdrawFunds(slot.request)
const endBalance = await token.balanceOf(client.address) const endBalance = await token.balanceOf(client.address)
const expectedRefund = const expectedRefund = payoutForDuration(request, startedAt, finishedAt) - protocolFee(request, config)
(finishedAt - failedAt) *
request.ask.slots *
pricePerSlotPerSecond(request)
expect(endBalance - startBalance).to.be.gte(expectedRefund) expect(endBalance - startBalance).to.be.gte(expectedRefund)
}) })
@ -816,8 +823,7 @@ describe("Marketplace", function () {
await setNextBlockTimestamp(filledAt) await setNextBlockTimestamp(filledAt)
await marketplace.fillSlot(slot.request, slot.index, proof) await marketplace.fillSlot(slot.request, slot.index, proof)
await waitUntilCancelled(marketplace, request) await waitUntilCancelled(marketplace, request)
const expectedPartialHostReward = const expectedPartialHostReward = payoutForDuration(request, filledAt, expiresAt)
(expiresAt - filledAt) * pricePerSlotPerSecond(request)
switchAccount(client) switchAccount(client)
const startBalance = await token.balanceOf(client.address) const startBalance = await token.balanceOf(client.address)
@ -845,7 +851,7 @@ describe("Marketplace", function () {
const refund = payoutForDuration(request, freedAt, requestEnd) const refund = payoutForDuration(request, freedAt, requestEnd)
const reward = repairReward(config, collateralPerSlot(request)) const reward = repairReward(config, collateralPerSlot(request))
expect(endBalance - startBalance).to.equal( expect(endBalance - startBalance).to.equal(
maxPrice(request) - hostPayouts + refund + reward maxPrice(request, config) - hostPayouts + refund + reward
) )
}) })
}) })
@ -855,7 +861,7 @@ describe("Marketplace", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -929,7 +935,7 @@ describe("Marketplace", function () {
;({ periodOf, periodEnd } = periodic(period)) ;({ periodOf, periodEnd } = periodic(period))
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -999,7 +1005,7 @@ describe("Marketplace", function () {
describe("slot probability", function () { describe("slot probability", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -1028,7 +1034,7 @@ describe("Marketplace", function () {
;({ periodOf, periodEnd } = periodic(period)) ;({ periodOf, periodEnd } = periodic(period))
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -1113,7 +1119,7 @@ describe("Marketplace", function () {
;({ periodOf, periodEnd } = periodic(period)) ;({ periodOf, periodEnd } = periodic(period))
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -1228,7 +1234,7 @@ describe("Marketplace", function () {
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral) await token.approve(marketplace.address, collateral)
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
}) })
it("adds request to list when requesting storage", async function () { it("adds request to list when requesting storage", async function () {
@ -1272,7 +1278,7 @@ describe("Marketplace", function () {
describe("list of active slots", function () { describe("list of active slots", function () {
beforeEach(async function () { beforeEach(async function () {
switchAccount(client) switchAccount(client)
await token.approve(marketplace.address, maxPrice(request)) await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request) await marketplace.requestStorage(request)
switchAccount(host) switchAccount(host)
const collateral = collateralPerSlot(request) const collateral = collateralPerSlot(request)
@ -1344,4 +1350,34 @@ describe("Marketplace", function () {
expect(await marketplace.mySlots()).to.not.contain(slotId(slot)) expect(await marketplace.mySlots()).to.not.contain(slotId(slot))
}) })
}) })
describe("protocol fee", function () {
const dead = "0x000000000000000000000000000000000000dead"
it("is burned when storage request is created", async function () {
switchAccount(client)
let priceWithProtocolFee = maxPriceWithProtocolFee(request, config)
await token.approve(marketplace.address, priceWithProtocolFee)
const startBalance = await token.balanceOf(client.address)
const startDeadBalance = await token.balanceOf(dead)
await expect(marketplace.requestStorage(request))
.to.emit(marketplace, "StorageRequested")
const endBalance = await token.balanceOf(client.address)
const endDeadBalance = await token.balanceOf(dead)
expect(startBalance - endBalance).to.equal(maxPriceWithProtocolFee(request, config))
expect(endDeadBalance - startDeadBalance).to.equal(protocolFee(request, config))
})
it("is not returned when request is cancelled", async function () {
switchAccount(client)
await token.approve(marketplace.address, maxPriceWithProtocolFee(request, config))
await marketplace.requestStorage(request)
await waitUntilCancelled(marketplace, request)
const startBalance = await token.balanceOf(client.address)
await marketplace.withdrawFunds(slot.request)
const endBalance = await token.balanceOf(client.address)
expect(endBalance - startBalance).to.equal(maxPriceWithProtocolFee(request, config) - protocolFee(request, config))
})
})
}) })

View File

@ -20,6 +20,7 @@ const exampleConfiguration = () => ({
maxReservations: 3, maxReservations: 3,
}, },
requestDurationLimit: 60 * 60 * 24 * 30, // 30 days requestDurationLimit: 60 * 60 * 24 * 30, // 30 days
protocolFeePermille: 5,
}) })
const exampleRequest = async () => { const exampleRequest = async () => {

View File

@ -2,14 +2,29 @@ function pricePerSlotPerSecond(request) {
return request.ask.pricePerBytePerSecond * request.ask.slotSize return request.ask.pricePerBytePerSecond * request.ask.slotSize
} }
function protocolFee(request, config) {
let requestPrice = request.ask.slots * request.ask.duration * pricePerSlotPerSecond(request)
return (requestPrice / 1000) * config.protocolFeePermille
}
function maxPrice(request) { function maxPrice(request) {
return ( return (
request.ask.slots * request.ask.duration * pricePerSlotPerSecond(request) request.ask.slots * request.ask.duration * pricePerSlotPerSecond(request)
) )
} }
function maxPriceWithProtocolFee(request, config) {
return maxPrice(request) + protocolFee(request, config)
}
function maxPriceWithProtocolFee(request, config) {
let requestPrice = request.ask.slots * request.ask.duration * pricePerSlotPerSecond(request)
let protocolFee = (requestPrice / 1000) * config.protocolFeePermille
return requestPrice + protocolFee
}
function payoutForDuration(request, start, end) { function payoutForDuration(request, start, end) {
return (end - start) * pricePerSlotPerSecond(request) return (end - start) * pricePerSlotPerSecond(request)
} }
module.exports = { maxPrice, pricePerSlotPerSecond, payoutForDuration } module.exports = { maxPrice, maxPriceWithProtocolFee, protocolFee, pricePerSlotPerSecond, payoutForDuration }