[marketplace] Reward is paid out per second per slot
This commit is contained in:
parent
1d951ef8f8
commit
3e9fffb526
|
@ -39,9 +39,10 @@ contract Marketplace is Collateral, Proofs {
|
||||||
|
|
||||||
_createLock(id, request.expiry);
|
_createLock(id, request.expiry);
|
||||||
|
|
||||||
funds.received += request.ask.reward;
|
uint256 amount = price(request);
|
||||||
funds.balance += request.ask.reward;
|
funds.received += amount;
|
||||||
transferFrom(msg.sender, request.ask.reward);
|
funds.balance += amount;
|
||||||
|
transferFrom(msg.sender, amount);
|
||||||
|
|
||||||
emit StorageRequested(id, request.ask);
|
emit StorageRequested(id, request.ask);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +85,7 @@ contract Marketplace is Collateral, Proofs {
|
||||||
Slot storage slot = slots[slotId];
|
Slot storage slot = slots[slotId];
|
||||||
require(slot.host != address(0), "Slot empty");
|
require(slot.host != address(0), "Slot empty");
|
||||||
require(!slot.hostPaid, "Already paid");
|
require(!slot.hostPaid, "Already paid");
|
||||||
uint256 amount = requests[requestId].ask.reward;
|
uint256 amount = pricePerSlot(requests[requestId]);
|
||||||
funds.sent += amount;
|
funds.sent += amount;
|
||||||
funds.balance -= amount;
|
funds.balance -= amount;
|
||||||
slot.hostPaid = true;
|
slot.hostPaid = true;
|
||||||
|
@ -111,6 +112,14 @@ contract Marketplace is Collateral, Proofs {
|
||||||
return _end(contractId);
|
return _end(contractId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function price(Request calldata request) private pure returns (uint256) {
|
||||||
|
return request.ask.slots * request.ask.duration * request.ask.reward;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pricePerSlot(Request memory request) private pure returns (uint256) {
|
||||||
|
return request.ask.duration * request.ask.reward;
|
||||||
|
}
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
address client;
|
address client;
|
||||||
Ask ask;
|
Ask ask;
|
||||||
|
@ -123,7 +132,7 @@ contract Marketplace is Collateral, Proofs {
|
||||||
uint256 size; // size of requested storage in number of bytes
|
uint256 size; // size of requested storage in number of bytes
|
||||||
uint256 duration; // how long content should be stored (in seconds)
|
uint256 duration; // how long content should be stored (in seconds)
|
||||||
uint256 proofProbability; // how often storage proofs are required
|
uint256 proofProbability; // how often storage proofs are required
|
||||||
uint256 reward; // reward that the client will pay (in number of tokens)
|
uint256 reward; // amount of tokens paid per second per slot to hosts
|
||||||
uint64 slots; // the total number of hosts that store the data set
|
uint64 slots; // the total number of hosts that store the data set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ const { expect } = require("chai")
|
||||||
const { exampleRequest } = require("./examples")
|
const { exampleRequest } = require("./examples")
|
||||||
const { now, hours } = require("./time")
|
const { now, hours } = require("./time")
|
||||||
const { requestId, slotId, askToArray } = require("./ids")
|
const { requestId, slotId, askToArray } = require("./ids")
|
||||||
|
const { price, pricePerSlot } = require("./price")
|
||||||
const {
|
const {
|
||||||
snapshot,
|
snapshot,
|
||||||
revert,
|
revert,
|
||||||
|
@ -33,7 +34,7 @@ describe("Marketplace", function () {
|
||||||
const TestToken = await ethers.getContractFactory("TestToken")
|
const TestToken = await ethers.getContractFactory("TestToken")
|
||||||
token = await TestToken.deploy()
|
token = await TestToken.deploy()
|
||||||
for (account of [client, host1, host2, host3]) {
|
for (account of [client, host1, host2, host3]) {
|
||||||
await token.mint(account.address, 1000)
|
await token.mint(account.address, 1_000_000_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const Marketplace = await ethers.getContractFactory("Marketplace")
|
const Marketplace = await ethers.getContractFactory("Marketplace")
|
||||||
|
@ -69,7 +70,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, request.ask.reward)
|
await token.approve(marketplace.address, price(request))
|
||||||
await expect(marketplace.requestStorage(request))
|
await expect(marketplace.requestStorage(request))
|
||||||
.to.emit(marketplace, "StorageRequested")
|
.to.emit(marketplace, "StorageRequested")
|
||||||
.withArgs(requestId(request), askToArray(request.ask))
|
.withArgs(requestId(request), askToArray(request.ask))
|
||||||
|
@ -77,14 +78,14 @@ 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, invalid.ask.reward)
|
await token.approve(marketplace.address, price(invalid))
|
||||||
await expect(marketplace.requestStorage(invalid)).to.be.revertedWith(
|
await expect(marketplace.requestStorage(invalid)).to.be.revertedWith(
|
||||||
"Invalid client address"
|
"Invalid client address"
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("rejects request with insufficient payment", async function () {
|
it("rejects request with insufficient payment", async function () {
|
||||||
let insufficient = request.ask.reward - 1
|
let insufficient = price(request) - 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(
|
||||||
"ERC20: insufficient allowance"
|
"ERC20: insufficient allowance"
|
||||||
|
@ -92,7 +93,7 @@ describe("Marketplace", function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it("rejects resubmission of request", async function () {
|
it("rejects resubmission of request", async function () {
|
||||||
await token.approve(marketplace.address, request.ask.reward * 2)
|
await token.approve(marketplace.address, price(request) * 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(
|
||||||
"Request already exists"
|
"Request already exists"
|
||||||
|
@ -103,7 +104,7 @@ describe("Marketplace", function () {
|
||||||
describe("filling a slot", function () {
|
describe("filling a slot", function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
switchAccount(client)
|
switchAccount(client)
|
||||||
await token.approve(marketplace.address, request.ask.reward)
|
await token.approve(marketplace.address, price(request))
|
||||||
await marketplace.requestStorage(request)
|
await marketplace.requestStorage(request)
|
||||||
switchAccount(host)
|
switchAccount(host)
|
||||||
await token.approve(marketplace.address, collateral)
|
await token.approve(marketplace.address, collateral)
|
||||||
|
@ -160,7 +161,7 @@ describe("Marketplace", function () {
|
||||||
it("is rejected when request is expired", async function () {
|
it("is rejected when request is expired", async function () {
|
||||||
switchAccount(client)
|
switchAccount(client)
|
||||||
let expired = { ...request, expiry: now() - hours(1) }
|
let expired = { ...request, expiry: now() - hours(1) }
|
||||||
await token.approve(marketplace.address, request.ask.reward)
|
await token.approve(marketplace.address, price(request))
|
||||||
await marketplace.requestStorage(expired)
|
await marketplace.requestStorage(expired)
|
||||||
switchAccount(host)
|
switchAccount(host)
|
||||||
await expect(
|
await expect(
|
||||||
|
@ -179,7 +180,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, request.ask.reward)
|
await token.approve(marketplace.address, price(request))
|
||||||
await marketplace.requestStorage(request)
|
await marketplace.requestStorage(request)
|
||||||
switchAccount(host)
|
switchAccount(host)
|
||||||
await token.approve(marketplace.address, collateral)
|
await token.approve(marketplace.address, collateral)
|
||||||
|
@ -197,7 +198,7 @@ describe("Marketplace", function () {
|
||||||
const startBalance = await token.balanceOf(host.address)
|
const startBalance = await token.balanceOf(host.address)
|
||||||
await marketplace.payoutSlot(slot.request, slot.index)
|
await marketplace.payoutSlot(slot.request, slot.index)
|
||||||
const endBalance = await token.balanceOf(host.address)
|
const endBalance = await token.balanceOf(host.address)
|
||||||
expect(endBalance - startBalance).to.equal(request.ask.reward)
|
expect(endBalance - startBalance).to.equal(pricePerSlot(request))
|
||||||
})
|
})
|
||||||
|
|
||||||
it("is only allowed when the slot is filled", async function () {
|
it("is only allowed when the slot is filled", async function () {
|
||||||
|
@ -234,7 +235,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, request.ask.reward)
|
await token.approve(marketplace.address, price(request))
|
||||||
await marketplace.requestStorage(request)
|
await marketplace.requestStorage(request)
|
||||||
switchAccount(host)
|
switchAccount(host)
|
||||||
await token.approve(marketplace.address, collateral)
|
await token.approve(marketplace.address, collateral)
|
||||||
|
|
|
@ -6,6 +6,7 @@ const { exampleRequest } = require("./examples")
|
||||||
const { advanceTime, advanceTimeTo, currentTime } = require("./evm")
|
const { advanceTime, advanceTimeTo, currentTime } = require("./evm")
|
||||||
const { requestId, slotId } = require("./ids")
|
const { requestId, slotId } = require("./ids")
|
||||||
const { periodic } = require("./time")
|
const { periodic } = require("./time")
|
||||||
|
const { price } = require("./price")
|
||||||
|
|
||||||
describe("Storage", function () {
|
describe("Storage", function () {
|
||||||
const proof = hexlify(randomBytes(42))
|
const proof = hexlify(randomBytes(42))
|
||||||
|
@ -29,8 +30,8 @@ describe("Storage", function () {
|
||||||
token = await ethers.getContract("TestToken")
|
token = await ethers.getContract("TestToken")
|
||||||
storage = await ethers.getContract("Storage")
|
storage = await ethers.getContract("Storage")
|
||||||
|
|
||||||
await token.mint(client.address, 1000)
|
await token.mint(client.address, 1_000_000_000)
|
||||||
await token.mint(host.address, 1000)
|
await token.mint(host.address, 1_000_000_000)
|
||||||
|
|
||||||
collateralAmount = await storage.collateralAmount()
|
collateralAmount = await storage.collateralAmount()
|
||||||
slashMisses = await storage.slashMisses()
|
slashMisses = await storage.slashMisses()
|
||||||
|
@ -44,7 +45,7 @@ describe("Storage", function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
switchAccount(client)
|
switchAccount(client)
|
||||||
await token.approve(storage.address, request.ask.reward)
|
await token.approve(storage.address, price(request))
|
||||||
await storage.requestStorage(request)
|
await storage.requestStorage(request)
|
||||||
switchAccount(host)
|
switchAccount(host)
|
||||||
await token.approve(storage.address, collateralAmount)
|
await token.approve(storage.address, collateralAmount)
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
function price(request) {
|
||||||
|
return request.ask.slots * pricePerSlot(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pricePerSlot(request) {
|
||||||
|
return request.ask.duration * request.ask.reward
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { price, pricePerSlot }
|
Loading…
Reference in New Issue