Feat: price per byte (#208)

* changes reward => pricePerByte

* collateral => collateralPerByte

* updates tests

* introduces AskHelpers to compute price and collateral per slot

* adds public view function returning currentCollateral for the slot

* updates names for price and collateral

* uses pricePerSlotPerSecond in maxPriceHelper

* adds collateralPerSlot helper

* makes sure that the intended use of the <<currentCollateral>> view function is demonstrated in tests

* formatting

* fix comment

* mints more tokens so that it can be used with contracts tests in nim-codex

* Renaming <<collateral>> and <<reward>> to <<collateralPerByte>> and <<pricePerBytePerSecond>> respectively (merged in the meantime to the master)
This commit is contained in:
Marcin Czenko 2025-01-24 15:28:29 +01:00 committed by GitHub
parent d04acafde2
commit e74d3397a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 179 additions and 78 deletions

View File

@ -42,6 +42,7 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
using EnumerableSet for EnumerableSet.Bytes32Set;
using EnumerableSet for EnumerableSet.AddressSet;
using Requests for Request;
using AskHelpers for Ask;
IERC20 private immutable _token;
MarketplaceConfig private _config;
@ -72,14 +73,20 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
SlotState state;
RequestId requestId;
/// @notice Timestamp that signals when slot was filled
/// @dev Used for calculating payouts as hosts are paid based on time they actually host the content
/// @dev Used for calculating payouts as hosts are paid
/// based on time they actually host the content
uint256 filledAt;
uint256 slotIndex;
/// @notice Tracks the current amount of host's collateral that is to be payed out at the end of Slot's lifespan.
/// @dev When Slot is filled, the collateral is collected in amount of request.ask.collateral
/// @dev When Host is slashed for missing a proof the slashed amount is reflected in this variable
/// @notice Tracks the current amount of host's collateral that is
/// to be payed out at the end of Slot's lifespan.
/// @dev When Slot is filled, the collateral is collected in amount
/// of request.ask.collateralPerByte * request.ask.slotSize
/// (== request.ask.collateralPerSlot() when using the AskHelpers library)
/// @dev When Host is slashed for missing a proof the slashed amount is
/// reflected in this variable
uint256 currentCollateral;
address host; // address used for collateral interactions and identifying hosts
/// @notice address used for collateral interactions and identifying hosts
address host;
}
struct ActiveSlot {
@ -120,6 +127,10 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
return _token;
}
function currentCollateral(SlotId slotId) public view returns (uint256) {
return _slots[slotId].currentCollateral;
}
function requestStorage(Request calldata request) public {
RequestId id = request.id();
@ -137,10 +148,10 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
if (request.ask.proofProbability == 0) {
revert Marketplace_InsufficientProofProbability();
}
if (request.ask.collateral == 0) {
if (request.ask.collateralPerByte == 0) {
revert Marketplace_InsufficientCollateral();
}
if (request.ask.reward == 0) {
if (request.ask.pricePerBytePerSecond == 0) {
revert Marketplace_InsufficientReward();
}
if (bytes(request.content.cid).length == 0) {
@ -205,20 +216,20 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
// Collect collateral
uint256 collateralAmount;
uint256 collateralPerSlot = request.ask.collateralPerSlot();
if (slotState(slotId) == SlotState.Repair) {
// Host is repairing a slot and is entitled for repair reward, so he gets "discounted collateral"
// in this way he gets "physically" the reward at the end of the request when the full amount of collateral
// is returned to him.
collateralAmount =
request.ask.collateral -
((request.ask.collateral * _config.collateral.repairRewardPercentage) /
100);
collateralPerSlot -
((collateralPerSlot * _config.collateral.repairRewardPercentage) / 100);
} else {
collateralAmount = request.ask.collateral;
collateralAmount = collateralPerSlot;
}
_transferFrom(msg.sender, collateralAmount);
_marketplaceTotals.received += collateralAmount;
slot.currentCollateral = request.ask.collateral; // Even if he has collateral discounted, he is operating with full collateral
slot.currentCollateral = collateralPerSlot; // Even if he has collateral discounted, he is operating with full collateral
_addToMySlots(slot.host, slotId);
@ -326,7 +337,7 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
// TODO: Reward for validator that calls this function
if (missingProofs(slotId) % _config.collateral.slashCriterion == 0) {
uint256 slashedAmount = (request.ask.collateral *
uint256 slashedAmount = (request.ask.collateralPerSlot() *
_config.collateral.slashPercentage) / 100;
slot.currentCollateral -= slashedAmount;
if (
@ -586,7 +597,9 @@ contract Marketplace is SlotReservations, Proofs, StateRetrieval, Endian {
Request storage request = _requests[requestId];
if (startingTimestamp >= endingTimestamp)
revert Marketplace_StartNotBeforeExpiry();
return (endingTimestamp - startingTimestamp) * request.ask.reward;
return
(endingTimestamp - startingTimestamp) *
request.ask.pricePerSlotPerSecond();
}
function getHost(SlotId slotId) public view returns (address) {

View File

@ -17,8 +17,8 @@ struct Ask {
uint256 slotSize; // amount of storage per slot (in number of bytes)
uint256 duration; // how long content should be stored (in seconds)
uint256 proofProbability; // how often storage proofs are required
uint256 reward; // amount of tokens paid per second per slot to hosts
uint256 collateral; // amount of tokens required to be deposited by the hosts in order to fill the slot
uint256 pricePerBytePerSecond; // amount of tokens paid per second per byte to hosts
uint256 collateralPerByte; // amount of tokens per byte required to be deposited by the hosts in order to fill the slot
uint64 maxSlotLoss; // Max slots that can be lost without data considered to be lost
}
@ -45,7 +45,21 @@ enum SlotState {
Repair // when slot slot was forcible freed (host was kicked out from hosting the slot because of too many missed proofs) and needs to be repaired
}
library AskHelpers {
function collateralPerSlot(Ask memory ask) internal pure returns (uint256) {
return ask.collateralPerByte * ask.slotSize;
}
function pricePerSlotPerSecond(
Ask memory ask
) internal pure returns (uint256) {
return ask.pricePerBytePerSecond * ask.slotSize;
}
}
library Requests {
using AskHelpers for Ask;
function id(Request memory request) internal pure returns (RequestId) {
return RequestId.wrap(keccak256(abi.encode(request)));
}
@ -76,6 +90,9 @@ library Requests {
}
function maxPrice(Request memory request) internal pure returns (uint256) {
return request.ask.slots * request.ask.duration * request.ask.reward;
return
request.ask.slots *
request.ask.duration *
request.ask.pricePerSlotPerSecond();
}
}

View File

@ -1,16 +1,31 @@
const MINTED_TOKENS = 1_000_000_000
const MINTED_TOKENS = 1_000_000_000_000_000
module.exports = async ({ deployments, getNamedAccounts, getUnnamedAccounts, network }) => {
module.exports = async ({
deployments,
getNamedAccounts,
getUnnamedAccounts,
network,
}) => {
const { deployer } = await getNamedAccounts()
const tokenDeployment = await deployments.deploy("TestToken", { from: deployer })
const token = await hre.ethers.getContractAt("TestToken", tokenDeployment.address)
const tokenDeployment = await deployments.deploy("TestToken", {
from: deployer,
})
const token = await hre.ethers.getContractAt(
"TestToken",
tokenDeployment.address
)
const accounts = [...Object.values(await getNamedAccounts()), ...(await getUnnamedAccounts())]
const accounts = [
...Object.values(await getNamedAccounts()),
...(await getUnnamedAccounts()),
]
if (network.tags.local) {
for (const account of accounts) {
console.log(`Minting ${MINTED_TOKENS} tokens to address ${account}`)
const transaction = await token.mint(account, MINTED_TOKENS, { from: deployer })
const transaction = await token.mint(account, MINTED_TOKENS, {
from: deployer,
})
await transaction.wait()
}
console.log()

View File

@ -23,7 +23,12 @@ const {
waitUntilSlotFailed,
patchOverloads,
} = require("./marketplace")
const { maxPrice, payoutForDuration } = require("./price")
const {
maxPrice,
pricePerSlotPerSecond,
payoutForDuration,
} = require("./price")
const { collateralPerSlot } = require("./collateral")
const {
snapshot,
revert,
@ -35,7 +40,7 @@ const {
} = require("./evm")
const { arrayify } = require("ethers/lib/utils")
const ACCOUNT_STARTING_BALANCE = 1_000_000_000
const ACCOUNT_STARTING_BALANCE = 1_000_000_000_000_000
describe("Marketplace constructor", function () {
let Marketplace, token, verifier, config
@ -257,14 +262,14 @@ describe("Marketplace", function () {
})
it("is rejected when insufficient collateral", async function () {
request.ask.collateral = 0
request.ask.collateralPerByte = 0
await expect(marketplace.requestStorage(request)).to.be.revertedWith(
"Marketplace_InsufficientCollateral"
)
})
it("is rejected when insufficient reward", async function () {
request.ask.reward = 0
request.ask.pricePerBytePerSecond = 0
await expect(marketplace.requestStorage(request)).to.be.revertedWith(
"Marketplace_InsufficientReward"
)
@ -284,7 +289,7 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
await token.approve(marketplace.address, collateralPerSlot(request))
})
it("emits event when slot is filled", async function () {
@ -315,10 +320,12 @@ describe("Marketplace", function () {
await advanceTimeForNextBlock(config.proofs.period + 1)
const startBalance = await token.balanceOf(host.address)
const collateral = collateralPerSlot(request)
const discountedCollateral =
request.ask.collateral -
(request.ask.collateral * config.collateral.repairRewardPercentage) /
100
collateral -
Math.round(
(collateral * config.collateral.repairRewardPercentage) / 100
)
await token.approve(marketplace.address, discountedCollateral)
await marketplace.fillSlot(slot.request, slot.index, proof)
const endBalance = await token.balanceOf(host.address)
@ -404,7 +411,7 @@ describe("Marketplace", function () {
const lastSlot = request.ask.slots - 1
await token.approve(
marketplace.address,
request.ask.collateral * lastSlot
collateralPerSlot(request) * lastSlot
)
await token.approve(marketplace.address, maxPrice(request) * lastSlot)
for (let i = 0; i <= lastSlot; i++) {
@ -432,7 +439,7 @@ describe("Marketplace", function () {
})
it("is rejected when approved collateral is insufficient", async function () {
let insufficient = request.ask.collateral - 1
let insufficient = collateralPerSlot(request) - 1
await token.approve(marketplace.address, insufficient)
await marketplace.reserveSlot(slot.request, slot.index)
await expect(
@ -441,12 +448,12 @@ describe("Marketplace", function () {
})
it("collects only requested collateral and not more", async function () {
await token.approve(marketplace.address, request.ask.collateral * 2)
await token.approve(marketplace.address, collateralPerSlot(request) * 2)
const startBalance = await token.balanceOf(host.address)
await marketplace.reserveSlot(slot.request, slot.index)
await marketplace.fillSlot(slot.request, slot.index, proof)
const endBalance = await token.balanceOf(host.address)
expect(startBalance - endBalance).to.eq(request.ask.collateral)
expect(startBalance - endBalance).to.eq(collateralPerSlot(request))
})
})
@ -456,7 +463,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
await marketplace.reserveSlot(slot.request, slot.index)
await marketplace.fillSlot(slot.request, slot.index, proof)
await advanceTimeForNextBlock(config.proofs.period)
@ -494,7 +502,8 @@ describe("Marketplace", function () {
await marketplace.requestStorage(request)
requestTime = await currentTime()
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("sets the request end time to now + duration", async function () {
@ -551,7 +560,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("fails to free slot when slot not filled", async function () {
@ -589,7 +599,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("finished request pays out reward based on time hosted", async function () {
@ -611,8 +622,9 @@ describe("Marketplace", function () {
const endBalanceHost = await token.balanceOf(host.address)
expect(expectedPayouts[slot.index]).to.be.lt(maxPrice(request))
const collateral = collateralPerSlot(request)
expect(endBalanceHost - startBalanceHost).to.equal(
expectedPayouts[slot.index] + request.ask.collateral
expectedPayouts[slot.index] + collateral
)
})
@ -625,6 +637,10 @@ describe("Marketplace", function () {
hostCollateralRecipient.address
)
const collateralToBeReturned = await marketplace.currentCollateral(
slotId(slot)
)
await marketplace.freeSlot(
slotId(slot),
hostRewardRecipient.address,
@ -638,8 +654,9 @@ describe("Marketplace", function () {
const endBalanceHost = await token.balanceOf(host.address)
expect(endBalanceHost).to.equal(startBalanceHost)
expect(endBalanceCollateral - startBalanceCollateral).to.equal(
request.ask.collateral
collateralPerSlot(request)
)
expect(collateralToBeReturned).to.equal(collateralPerSlot(request))
})
it("pays reward to host reward address if specified", async function () {
@ -679,7 +696,8 @@ describe("Marketplace", function () {
await waitUntilCancelled(request)
await marketplace.freeSlot(slotId(slot))
const expectedPartialPayout = (expiresAt - filledAt) * request.ask.reward
const expectedPartialPayout =
(expiresAt - filledAt) * pricePerSlotPerSecond(request)
const endBalance = await token.balanceOf(host.address)
expect(endBalance - ACCOUNT_STARTING_BALANCE).to.be.equal(
expectedPartialPayout
@ -704,13 +722,19 @@ describe("Marketplace", function () {
const startBalanceCollateral = await token.balanceOf(
hostCollateralRecipient.address
)
const collateralToBeReturned = await marketplace.currentCollateral(
slotId(slot)
)
await marketplace.freeSlot(
slotId(slot),
hostRewardRecipient.address,
hostCollateralRecipient.address
)
const expectedPartialPayout = (expiresAt - filledAt) * request.ask.reward
const expectedPartialPayout =
(expiresAt - filledAt) * pricePerSlotPerSecond(request)
const endBalanceReward = await token.balanceOf(
hostRewardRecipient.address
@ -726,8 +750,10 @@ describe("Marketplace", function () {
hostCollateralRecipient.address
)
expect(endBalanceCollateral - startBalanceCollateral).to.be.equal(
request.ask.collateral
collateralPerSlot(request)
)
expect(collateralToBeReturned).to.be.equal(collateralPerSlot(request))
})
it("does not pay when the contract hasn't ended", async function () {
@ -777,21 +803,23 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("emits event when all slots are filled", async function () {
const lastSlot = request.ask.slots - 1
await token.approve(
marketplace.address,
request.ask.collateral * lastSlot
collateralPerSlot(request) * lastSlot
)
for (let i = 0; i < lastSlot; i++) {
await marketplace.reserveSlot(slot.request, i)
await marketplace.fillSlot(slot.request, i, proof)
}
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
await marketplace.reserveSlot(slot.request, lastSlot)
await expect(marketplace.fillSlot(slot.request, lastSlot, proof))
.to.emit(marketplace, "RequestFulfilled")
@ -799,7 +827,8 @@ describe("Marketplace", function () {
})
it("sets state when all slots are filled", async function () {
const slots = request.ask.slots
await token.approve(marketplace.address, request.ask.collateral * slots)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral * slots)
for (let i = 0; i < slots; i++) {
await marketplace.reserveSlot(slot.request, i)
await marketplace.fillSlot(slot.request, i, proof)
@ -812,7 +841,7 @@ describe("Marketplace", function () {
const lastSlot = request.ask.slots - 1
await token.approve(
marketplace.address,
request.ask.collateral * (lastSlot + 1)
collateralPerSlot(request) * (lastSlot + 1)
)
for (let i = 0; i <= lastSlot; i++) {
await marketplace.reserveSlot(slot.request, i)
@ -830,7 +859,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("rejects withdraw when request not yet timed out", async function () {
@ -852,7 +882,7 @@ describe("Marketplace", function () {
const lastSlot = request.ask.slots - 1
await token.approve(
marketplace.address,
request.ask.collateral * (lastSlot + 1)
collateralPerSlot(request) * (lastSlot + 1)
)
for (let i = 0; i <= lastSlot; i++) {
await marketplace.reserveSlot(slot.request, i)
@ -915,7 +945,7 @@ describe("Marketplace", function () {
// at the time of expiry and hence the user would get the full "expiry window" reward back.
expect(endBalancePayout - startBalancePayout).to.be.gt(0)
expect(endBalancePayout - startBalancePayout).to.be.lte(
request.expiry * request.ask.reward
request.expiry * pricePerSlotPerSecond(request)
)
})
@ -974,7 +1004,7 @@ describe("Marketplace", function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
await waitUntilCancelled(request)
const expectedPartialhostRewardRecipient =
(expiresAt - filledAt) * request.ask.reward
(expiresAt - filledAt) * pricePerSlotPerSecond(request)
switchAccount(client)
await marketplace.withdrawFunds(
@ -1018,7 +1048,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("is 'New' initially", async function () {
@ -1056,7 +1087,7 @@ describe("Marketplace", function () {
it("does not change to 'Failed' before it is started", async function () {
await token.approve(
marketplace.address,
request.ask.collateral * (request.ask.maxSlotLoss + 1)
collateralPerSlot(request) * (request.ask.maxSlotLoss + 1)
)
for (let i = 0; i <= request.ask.maxSlotLoss; i++) {
await marketplace.reserveSlot(slot.request, i)
@ -1098,7 +1129,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
async function waitUntilProofIsRequired(id) {
@ -1185,7 +1217,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
async function waitUntilProofWillBeRequired(id) {
@ -1276,7 +1309,8 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
async function waitUntilProofIsRequired(id) {
@ -1315,8 +1349,10 @@ describe("Marketplace", function () {
await advanceTimeForNextBlock(period + 1)
await marketplace.markProofAsMissing(id, missedPeriod)
}
const expectedBalance =
(request.ask.collateral * (100 - slashPercentage)) / 100
const collateral = collateralPerSlot(request)
const expectedBalance = Math.round(
(collateral * (100 - slashPercentage)) / 100
)
expect(
BigNumber.from(expectedBalance).eq(
@ -1327,9 +1363,10 @@ describe("Marketplace", function () {
})
it("frees slot when collateral slashed below minimum threshold", async function () {
const collateral = collateralPerSlot(request)
const minimum =
request.ask.collateral -
(request.ask.collateral *
collateral -
(collateral *
config.collateral.maxNumberOfSlashes *
config.collateral.slashPercentage) /
100
@ -1352,9 +1389,10 @@ describe("Marketplace", function () {
})
it("free slot when minimum reached and resets missed proof counter", async function () {
const collateral = collateralPerSlot(request)
const minimum =
request.ask.collateral -
(request.ask.collateral *
collateral -
(collateral *
config.collateral.maxNumberOfSlashes *
config.collateral.slashPercentage) /
100
@ -1386,7 +1424,8 @@ describe("Marketplace", function () {
describe("list of active requests", function () {
beforeEach(async function () {
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
switchAccount(client)
await token.approve(marketplace.address, maxPrice(request))
})
@ -1440,14 +1479,16 @@ describe("Marketplace", function () {
await token.approve(marketplace.address, maxPrice(request))
await marketplace.requestStorage(request)
switchAccount(host)
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
})
it("adds slot to list when filling slot", async function () {
await marketplace.reserveSlot(slot.request, slot.index)
await marketplace.fillSlot(slot.request, slot.index, proof)
let slot1 = { ...slot, index: slot.index + 1 }
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
await marketplace.reserveSlot(slot.request, slot1.index)
await marketplace.fillSlot(slot.request, slot1.index, proof)
expect(await marketplace.mySlots()).to.have.members([
@ -1460,10 +1501,11 @@ describe("Marketplace", function () {
await marketplace.reserveSlot(slot.request, slot.index)
await marketplace.fillSlot(slot.request, slot.index, proof)
let slot1 = { ...slot, index: slot.index + 1 }
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
await marketplace.reserveSlot(slot.request, slot1.index)
await marketplace.fillSlot(slot.request, slot1.index, proof)
await token.approve(marketplace.address, request.ask.collateral)
await token.approve(marketplace.address, collateral)
await marketplace.freeSlot(slotId(slot))
expect(await marketplace.mySlots()).to.have.members([slotId(slot1)])
})
@ -1473,7 +1515,8 @@ describe("Marketplace", function () {
await marketplace.fillSlot(slot.request, slot.index, proof)
let slot1 = { ...slot, index: slot.index + 1 }
await token.approve(marketplace.address, request.ask.collateral)
const collateral = collateralPerSlot(request)
await token.approve(marketplace.address, collateral)
await marketplace.reserveSlot(slot.request, slot1.index)
await marketplace.fillSlot(slot.request, slot1.index, proof)
await waitUntilCancelled(request)

5
test/collateral.js Normal file
View File

@ -0,0 +1,5 @@
function collateralPerSlot(request) {
return request.ask.collateralPerByte * request.ask.slotSize
}
module.exports = { collateralPerSlot }

View File

@ -29,9 +29,9 @@ const exampleRequest = async () => {
slotSize: 1 * 1024 * 1024 * 1024, // 1 Gigabyte
duration: hours(10),
proofProbability: 4, // require a proof roughly once every 4 periods
reward: 84,
pricePerBytePerSecond: 1,
maxSlotLoss: 2,
collateral: 200,
collateralPerByte: 1,
},
content: {
cid: "zb2rhheVmk3bLks5MgzTqyznLu1zqGH5jrfTA1eAZXrjx7Vob",

View File

@ -15,8 +15,8 @@ function askToArray(ask) {
ask.slotSize,
ask.duration,
ask.proofProbability,
ask.reward,
ask.collateral,
ask.pricePerBytePerSecond,
ask.collateralPerByte,
ask.maxSlotLoss,
]
}

View File

@ -1,6 +1,7 @@
const { advanceTimeToForNextBlock, currentTime } = require("./evm")
const { slotId, requestId } = require("./ids")
const { maxPrice, payoutForDuration } = require("./price")
const { collateralPerSlot } = require("./collateral")
/**
* @dev This will not advance the time right on the "expiry threshold" but will most probably "overshoot it"
@ -15,7 +16,8 @@ async function waitUntilCancelled(request) {
}
async function waitUntilSlotsFilled(contract, request, proof, token, slots) {
await token.approve(contract.address, request.ask.collateral * slots.length)
let collateral = collateralPerSlot(request)
await token.approve(contract.address, collateral * slots.length)
let requestEnd = (await contract.requestEnd(requestId(request))).toNumber()
const payouts = []

View File

@ -1,9 +1,15 @@
function pricePerSlotPerSecond(request) {
return request.ask.pricePerBytePerSecond * request.ask.slotSize
}
function maxPrice(request) {
return request.ask.slots * request.ask.duration * request.ask.reward
return (
request.ask.slots * request.ask.duration * pricePerSlotPerSecond(request)
)
}
function payoutForDuration(request, start, end) {
return (end - start) * request.ask.reward
return (end - start) * pricePerSlotPerSecond(request)
}
module.exports = { maxPrice, payoutForDuration }
module.exports = { maxPrice, pricePerSlotPerSecond, payoutForDuration }