2022-02-16 09:50:00 +00:00
|
|
|
const { ethers } = require("hardhat")
|
2022-06-13 08:40:18 +00:00
|
|
|
const { hexlify, randomBytes } = ethers.utils
|
2022-02-16 09:50:00 +00:00
|
|
|
const { expect } = require("chai")
|
2022-06-13 10:17:37 +00:00
|
|
|
const { exampleRequest } = require("./examples")
|
2022-02-16 13:38:19 +00:00
|
|
|
const { now, hours } = require("./time")
|
2022-07-19 09:33:54 +00:00
|
|
|
const { requestId, slotId, askToArray } = require("./ids")
|
2022-09-13 07:20:07 +00:00
|
|
|
const { waitUntilExpired, waitUntilAllSlotsFilled, RequestState } = require("./marketplace")
|
2022-07-20 09:07:20 +00:00
|
|
|
const { price, pricePerSlot } = require("./price")
|
2022-07-19 15:09:35 +00:00
|
|
|
const {
|
|
|
|
snapshot,
|
|
|
|
revert,
|
|
|
|
ensureMinimumBlockHeight,
|
|
|
|
advanceTimeTo,
|
2022-09-08 07:56:01 +00:00
|
|
|
currentTime,
|
2022-07-19 15:09:35 +00:00
|
|
|
} = require("./evm")
|
2022-02-16 09:50:00 +00:00
|
|
|
|
|
|
|
describe("Marketplace", function () {
|
2022-02-16 13:38:19 +00:00
|
|
|
const collateral = 100
|
2022-06-13 08:40:18 +00:00
|
|
|
const proofPeriod = 30 * 60
|
|
|
|
const proofTimeout = 5
|
|
|
|
const proofDowntime = 64
|
2022-07-19 15:09:35 +00:00
|
|
|
const proof = hexlify(randomBytes(42))
|
2022-02-16 09:50:00 +00:00
|
|
|
|
|
|
|
let marketplace
|
|
|
|
let token
|
2022-02-21 10:31:37 +00:00
|
|
|
let client, host, host1, host2, host3
|
2022-06-13 10:17:37 +00:00
|
|
|
let request
|
2022-07-19 15:09:35 +00:00
|
|
|
let slot
|
2022-02-16 09:50:00 +00:00
|
|
|
|
|
|
|
beforeEach(async function () {
|
2022-06-13 08:40:18 +00:00
|
|
|
await snapshot()
|
|
|
|
await ensureMinimumBlockHeight(256)
|
2022-02-21 10:31:37 +00:00
|
|
|
;[client, host1, host2, host3] = await ethers.getSigners()
|
|
|
|
host = host1
|
2022-02-17 10:00:18 +00:00
|
|
|
|
2022-02-16 09:50:00 +00:00
|
|
|
const TestToken = await ethers.getContractFactory("TestToken")
|
|
|
|
token = await TestToken.deploy()
|
2022-02-21 10:31:37 +00:00
|
|
|
for (account of [client, host1, host2, host3]) {
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.mint(account.address, 1_000_000_000)
|
2022-02-21 10:31:37 +00:00
|
|
|
}
|
2022-02-17 10:00:18 +00:00
|
|
|
|
2022-09-08 07:56:01 +00:00
|
|
|
const Marketplace = await ethers.getContractFactory("TestMarketplace")
|
2022-06-13 08:40:18 +00:00
|
|
|
marketplace = await Marketplace.deploy(
|
|
|
|
token.address,
|
|
|
|
collateral,
|
|
|
|
proofPeriod,
|
|
|
|
proofTimeout,
|
|
|
|
proofDowntime
|
|
|
|
)
|
2022-02-17 10:00:18 +00:00
|
|
|
|
|
|
|
request = exampleRequest()
|
|
|
|
request.client = client.address
|
2022-07-19 15:09:35 +00:00
|
|
|
|
|
|
|
slot = {
|
|
|
|
request: requestId(request),
|
2022-07-20 08:44:22 +00:00
|
|
|
index: request.ask.slots / 2,
|
2022-07-19 15:09:35 +00:00
|
|
|
}
|
2022-02-16 09:50:00 +00:00
|
|
|
})
|
|
|
|
|
2022-06-13 08:40:18 +00:00
|
|
|
afterEach(async function () {
|
|
|
|
await revert()
|
|
|
|
})
|
|
|
|
|
2022-02-17 10:00:18 +00:00
|
|
|
function switchAccount(account) {
|
|
|
|
token = token.connect(account)
|
|
|
|
marketplace = marketplace.connect(account)
|
|
|
|
}
|
|
|
|
|
2022-02-16 09:50:00 +00:00
|
|
|
describe("requesting storage", function () {
|
2022-02-17 10:00:18 +00:00
|
|
|
beforeEach(function () {
|
|
|
|
switchAccount(client)
|
|
|
|
})
|
|
|
|
|
2022-02-16 09:50:00 +00:00
|
|
|
it("emits event when storage is requested", async function () {
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(request))
|
2022-02-16 09:50:00 +00:00
|
|
|
await expect(marketplace.requestStorage(request))
|
|
|
|
.to.emit(marketplace, "StorageRequested")
|
2022-04-06 12:26:56 +00:00
|
|
|
.withArgs(requestId(request), askToArray(request.ask))
|
2022-02-16 09:50:00 +00:00
|
|
|
})
|
|
|
|
|
2022-02-17 10:00:18 +00:00
|
|
|
it("rejects request with invalid client address", async function () {
|
|
|
|
let invalid = { ...request, client: host.address }
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(invalid))
|
2022-02-17 10:00:18 +00:00
|
|
|
await expect(marketplace.requestStorage(invalid)).to.be.revertedWith(
|
|
|
|
"Invalid client address"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-02-16 09:50:00 +00:00
|
|
|
it("rejects request with insufficient payment", async function () {
|
2022-07-20 09:07:20 +00:00
|
|
|
let insufficient = price(request) - 1
|
2022-02-16 09:50:00 +00:00
|
|
|
await token.approve(marketplace.address, insufficient)
|
|
|
|
await expect(marketplace.requestStorage(request)).to.be.revertedWith(
|
2022-03-15 15:18:44 +00:00
|
|
|
"ERC20: insufficient allowance"
|
2022-02-16 09:50:00 +00:00
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("rejects resubmission of request", async function () {
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(request) * 2)
|
2022-02-16 09:50:00 +00:00
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
await expect(marketplace.requestStorage(request)).to.be.revertedWith(
|
|
|
|
"Request already exists"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
})
|
2022-02-16 13:38:19 +00:00
|
|
|
|
2022-09-21 09:29:40 +00:00
|
|
|
describe("freeing a slot", function () {
|
|
|
|
var id
|
|
|
|
beforeEach(async function () {
|
|
|
|
slot.index = 0
|
|
|
|
id = slotId(slot)
|
|
|
|
|
|
|
|
switchAccount(client)
|
|
|
|
await token.approve(marketplace.address, price(request))
|
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
|
|
|
|
// await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("fails to free slot when slot not filled", async function () {
|
|
|
|
slot.index = 5
|
|
|
|
let nonExistentId = slotId(slot)
|
|
|
|
await expect(marketplace.freeSlot(nonExistentId)).to.be.revertedWith(
|
|
|
|
"Slot empty"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("fails to free slot when not started", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
await expect(marketplace.freeSlot(id)).to.be.revertedWith("Invalid state")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("successfully frees slot", async function () {
|
2022-09-21 09:34:05 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-09-21 09:29:40 +00:00
|
|
|
await expect(marketplace.freeSlot(id)).not.to.be.reverted
|
|
|
|
})
|
|
|
|
|
|
|
|
it("emits event once slot is freed", async function () {
|
2022-09-21 09:34:05 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-09-21 09:29:40 +00:00
|
|
|
await expect(await marketplace.freeSlot(id))
|
|
|
|
.to.emit(marketplace, "SlotFreed")
|
|
|
|
.withArgs(slot.request, id)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("cannot get slot once freed", async function () {
|
2022-09-21 09:34:05 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-09-21 09:29:40 +00:00
|
|
|
await marketplace.freeSlot(id)
|
|
|
|
await expect(marketplace.slot(id)).to.be.revertedWith("Slot empty")
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-07-19 09:33:54 +00:00
|
|
|
describe("filling a slot", function () {
|
|
|
|
beforeEach(async function () {
|
|
|
|
switchAccount(client)
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(request))
|
2022-07-19 09:33:54 +00:00
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("emits event when slot is filled", async function () {
|
|
|
|
await expect(marketplace.fillSlot(slot.request, slot.index, proof))
|
|
|
|
.to.emit(marketplace, "SlotFilled")
|
|
|
|
.withArgs(slot.request, slot.index, slotId(slot))
|
|
|
|
})
|
|
|
|
|
|
|
|
it("locks collateral of host", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
await expect(marketplace.withdraw()).to.be.revertedWith("Account locked")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("starts requiring storage proofs", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
expect(await marketplace.proofEnd(slotId(slot))).to.be.gt(0)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("is rejected when proof is incorrect", async function () {
|
|
|
|
let invalid = hexlify([])
|
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(slot.request, slot.index, invalid)
|
|
|
|
).to.be.revertedWith("Invalid proof")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("is rejected when collateral is insufficient", async function () {
|
|
|
|
let insufficient = collateral - 1
|
|
|
|
await marketplace.withdraw()
|
|
|
|
await token.approve(marketplace.address, insufficient)
|
|
|
|
await marketplace.deposit(insufficient)
|
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
).to.be.revertedWith("Insufficient collateral")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("is rejected when slot already filled", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
).to.be.revertedWith("Slot already filled")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("is rejected when request is unknown", async function () {
|
|
|
|
let unknown = exampleRequest()
|
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(requestId(unknown), 0, proof)
|
|
|
|
).to.be.revertedWith("Unknown request")
|
|
|
|
})
|
|
|
|
|
2022-09-21 09:13:12 +00:00
|
|
|
it("is rejected when request is cancelled", async function () {
|
2022-07-19 09:33:54 +00:00
|
|
|
switchAccount(client)
|
|
|
|
let expired = { ...request, expiry: now() - hours(1) }
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(request))
|
2022-07-19 09:33:54 +00:00
|
|
|
await marketplace.requestStorage(expired)
|
|
|
|
switchAccount(host)
|
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(requestId(expired), slot.index, proof)
|
2022-09-21 09:13:12 +00:00
|
|
|
).to.be.revertedWith("Request not accepting proofs")
|
2022-07-19 09:33:54 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
it("is rejected when slot index not in range", async function () {
|
2022-07-20 08:44:22 +00:00
|
|
|
const invalid = request.ask.slots
|
2022-07-19 09:33:54 +00:00
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(slot.request, invalid, proof)
|
|
|
|
).to.be.revertedWith("Invalid slot")
|
|
|
|
})
|
2022-09-07 05:25:01 +00:00
|
|
|
|
|
|
|
it("fails when all slots are already filled", async function () {
|
|
|
|
const lastSlot = request.ask.slots - 1
|
|
|
|
for (let i = 0; i <= lastSlot; i++) {
|
|
|
|
await marketplace.fillSlot(slot.request, i, proof)
|
|
|
|
}
|
|
|
|
await expect(
|
|
|
|
marketplace.fillSlot(slot.request, lastSlot, proof)
|
2022-09-21 09:13:12 +00:00
|
|
|
).to.be.revertedWith("Slot already filled")
|
2022-09-07 05:25:01 +00:00
|
|
|
})
|
2022-07-19 09:33:54 +00:00
|
|
|
})
|
|
|
|
|
2022-09-13 07:32:02 +00:00
|
|
|
describe("freeing a slot", function () {
|
|
|
|
var id
|
|
|
|
beforeEach(async function () {
|
|
|
|
slot.index = 0
|
|
|
|
id = slotId(slot)
|
|
|
|
|
|
|
|
switchAccount(client)
|
|
|
|
await token.approve(marketplace.address, price(request))
|
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("fails to free slot when slot not filled", async function () {
|
|
|
|
slot.index = 5
|
|
|
|
let nonExistentId = slotId(slot)
|
|
|
|
await expect(marketplace.freeSlot(nonExistentId)).to.be.revertedWith(
|
|
|
|
"Slot empty"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("successfully frees slot", async function () {
|
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
|
|
|
await expect(marketplace.freeSlot(id)).not.to.be.reverted
|
|
|
|
})
|
|
|
|
|
|
|
|
it("emits event once slot is freed", async function () {
|
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
|
|
|
await expect(await marketplace.freeSlot(id))
|
|
|
|
.to.emit(marketplace, "SlotFreed")
|
|
|
|
.withArgs(slot.request, id)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("cannot get slot once freed", async function () {
|
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
|
|
|
await marketplace.freeSlot(id)
|
|
|
|
await expect(marketplace.slot(id)).to.be.revertedWith("Slot empty")
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-07-19 15:09:35 +00:00
|
|
|
describe("paying out a slot", function () {
|
|
|
|
beforeEach(async function () {
|
|
|
|
switchAccount(client)
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(request))
|
2022-07-19 15:09:35 +00:00
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
})
|
|
|
|
|
|
|
|
async function waitUntilEnd() {
|
|
|
|
const end = (await marketplace.proofEnd(slotId(slot))).toNumber()
|
|
|
|
await advanceTimeTo(end)
|
|
|
|
}
|
|
|
|
|
|
|
|
it("pays the host", async function () {
|
2022-09-21 09:38:42 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-07-19 15:09:35 +00:00
|
|
|
await waitUntilEnd()
|
|
|
|
const startBalance = await token.balanceOf(host.address)
|
|
|
|
await marketplace.payoutSlot(slot.request, slot.index)
|
|
|
|
const endBalance = await token.balanceOf(host.address)
|
2022-07-20 09:07:20 +00:00
|
|
|
expect(endBalance - startBalance).to.equal(pricePerSlot(request))
|
2022-07-19 15:09:35 +00:00
|
|
|
})
|
|
|
|
|
2022-09-21 09:38:42 +00:00
|
|
|
it("is only allowed when the contract is finished", async function () {
|
2022-07-19 15:09:35 +00:00
|
|
|
await expect(
|
|
|
|
marketplace.payoutSlot(slot.request, slot.index)
|
2022-09-21 09:38:42 +00:00
|
|
|
).to.be.revertedWith("Contract not ended")
|
2022-07-19 15:09:35 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
it("is only allowed when the contract has ended", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
await expect(
|
|
|
|
marketplace.payoutSlot(slot.request, slot.index)
|
|
|
|
).to.be.revertedWith("Contract not ended")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("can only be done once", async function () {
|
2022-09-21 09:38:42 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-07-19 15:09:35 +00:00
|
|
|
await waitUntilEnd()
|
|
|
|
await marketplace.payoutSlot(slot.request, slot.index)
|
|
|
|
await expect(
|
|
|
|
marketplace.payoutSlot(slot.request, slot.index)
|
|
|
|
).to.be.revertedWith("Already paid")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("cannot be filled again", async function () {
|
2022-09-21 09:38:42 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-07-19 15:09:35 +00:00
|
|
|
await waitUntilEnd()
|
|
|
|
await marketplace.payoutSlot(slot.request, slot.index)
|
|
|
|
await expect(marketplace.fillSlot(slot.request, slot.index, proof)).to.be
|
|
|
|
.reverted
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-07-20 08:29:24 +00:00
|
|
|
describe("fulfilling a request", function () {
|
|
|
|
beforeEach(async function () {
|
|
|
|
switchAccount(client)
|
2022-07-20 09:07:20 +00:00
|
|
|
await token.approve(marketplace.address, price(request))
|
2022-07-20 08:29:24 +00:00
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("emits event when all slots are filled", async function () {
|
2022-07-20 08:44:22 +00:00
|
|
|
const lastSlot = request.ask.slots - 1
|
2022-07-20 08:29:24 +00:00
|
|
|
for (let i = 0; i < lastSlot; i++) {
|
|
|
|
await marketplace.fillSlot(slot.request, i, proof)
|
|
|
|
}
|
|
|
|
await expect(marketplace.fillSlot(slot.request, lastSlot, proof))
|
|
|
|
.to.emit(marketplace, "RequestFulfilled")
|
|
|
|
.withArgs(requestId(request))
|
|
|
|
})
|
2022-08-03 09:54:29 +00:00
|
|
|
it("sets state when all slots are filled", async function () {
|
|
|
|
const lastSlot = request.ask.slots - 1
|
|
|
|
for (let i = 0; i <= lastSlot; i++) {
|
|
|
|
await marketplace.fillSlot(slot.request, i, proof)
|
|
|
|
}
|
2022-09-07 05:25:01 +00:00
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.Started
|
|
|
|
)
|
2022-08-04 02:14:36 +00:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
describe("withdrawing funds", function () {
|
|
|
|
beforeEach(async function () {
|
|
|
|
switchAccount(client)
|
|
|
|
await token.approve(marketplace.address, price(request))
|
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("rejects withdraw when request not yet timed out", async function () {
|
|
|
|
switchAccount(client)
|
|
|
|
await expect(marketplace.withdrawFunds(slot.request)).to.be.revertedWith(
|
|
|
|
"Request not yet timed out"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("rejects withdraw when wrong account used", async function () {
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
await expect(marketplace.withdrawFunds(slot.request)).to.be.revertedWith(
|
|
|
|
"Invalid client address"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("rejects withdraw when in wrong state", async function () {
|
|
|
|
// fill all slots, should change state to RequestState.Started
|
|
|
|
const lastSlot = request.ask.slots - 1
|
|
|
|
for (let i = 0; i <= lastSlot; i++) {
|
|
|
|
await marketplace.fillSlot(slot.request, i, proof)
|
|
|
|
}
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
switchAccount(client)
|
|
|
|
await expect(marketplace.withdrawFunds(slot.request)).to.be.revertedWith(
|
|
|
|
"Invalid state"
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("emits event once request is cancelled", async function () {
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
switchAccount(client)
|
|
|
|
await expect(marketplace.withdrawFunds(slot.request))
|
|
|
|
.to.emit(marketplace, "RequestCancelled")
|
|
|
|
.withArgs(requestId(request))
|
|
|
|
})
|
|
|
|
|
|
|
|
it("withdraws to the client", async function () {
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
switchAccount(client)
|
|
|
|
const startBalance = await token.balanceOf(client.address)
|
|
|
|
await marketplace.withdrawFunds(slot.request)
|
|
|
|
const endBalance = await token.balanceOf(client.address)
|
|
|
|
expect(endBalance - startBalance).to.equal(price(request))
|
|
|
|
})
|
2022-07-20 08:29:24 +00:00
|
|
|
})
|
2022-08-12 01:40:04 +00:00
|
|
|
|
|
|
|
describe("contract state", function () {
|
|
|
|
beforeEach(async function () {
|
|
|
|
switchAccount(client)
|
|
|
|
await token.approve(marketplace.address, price(request))
|
|
|
|
await marketplace.requestStorage(request)
|
|
|
|
switchAccount(host)
|
|
|
|
await token.approve(marketplace.address, collateral)
|
|
|
|
await marketplace.deposit(collateral)
|
|
|
|
})
|
|
|
|
|
2022-09-08 07:56:01 +00:00
|
|
|
it("changes state to Cancelled when client withdraws funds", async function () {
|
2022-08-12 01:40:04 +00:00
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.New
|
|
|
|
)
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
switchAccount(client)
|
|
|
|
await marketplace.withdrawFunds(slot.request)
|
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.Cancelled
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-09-08 07:56:01 +00:00
|
|
|
it("changes state to Started once all slots are filled", async function () {
|
2022-08-12 01:40:04 +00:00
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.New
|
|
|
|
)
|
2022-09-13 07:20:07 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
2022-08-12 01:40:04 +00:00
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.Started
|
|
|
|
)
|
|
|
|
})
|
2022-09-08 07:56:01 +00:00
|
|
|
|
2022-09-21 09:34:05 +00:00
|
|
|
// fill all slots, should change state to RequestState.Started
|
2022-09-13 07:20:07 +00:00
|
|
|
await waitUntilAllSlotsFilled(
|
|
|
|
marketplace,
|
|
|
|
request.ask.slots,
|
|
|
|
slot.request,
|
|
|
|
proof
|
|
|
|
)
|
|
|
|
for (let i = 0; i <= request.ask.maxSlotLoss; i++) {
|
|
|
|
slot.index = i
|
|
|
|
let id = slotId(slot)
|
|
|
|
await marketplace.freeSlot(id)
|
|
|
|
}
|
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.Failed
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-09-21 09:13:12 +00:00
|
|
|
it("does not change state to Failed if too many slots freed but contract not started", async function () {
|
|
|
|
for (let i = 0; i <= request.ask.maxSlotLoss; i++) {
|
|
|
|
await marketplace.fillSlot(slot.request, i, proof)
|
|
|
|
}
|
|
|
|
for (let i = 0; i <= request.ask.maxSlotLoss; i++) {
|
|
|
|
slot.index = i
|
|
|
|
let id = slotId(slot)
|
|
|
|
await marketplace.freeSlot(id)
|
|
|
|
}
|
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.New
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
2022-09-08 07:56:01 +00:00
|
|
|
it("changes state to Cancelled once request is cancelled", async function () {
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
await expect(await marketplace.state(slot.request)).to.equal(
|
|
|
|
RequestState.Cancelled
|
|
|
|
)
|
|
|
|
})
|
|
|
|
|
|
|
|
it("changes isCancelled to true once request is cancelled", async function () {
|
|
|
|
await expect(await marketplace.isCancelled(slot.request)).to.be.false
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
await expect(await marketplace.isCancelled(slot.request)).to.be.true
|
|
|
|
})
|
|
|
|
|
|
|
|
it("rejects isSlotCancelled when slot is empty", async function () {
|
|
|
|
await expect(
|
|
|
|
marketplace.isSlotCancelled(slotId(slot))
|
|
|
|
).to.be.revertedWith("Slot empty")
|
|
|
|
})
|
|
|
|
|
|
|
|
it("changes isSlotCancelled to true once request is cancelled", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
await expect(await marketplace.isSlotCancelled(slotId(slot))).to.be.false
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
await expect(await marketplace.isSlotCancelled(slotId(slot))).to.be.true
|
|
|
|
})
|
|
|
|
|
|
|
|
it("changes proofEnd to the past when request is cancelled", async function () {
|
|
|
|
await marketplace.fillSlot(slot.request, slot.index, proof)
|
|
|
|
await expect(await marketplace.proofEnd(slotId(slot))).to.be.gt(
|
|
|
|
await currentTime()
|
|
|
|
)
|
|
|
|
await waitUntilExpired(request.expiry)
|
|
|
|
await expect(await marketplace.proofEnd(slotId(slot))).to.be.lt(
|
|
|
|
await currentTime()
|
|
|
|
)
|
|
|
|
})
|
2022-08-12 01:40:04 +00:00
|
|
|
})
|
2022-02-16 09:50:00 +00:00
|
|
|
})
|